package org.mote.wiimote.whiteboard.preferences;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
import org.mote.wiimote.whiteboard.gui.PreferencesWindow;
import org.mote.wiimote.whiteboard.mouse.DefaultControlStrategy;
import org.mote.wiimote.whiteboard.mouse.rightclick.DefaultRightClick;
import org.mote.wiimote.whiteboard.mouse.rightclick.DragRightClick;
import org.mote.wiimote.whiteboard.mouse.rightclick.RightClickStrategy;
import org.mote.wiimote.whiteboard.mouse.smoothing.AdaptiveExponentialSmoothing;
import org.mote.wiimote.whiteboard.mouse.smoothing.MouseSmoothingStrategy;
import org.mote.wiimote.whiteboard.mouse.smoothing.NoSmoothing;
import org.mote.wiimote.whiteboard.mouse.smoothing.SimpleMovingAverage;
import org.mote.wiimote.whiteboard.util.Util;

import wiiremotej.IRSensitivitySettings;

public class WWPreferences {
	
	public static class LocaleWrapper {
		private final Locale locale;
		private final String name;
		public LocaleWrapper(Locale locale, String name) {
			this.locale = locale;
			this.name = name;
		}

		public String getLocaleString() {
			return locale != null ? locale.toString() : "";
		}
		@Override
		public String toString() {
			return name != null ? name : Util.getResourceMap(PreferencesWindow.class).getString("default");
		}
	}
	
	public static final LocaleWrapper[] LANGUAGES = {
		new LocaleWrapper(null, null),
		new LocaleWrapper(Locale.GERMAN, "Deutsch"),
		new LocaleWrapper(new Locale("et"), "Eesti"),
		new LocaleWrapper(Locale.ENGLISH, "English"),
		new LocaleWrapper(new Locale("es"), "Espa\u00f1ol"),
		new LocaleWrapper(Locale.FRENCH, "Fran\u00e7ais"),
		new LocaleWrapper(new Locale("in"), "Bahasa Indonesia"),
		new LocaleWrapper(Locale.ITALIAN, "Italiano"),
		new LocaleWrapper(new Locale("pl"), "Polski"),
		new LocaleWrapper(new Locale("pt"), "Portugu\u00eas"),
		new LocaleWrapper(new Locale("ru"), "\u0420\u0443\u0441\u0441\u043a\u0438\u0439"),
		new LocaleWrapper(new Locale("sl"), "Sloven\u0161\u010dina")
	};
	
	public static final int WIIMOTES;// = 2;	
	public static final int PIXEL_MOVE_TOLERANCE;
	public static final int SHORT_DELAY;
	public static final int MOUSE_PRESS_DELAY;
	public static final boolean MOUSE_CONTROL_AFTER_CALIBRATION;
	
	private static final byte[] MAX_SENSITIVITY_BLOCK1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x90, 0x00, 0x41 };
	private static final byte[] MAX_SENSITIVITY_BLOCK2 = new byte[] { 0x40, 0x00 };
	public static final IRSensitivitySettings SENSITIVITY_SETTINGS;
	
	public static final RightClickStrategy RIGHT_CLICK_STRATEGY;
	public static final List<String> WIIMOTE_BT_ADDRESSES;
	
	static {		

		int tolerance = -1;
		try {
			tolerance = Integer.parseInt(System.getProperty("org.mote.wiimote.whiteboard.pixelMoveTolerance"));
		} catch (Exception e) {}
		PIXEL_MOVE_TOLERANCE = tolerance < 0 ? 10 : tolerance;

		int delay = -1;
		try {
			delay = Integer.parseInt(System.getProperty("org.mote.wiimote.whiteboard.shortDelay"));
		} catch (Exception e) {}
		SHORT_DELAY = delay < 0 ? 200 : delay;

		int mouseDelay = -1;
		try {
			mouseDelay = Integer.parseInt(System.getProperty("org.mote.wiimote.whiteboard.mousePressDelay"));
		} catch (Exception e) {}
		MOUSE_PRESS_DELAY = mouseDelay < 0 ? 0 : mouseDelay;
		
		IRSensitivitySettings sensitivity = new IRSensitivitySettings(MAX_SENSITIVITY_BLOCK1, MAX_SENSITIVITY_BLOCK2);
		try {
			String str = System.getProperty("org.mote.wiimote.whiteboard.sensitivity");
			if (str != null) {
				if (str.equals("wii1"))
					sensitivity = IRSensitivitySettings.WII_LEVEL_1;
				else if (str.equals("wii2"))
					sensitivity = IRSensitivitySettings.WII_LEVEL_2;
				else if (str.equals("wii3"))
					sensitivity = IRSensitivitySettings.WII_LEVEL_3;
				else if (str.equals("wii4"))
					sensitivity = IRSensitivitySettings.WII_LEVEL_4;
				else if (str.equals("wii5"))
					sensitivity = IRSensitivitySettings.WII_LEVEL_5;
			}
		} catch (Exception e) {}
		SENSITIVITY_SETTINGS = sensitivity;
		
		int wiimotes = 0;
		try {
			wiimotes = Integer.parseInt(System.getProperty("org.mote.wiimote.whiteboard.wiimotes"));
		} catch (Exception e) {}
		WIIMOTES = wiimotes == 1 || wiimotes == 2 ? wiimotes : 2;
		
		List<String> addresses = Collections.emptyList();
		try {
			String str = System.getProperty("org.mote.wiimote.whiteboard.wiimoteAddresses");
			if (str != null) {
				addresses = Collections.unmodifiableList(Arrays.asList(str.toUpperCase().split(":")));
			}
		} catch (Exception e) {}
		WIIMOTE_BT_ADDRESSES = addresses;
		
		RightClickStrategy rcs = new DefaultRightClick();
		try {
			String str = System.getProperty("org.mote.wiimote.whiteboard.rightClick");
			if (str != null && str.equals("drag")) {
				rcs = new DragRightClick();
			}
		} catch (Exception e) {}
		RIGHT_CLICK_STRATEGY = rcs;
		
		boolean mc = true;
		try {
			String str = System.getProperty("org.mote.wiimote.whiteboard.mouseControlAfterCalibration");
			mc = !(str != null && str.equals("false"));
		} catch (Exception e) {}
		MOUSE_CONTROL_AFTER_CALIBRATION = mc;
		
	}
	
	private static final String RIGHT_CLICK_DELAY = "rightClickDelay";
	private static final String RIGHT_CLICK = "rightClick";
	private static final String LEFT_CLICK = "leftClick";
	private static final String LOW_BATTERY_WARNING = "lowBatteryWarning";
	private static final String CHECK_FOR_UPDATES = "checkForUpdates";
	private static final String MOUSE_SMOOTHING = "mouseSmoothing";
	private static final String TUIO_ENABLED = "tuioEnabled";
	private static final String TUIO_PORT = "tuioPort";
	private static final String TUIO_HOST = "tuioHost";
	private static final String CURSOR_CONTROL = "cursorControl";
	private static final String ASSIST_DOUBLE_CLICKS = "assistDoubleClicks";
	private static final String LANGUAGE = "language";
	
	public static interface PreferencesListener {
		public void preferencesChanged();
	}	
	
	private final Set<PreferencesListener> listener = new HashSet<PreferencesListener>();
	private final static WWPreferences instance = new WWPreferences();	
	private final Preferences settings;
	
	private WWPreferences() {
		settings = Preferences.userNodeForPackage(WiimoteWhiteboard.class);
		MouseSmoothingStrategy.REGISTERED.put(NoSmoothing.NAME, NoSmoothing.class);
		MouseSmoothingStrategy.REGISTERED.put(SimpleMovingAverage.NAME, SimpleMovingAverage.class);
	}
	
	public static WWPreferences getPreferences() {
		return instance;
	}
	
	public void reset() {
		try {
			settings.clear();
			notifyListener();
		} catch (BackingStoreException e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * LISTENER
	 */
	
	public void addPreferencesListener(PreferencesListener l) {
		listener.add(l);
	}
	
	public void removePreferencesListener(PreferencesListener l) {
		listener.remove(l);
	}
	
	private void notifyListener() {
		for (Object l : listener.toArray())
			((PreferencesListener)l).preferencesChanged();
	}
	
	/*
	 * GETTER & SETTER
	 */	
	
	public boolean isLeftClick() {
		return settings.getBoolean(LEFT_CLICK, true);
	}

	public void setLeftClick(boolean leftClick) {
		settings.putBoolean(LEFT_CLICK, leftClick);
		notifyListener();
	}

	public boolean isRightClick() {
		return settings.getBoolean(RIGHT_CLICK, true);
	}

	public void setRightClick(boolean rightClick) {
		settings.putBoolean(RIGHT_CLICK, rightClick);
		notifyListener();
	}

	public long getRightClickDelay() {
		return settings.getLong(RIGHT_CLICK_DELAY, 1000L);
	}

	public void setRightClickDelay(long rightClickDelay) {
		settings.putLong(RIGHT_CLICK_DELAY, rightClickDelay);
		notifyListener();
	}
	
	public boolean isLowBatteryWarning() {
		return settings.getBoolean(LOW_BATTERY_WARNING, true);
	}
	
	public void setLowBatteryWarning(boolean lowBatteryWarning) {
		settings.putBoolean(LOW_BATTERY_WARNING, lowBatteryWarning);
		notifyListener();
	}
	
	public boolean checkForUpdates() {
		return settings.getBoolean(CHECK_FOR_UPDATES, true);
	}
	
	public void setCheckForUpdates(boolean checkForUpdates) {
		settings.putBoolean(CHECK_FOR_UPDATES, checkForUpdates);
		notifyListener();
	}
	
	public String getMouseSmoothing() {
		return settings.get(MOUSE_SMOOTHING, AdaptiveExponentialSmoothing.class.getName());
	}

	public void setMouseSmoothing(String mouseSmoothing) {
		if (!getMouseSmoothing().equals(mouseSmoothing)) {
			settings.put(MOUSE_SMOOTHING, mouseSmoothing);
			notifyListener();
		}
	}
	
	public boolean isTuioEnabled() {
		return settings.getBoolean(TUIO_ENABLED, false);
	}
	
	public void setTuioEnabled(boolean tuioEnabled) {
		settings.putBoolean(TUIO_ENABLED, tuioEnabled);
		notifyListener();
	}
	
	public int getTuioPort() {
		return settings.getInt(TUIO_PORT, 3333);
	}
	
	public void setTuioPort(int tuioPort) {
		settings.putInt(TUIO_PORT, tuioPort);
	}
	
	public String getTuioHost() {
		return settings.get(TUIO_HOST, "localhost");
	}
	
	public void setTuioHost(String tuioHost) {
		settings.put(TUIO_HOST, tuioHost);
	}
	
	public String getCursorControl() {
		return settings.get(CURSOR_CONTROL, DefaultControlStrategy.class.getName());
	}

	public void setCursorControl(String cursorControl) {
		settings.put(CURSOR_CONTROL, cursorControl);
		notifyListener();
	}
	
	public boolean assistDoubleClicks() {
		return settings.getBoolean(ASSIST_DOUBLE_CLICKS, false);
	}
	
	public void setAssistDoubleClicks(boolean assistDoubleClicks) {
		settings.putBoolean(ASSIST_DOUBLE_CLICKS, assistDoubleClicks);
		notifyListener();
	}
	
	public void setLanguage(String language) {
		if (!getLanguage().equals(language)) {
			settings.put(LANGUAGE, language);
			notifyListener();
		}
	}
	
	public String getLanguage() {
		return settings.get(LANGUAGE, "");
	}
}
