package net.oni2;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;

/**
 * Manages and stores programm settings
 * 
 * @author Christian Illy
 */
public class SettingsManager implements Serializable {

	private static final long serialVersionUID = 8067725289301601179L;

	private static SettingsManager instance = new SettingsManager();

	private static boolean debugRun = false;
	private static boolean useWorkingDir = false;

	private HashMap<String, Object> prefs = new HashMap<String, Object>();

	private boolean printNamesNotInMap = false;

	private boolean offlineMode = false;
	private boolean noCacheUpdate = false;

	/**
	 * Get the singleton instance
	 * 
	 * @return Singleton instance
	 */
	public static SettingsManager getInstance() {
		return instance;
	}

	/**
	 * @param debug
	 *            Debug mode
	 */
	public static void setDebug(boolean debug) {
		debugRun = debug;
	}

	/**
	 * @return Is debug run
	 */
	public static boolean isDebug() {
		return debugRun;
	}

	/**
	 * @param useWd
	 *            Use working directory instead of jar path
	 */
	public static void setUseWorkingDir(boolean useWd) {
		useWorkingDir = useWd;
	}

	/**
	 * @return Do we want to use working directory
	 */
	public static boolean getUseWorkingDir() {
		return useWorkingDir;
	}

	/**
	 * @return Is offline?
	 */
	public boolean isOfflineMode() {
		return offlineMode;
	}

	/**
	 * @param offline
	 *            Is offline?
	 */
	public void setOfflineMode(boolean offline) {
		this.offlineMode = offline;
	}

	/**
	 * @return Is in noCacheUpdate mode?
	 */
	public boolean isNoCacheUpdateMode() {
		return noCacheUpdate;
	}

	/**
	 * @param noCacheUpdate
	 *            Is in noCacheUpdate mode?
	 */
	public void setNoCacheUpdateMode(boolean noCacheUpdate) {
		this.noCacheUpdate = noCacheUpdate;
	}

	private static XStream getXStream() {
		XStream xs = new XStream(new StaxDriver());
		xs.alias("Settings", SettingsManager.class);
		return xs;
	}

	/**
	 * Serializes the settings to disk
	 * 
	 * @param settingsFile
	 *            File to write to
	 */
	public void serializeToFile(File settingsFile) {
		try {
			FileOutputStream fos = new FileOutputStream(settingsFile);
			XStream xs = getXStream();
			xs.toXML(this, fos);
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Deserializes the settings from disk
	 * 
	 * @param settingsFile
	 *            File to read from
	 */
	public static void deserializeFromFile(File settingsFile) {
		try {
			FileInputStream fis = new FileInputStream(settingsFile);
			XStream xs = getXStream();
			Object obj = xs.fromXML(fis);
			if (obj instanceof SettingsManager)
				instance = (SettingsManager) obj;
			fis.close();
		} catch (FileNotFoundException e) {
		} catch (IOException e) {
		}
	}

	/**
	 * Put a string value
	 * 
	 * @param key
	 *            Key for value
	 * @param value
	 *            Value
	 */
	public void put(String key, String value) {
		prefs.put(key, value);
	}

	/**
	 * Put a boolean value
	 * 
	 * @param key
	 *            Key for value
	 * @param value
	 *            Value
	 */
	public void put(String key, boolean value) {
		prefs.put(key, value);
	}

	/**
	 * Put a int value
	 * 
	 * @param key
	 *            Key for value
	 * @param value
	 *            Value
	 */
	public void put(String key, int value) {
		prefs.put(key, value);
	}

	/**
	 * Get a string value
	 * 
	 * @param key
	 *            Key for value
	 * @param def
	 *            Default return value if key does not exist
	 * @return Value
	 */
	public String get(String key, String def) {
		if (prefs.containsKey(key)) {
			if (prefs.get(key) instanceof String)
				return (String) (prefs.get(key));
		}
		if (printNamesNotInMap)
			System.out.println("Settings: Key \"" + key
					+ "\" not in Map, defaulting to \"" + def + "\".");
		return def;
	}

	/**
	 * Get a boolean value
	 * 
	 * @param key
	 *            Key for value
	 * @param def
	 *            Default return value if key does not exist
	 * @return Value
	 */
	public Boolean get(String key, Boolean def) {
		if (prefs.containsKey(key)) {
			if (prefs.get(key) instanceof Boolean)
				return (Boolean) (prefs.get(key));
		}
		if (printNamesNotInMap)
			System.out.println("Settings: Key \"" + key
					+ "\" not in Map, defaulting to \"" + def + "\".");
		return def;
	}

	/**
	 * Get a int value
	 * 
	 * @param key
	 *            Key for value
	 * @param def
	 *            Default return value if key does not exist
	 * @return Value
	 */
	public int get(String key, int def) {
		if (prefs.containsKey(key)) {
			if (prefs.get(key) instanceof Integer)
				return (Integer) (prefs.get(key));
		}
		if (printNamesNotInMap)
			System.out.println("Settings: Key \"" + key
					+ "\" not in Map, defaulting to \"" + def + "\".");
		return def;
	}

	/**
	 * Remove a value
	 * 
	 * @param key
	 *            Key to value to remove
	 */
	public void removeValue(String key) {
		prefs.remove(key);
	}

}
