/*
 * ***********************************************************************
 *
 *  ADOBE CONFIDENTIAL
 *  ___________________
 *
 *  Copyright 2013 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 *  NOTICE:  All information contained herein is, and remains
 *  the property of Adobe Systems Incorporated and its suppliers,
 *  if any.  The intellectual and technical concepts contained
 *  herein are proprietary to Adobe Systems Incorporated and its
 *  suppliers and are protected by trade secret or copyright law.
 *  Dissemination of this information or reproduction of this material
 *  is strictly forbidden unless prior written permission is obtained
 *  from Adobe Systems Incorporated.
 *
 * ***********************************************************************
 */

package com.adobe.primetime.reference.ui.settings.test;

import android.annotation.TargetApi;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Build;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import com.adobe.primetime.reference.PrimetimeReference;
import com.adobe.primetime.reference.manager.AdsManager;
import com.adobe.primetime.reference.manager.CCManager;
import com.adobe.primetime.reference.manager.DrmManager;
import com.adobe.primetime.reference.manager.PlaybackManager;
import com.adobe.primetime.reference.manager.QosManager;
import com.adobe.primetime.reference.manager.VAManager;
import com.adobe.primetime.reference.ui.settings.SettingsActivity;
import com.adobe.primetime.reference.ui.settings.SettingsActivity.PrefsFragment;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

// identify how to simulate a click on the preferenceFragment that has been loaded
// so that listener code coverage can be tested.
// create tests for api < 11
//
// "What is the expected externally visible outcome of this implementation?"

/*
 * Currently this only tests api_version > 11
 */
public class SettingsActivityTest extends
		ActivityInstrumentationTestCase2<SettingsActivity> {
	private SettingsActivity activity;
	private Map<String, ?> spEntrySet;

	public SettingsActivityTest() {
		super(SettingsActivity.class);
	}

	/*
	 * This is the setup for the settings activity. it will remove all saved
	 * preferences and test the defaults. (non-Javadoc)
	 * 
	 * @see android.test.ActivityInstrumentationTestCase2#setUp()
	 */
	@Override
	protected void setUp() throws Exception {
		super.setUp();

		Intent intent = new Intent(getInstrumentation().getTargetContext(),
				SettingsActivity.class);
		setActivityInitialTouchMode(true);
		setActivityIntent(intent);

		// resets default preferences
		this.getInstrumentation().getTargetContext();
		Context context = this.getInstrumentation().getTargetContext()
				.getApplicationContext();
		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(context);
		// backup clients preferences (they are restored on tearDown())
		spEntrySet = prefs.getAll();

		Editor editor = prefs.edit();
		editor.clear();
		editor.commit();

		activity = this.getActivity();
	}

	@Override
	protected void tearDown() throws Exception {
		// restore the savedpreferences
		Context context = this.getInstrumentation().getTargetContext()
				.getApplicationContext();
		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(context);
		SharedPreferences.Editor ed = prefs.edit();
		ed.clear();
		for (Entry<String, ?> entry : spEntrySet.entrySet()) {
			Object v = entry.getValue();
			String key = entry.getKey();
			Log.d("x", key + " " + v.toString());

			if (v instanceof Boolean)
				ed.putBoolean(key, ((Boolean) v).booleanValue());
			else if (v instanceof Float)
				ed.putFloat(key, ((Float) v).floatValue());
			else if (v instanceof Integer)
				ed.putInt(key, ((Integer) v).intValue());
			else if (v instanceof Long)
				ed.putLong(key, ((Long) v).longValue());
			else if (v instanceof String)
				ed.putString(key, ((String) v));
		}
		ed.commit(); // save it.

		super.tearDown();
	}

	/**
	 * verify default settings
	 * 
	 * @throws Exception
	 */
	public void testDefaultSettings() throws Exception {
		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
			return;
		}
		final String listPreferenceKey = "preference_cc_style";

		/**
		 * the following will load the fragment "preference_cc_style" and
		 * display the fragment in 2 panes (header & fragment) on larger
		 * displays. see R.xml.preference_headers for details
		 */
		activity.runOnUiThread(new Runnable() {
			public void run() {
				Bundle b = new Bundle();
				b.putString("pref-resource", listPreferenceKey);
				// switchToHeader only works in 2 pane mode.
				// single pane? should use startWithFragment() i think
				activity.switchToHeader(
						"com.adobe.primetime.reference.ui.settings.SettingsActivity$PrefsFragment",
						b);
			}
		});
		// wait for ui thread to finish instantiating fragment after switch
		getInstrumentation().waitForIdleSync();

		// in api > 11, the preference manager handles the storing and
		// modification
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(activity.getApplicationContext());

		Map<String, Object> defaultPreferences = getDefaultPreferences();
		Map<String, ?> storedPreferences = sp.getAll();
		for (Map.Entry<String, ?> entry : storedPreferences.entrySet()) {
			assertEquals(entry.getKey(), entry.getValue(),
					defaultPreferences.get(entry.getKey()));
			defaultPreferences.remove(entry.getKey());
		}
	}

	/**
	 * displays the fragment content on screen.
	 * 
	 * @param fragment
	 *            The fragment that gets loaded.
	 * @param fragmentName
	 * @return
	 */
	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	private Fragment startFragment(Fragment fragment, String fragmentName) {
		android.app.FragmentTransaction transaction = activity
				.getFragmentManager().beginTransaction();
		transaction.add(android.R.id.content, fragment, fragmentName);
		// transaction.commit();
		transaction.commitAllowingStateLoss();
		getInstrumentation().waitForIdleSync();
		Fragment frag = activity.getFragmentManager().findFragmentByTag(
				fragmentName);
		return frag;
	}

	/**
	 * This allows an individual fragment to be created and displayed This can
	 * be used as a model for testing other PreferenceFragments
	 */
	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public void testCCStyleFontValue() {
		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
			return;
		}

		Log.d("testCCStyleFontValue------->>", "starting");
		String fragmentName = "preference_cc_style";
		PrefsFragment fragment = new PrefsFragment() {
			// Override methods and add assertions here.
		};
		Bundle ccBundle = new Bundle();
		ccBundle.putString("pref-resource", fragmentName);
		fragment.setArguments(ccBundle);

		Fragment frag = startFragment(fragment, fragmentName);
		Log.d("fragment loaded-------->>", frag.getTag());

		for (String preferenceKey : getCCPreferenceList()) {
			PreferenceFragment pf = (PreferenceFragment) frag;
			Preference p = pf.findPreference(preferenceKey);
			ListPreference lp = (ListPreference) p;

			Map<String, Object> defaults = getDefaultPreferences();
			assertEquals(lp.getValue(), defaults.get(preferenceKey));

			// add each of the entries to a list, and compare values
			String[] list = null;
			if (p.getKey().equals("settings_cc_style_font")) {
				list = getCCStyleFontOptions();
			} else if (p.getKey().equals("settings_cc_style_font_color")
					|| p.getKey().equals("settings_cc_style_bg_color")
					|| p.getKey().equals("settings_cc_style_edge_color")) {
				list = getCCColorOptions();
			} else if (p.getKey().equals("settings_cc_style_bg_opacity")
					|| p.getKey().equals("settings_cc_style_font_opacity")) {
				list = getCCOpacityValues();
			} else if (p.getKey().equals("settings_cc_style_size")) {
				list = getCCSizeOptions();
			} else if (p.getKey().equals("settings_cc_style_font_edge")) {
				list = getCCFontEdgeOptions();
			}

			int i = 0;
			for (CharSequence x : lp.getEntryValues()) {
				assertEquals(list[i], x.toString());
				i++;
			}
			assertEquals(list.length, i);
		}
	}

	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	// getTag
	public void testCCStyleFontEntries() {
		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
			return;
		}

		String fragmentName = "preference_cc_style";
		PrefsFragment fragment = new PrefsFragment() {
			// Override methods and add assertions here.
		};
		Bundle ccBundle = new Bundle();
		ccBundle.putString("pref-resource", fragmentName);
		fragment.setArguments(ccBundle);

		Fragment frag = startFragment(fragment, fragmentName);
		Log.d("fragment loaded-------->>", frag.getTag());

		for (String preferenceKey : getCCPreferenceList()) {
			PreferenceFragment pf = (PreferenceFragment) frag;
			Preference p = pf.findPreference(preferenceKey);
			ListPreference lp = (ListPreference) p;

			// add each of the entries to a list, and compare
			String[] list = null;
			if (p.getKey().equals("settings_cc_style_font")) {
				list = getCCStyleFontOptions();
			} else if (p.getKey().equals("settings_cc_style_font_color")
					|| p.getKey().equals("settings_cc_style_bg_color")
					|| p.getKey().equals("settings_cc_style_edge_color")) {
				list = getCCColorOptions();
			} else if (p.getKey().equals("settings_cc_style_bg_opacity")
					|| p.getKey().equals("settings_cc_style_font_opacity")) {
				list = getCCOpacityOptions();
			} else if (p.getKey().equals("settings_cc_style_size")) {
				list = getCCSizeOptions();
			} else if (p.getKey().equals("settings_cc_style_font_edge")) {
				list = getCCFontEdgeOptions();
			}

			int i = 0;
			for (CharSequence x : lp.getEntries()) {
				// Log.d("entry:", x.toString() + "   vs "+ list[i]);
				assertEquals(list[i], x.toString());
				i++;
			}
			assertEquals(list.length, i);
		}
	}

	/*
	 * preferences found in the fragment which is defined in the resource:
	 * xml/preference_cc_style.xml
	 */
	public static String[] getCCPreferenceList() {
		return new String[] { "settings_cc_style_font",
				"settings_cc_style_font_color", "settings_cc_style_bg_color",
				"settings_cc_style_bg_opacity",
				"settings_cc_style_font_opacity", "settings_cc_style_size",
				"settings_cc_style_font_edge", "settings_cc_style_edge_color" };
	}

	/*
	 * returns the set of default preferences
	 */
	public static Map<String, Object> getDefaultPreferences() {
		Map<String, Object> defaultSettings = new HashMap<String, Object>();

		defaultSettings.put(PrimetimeReference.SETTINGS_CONTROLBAR_AUTOHIDE,
				PrimetimeReference.DEFAULT_AUTOHIDE_CONTROL_BAR);
		defaultSettings.put(QosManager.SETTINGS_QOS_VISIBILITY,
				QosManager.DEFAULT_QOS_VISIBILITY);
		defaultSettings.put(PrimetimeReference.SETTINGS_RETURN_HOME_ON_PLAY_COMPLETE,
				PrimetimeReference.DEFAULT_RETURN_HOME_ON_PLAY_COMPLETE);
		defaultSettings.put(PlaybackManager.SETTINGS_FORCE_OMXAL,
				PlaybackManager.DEFAULT_FORCE_OMXAL);		
		defaultSettings.put(PrimetimeReference.SETTINGS_LOG_MAX_ENTRY_COUNT_KEY, "1000");
		defaultSettings.put(DrmManager.SETTINGS_DRM_PRE_CACHE,
				DrmManager.DEFAULT_DRM_PRECACHE);
		defaultSettings.put(PrimetimeReference.SETTINGS_CONTENT_URL_KEY,
				"http://d398890tia84ty.cloudfront.net/reference/ref_player_sample_v2.json");
		defaultSettings.put(PrimetimeReference.SETTINGS_REMOTE_LOGGING_ACTIVE,
				PrimetimeReference.DEFAULT_REMOTE_LOGGING_ACTIVE);
		defaultSettings.put(PrimetimeReference.SETTINGS_TOAST_WARNINGS,
				PrimetimeReference.DEFAULT_TOAST_WARNINGS);

		// CC default settings
		defaultSettings.put(CCManager.SETTINGS_CC_STYLE_FONT, "DEFAULT");
		defaultSettings.put(CCManager.SETTINGS_CC_STYLE_FONT_COLOR, "DEFAULT");
		defaultSettings.put(CCManager.SETTINGS_CC_STYLE_FONT_EDGE, "DEFAULT");
		defaultSettings.put(CCManager.SETTINGS_CC_STYLE_FONT_OPACITY, "-1");
		defaultSettings.put(CCManager.SETTINGS_CC_STYLE_BACKGROUND_OPACITY,
				"-1");
		defaultSettings.put(CCManager.SETTINGS_CC_STYLE_BACKGROUND_COLOR,
				"DEFAULT");
		defaultSettings.put(CCManager.SETTINGS_CC_STYLE_EDGE_COLOR, "DEFAULT");
		defaultSettings.put(CCManager.SETTINGS_CC_STYLE_SIZE, "DEFAULT");

		// ABR default settings
		defaultSettings.put(PlaybackManager.SETTINGS_ABR_POLICY, "DEFAULT");
		defaultSettings
				.put(PlaybackManager.SETTINGS_ABR_MAX_BITRATE, "DEFAULT");
		defaultSettings
				.put(PlaybackManager.SETTINGS_ABR_MIN_BITRATE, "DEFAULT");
		defaultSettings.put(PlaybackManager.SETTINGS_ABR_INITIAL_BITRATE, "DEFAULT");
		defaultSettings.put(PlaybackManager.SETTINGS_ABR_CTRL_ENABLED, "DEFAULT");

        // VA default settings
        defaultSettings.put(VAManager.SETTINGS_VA_JOB_ID, VAManager.DEFAULT_VA_JOB_ID);
        defaultSettings.put(VAManager.SETTINGS_VA_PUBLISHER, VAManager.DEFAULT_VA_PUBLISHER);
        defaultSettings.put(VAManager.SETTINGS_VA_CHANNEL, VAManager.DEFAULT_VA_CHANNEL);
        defaultSettings.put(VAManager.SETTINGS_VA_TRACKING_SERVER, VAManager.DEFAULT_VA_TRACKING_SERVER);
        defaultSettings.put(VAManager.SETTINGS_VA_DEBUG_LOGGING_ENABLED, VAManager.DEFAULT_VA_DEBUG_LOGGING);
        defaultSettings.put(VAManager.SETTINGS_VA_QUITE_MODE, VAManager.DEFAULT_VA_QUITE_MODE);
        defaultSettings.put(VAManager.SETTINGS_VA_ENABLED, VAManager.DEFAULT_VA_ENABLED);

        // AD default settings
        defaultSettings.put(AdsManager.SETTINGS_CLICKABLE_ADS, AdsManager.DEFAULT_CLICKABLE_ADS);
		defaultSettings.put(AdsManager.SETTINGS_ADVERTISING_SIGNALING_MODE, "default");
        defaultSettings.put(AdsManager.SETTINGS_CUSTOM_AD_CLIENT_FACTORY, AdsManager.DEFAULT_CUSTOM_AD_CLIENT_FACTORY);
        defaultSettings.put(AdsManager.SETTINGS_ADVERTISING_WORKFLOW_ENABLED, AdsManager.DEFAULT_ADVERTISING_WORKFLOW_ENABLED);

		return defaultSettings;
	}

	public static String[] getCCStyleFontOptions() {
		return new String[] { "DEFAULT",
				"MONOSPACED_WITH_SERIFS",
				"PROPORTIONAL_WITH_SERIFS",
				"MONOSPACED_WITHOUT_SERIFS", // <---- perhaps this should be
												// MONOSPACED_WITHOUT_SERIFS?
				"PROPORTIONAL_WITHOUT_SERIFS", "CASUAL", "CURSIVE",
				"SMALL_CAPITALS" };
	}

	public static String[] getCCColorOptions() {
		return new String[] { "DEFAULT", "BLACK", "GRAY", "WHITE",
				"BRIGHT_WHITE", "DARK_RED", "RED", "BRIGHT_RED", "DARK_GREEN",
				"GREEN", "BRIGHT_GREEN", "DARK_BLUE", "BLUE", "BRIGHT_BLUE",
				"DARK_YELLOW", "YELLOW", "BRIGHT_YELLOW", "DARK_MAGENTA",
				"MAGENTA", "BRIGHT_MAGENTA", "DARK_CYAN", "CYAN", "BRIGHT_CYAN" };
	}

	public static String[] getCCOpacityOptions() {
		return new String[] { "DEFAULT", "0", "10", "20", "30", "40", "50",
				"60", "70", "80", "90", "100" };
	}

	public static String[] getCCOpacityValues() {
		return new String[] { "-1", "0", "10", "20", "30", "40", "50", "60",
				"70", "80", "90", "100" };
	}

	public static String[] getCCSizeOptions() {
		return new String[] { "DEFAULT", "SMALL", "MEDIUM", "LARGE" };
	}

	public static String[] getCCFontEdgeOptions() {
		return new String[] { "DEFAULT", "NONE", "RAISED", "DEPRESSED",
				"UNIFORM", "DROP_SHADOW_LEFT", "DROP_SHADOW_RIGHT" };
	}

}
