package net.oni2.aeinstaller.backend.oni.management;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.TreeSet;

import net.oni2.aeinstaller.backend.Paths;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;

/**
 * @author Christian Illy
 */
public class ModInstallationList {
	private static ModInstallationList instance = loadList();

	private TreeSet<Integer> mods = new TreeSet<Integer>();
	private HashSet<String> affectedLevels = new HashSet<String>();
	private transient boolean isLoaded = false;

	/**
	 * @return Get singleton instance
	 */
	public static ModInstallationList getInstance() {
		return instance;
	}

	/**
	 * @return Currently installed mods
	 */
	public TreeSet<Integer> getInstalledMods() {
		return mods;
	}

	/**
	 * Check if given mod is installed
	 * 
	 * @param packageId
	 *            Package Id to check for
	 * @return Is mod installed?
	 */
	public boolean isInstalled(int packageId) {
		return mods.contains(packageId);
	}

	/**
	 * Set the mods that are installed by a new installation
	 * 
	 * @param mods
	 *            List of installed mods
	 */
	public void setInstalledMods(TreeSet<Integer> mods) {
		this.mods = mods;
	}

	/**
	 * @return List of affected levels by current installation
	 */
	public HashSet<String> getAffectedLevels() {
		return affectedLevels;
	}

	/**
	 * Check if given level is affected by current mod installation
	 * 
	 * @param level
	 *            Level name (e.g. level1_Final)
	 * @return Is level affected?
	 */
	public boolean isLevelAffected(String level) {
		return affectedLevels.contains(level.toLowerCase());
	}

	/**
	 * Set the levels that are affected by a new mod installation
	 * 
	 * @param levels
	 *            List of affected level
	 */
	public void setAffectedLevels(HashSet<String> levels) {
		affectedLevels.clear();
		for (String l : levels) {
			affectedLevels.add(l.toLowerCase());
		}
	}

	/**
	 * Check if the current state of the ModInstallationList was loaded from the
	 * mod_installation.xml
	 * 
	 * @return Loaded from file?
	 */
	public boolean isLoadedFromFile() {
		return isLoaded;
	}

	private static File getFile() {
		return new File(Paths.getEditionGDF(), "installed_mods.xml");
	}

	private static XStream getStream() {
		XStream xs = new XStream(new StaxDriver());
		xs.alias("MIL", ModInstallationList.class);
		return xs;
	}

	private static ModInstallationList loadList() {
		ModInstallationList mil = new ModInstallationList();
		try {
			if (getFile().exists()) {
				FileInputStream fis = new FileInputStream(getFile());
				XStream xs = getStream();
				Object obj = xs.fromXML(fis);
				if (obj instanceof ModInstallationList) {
					mil = (ModInstallationList) obj;
					mil.isLoaded = true;
				}
				fis.close();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return mil;
	}

	/**
	 * Write this mod installation list to the installed_mods.xml file
	 */
	public void saveList() {
		try {
			FileOutputStream fos = new FileOutputStream(getFile());
			XStream xs = getStream();
			xs.toXML(this, fos);
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
