package net.oni2.aeinstaller.backend.oni;

import java.io.File;
import java.io.IOException;
import java.util.Vector;

import net.oni2.aeinstaller.backend.CaseInsensitiveFile;
import net.oni2.aeinstaller.backend.Paths;
import net.oni2.platformtools.PlatformInformation;
import net.oni2.platformtools.PlatformInformation.Platform;
import net.oni2.platformtools.applicationinvoker.ApplicationInvoker;
import net.oni2.platformtools.applicationinvoker.ApplicationInvocationResult;
import net.oni2.platformtools.applicationinvoker.EExeType;
import net.oni2.platformtools.applicationinvoker.ERuntimeNotInstalledException;

/**
 * @author Christian Illy
 */
public class OniSplit {

	/**
	 * @return Is Onisplit installed?
	 */
	public static boolean isOniSplitInstalled() {
		return getProgramFile().exists();
	}

	/**
	 * Export given dat-file to target folder
	 * 
	 * @param targetFolder
	 *            Target folder
	 * @param input
	 *            Dat file
	 * @return OniSplit output
	 */
	public static ApplicationInvocationResult export(File targetFolder,
			File input) {
		return export(targetFolder, input, null);
	}

	/**
	 * Export named resources from given dat-file to target folder
	 * 
	 * @param targetFolder
	 *            Target folder
	 * @param input
	 *            Dat file
	 * @param patterns
	 *            Filename patterns for files to export
	 * @return OniSplit output
	 */
	public static ApplicationInvocationResult export(File targetFolder,
			File input, Vector<String> patterns) {
		if (!targetFolder.exists())
			targetFolder.mkdir();

		Vector<String> params = new Vector<String>();
		if (patterns == null)
			params.add("-export");
		else {
			for (String p : patterns)
				params.add("-export:" + p);
		}
		params.add(targetFolder.getPath());
		params.add(input.getPath());
		ApplicationInvocationResult res = null;
		try {
			res = ApplicationInvoker.executeAndWait(EExeType.DOTNET, null,
					getProgramFile(), params, false);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ERuntimeNotInstalledException e) {
			e.printStackTrace();
		}
		return res;
	}

	/**
	 * Import given folder to a .dat-file
	 * 
	 * @param sourceFolders
	 *            Folders containing .oni-files
	 * @param targetFile
	 *            Target .dat-file
	 * @return OniSplit output
	 */
	public static ApplicationInvocationResult importLevel(
			Vector<File> sourceFolders, File targetFile) {
		Vector<String> params = new Vector<String>();
		params.add(getImportParam());
		for (File f : sourceFolders)
			params.add(f.getPath());
		params.add(targetFile.getPath());
		ApplicationInvocationResult res = null;
		try {
			res = ApplicationInvoker.executeAndWait(EExeType.DOTNET, null,
					getProgramFile(), params, false);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ERuntimeNotInstalledException e) {
			e.printStackTrace();
		}
		return res;
	}

	/**
	 * Pack a level to a .dat-file. More powerful variant which allows
	 * specifying single .oni/.dat files
	 * 
	 * @param sourceFoldersFiles
	 *            Folders (for recursive .oni import) or files (.dat and single
	 *            .oni) to import
	 * @param targetFile
	 *            Target .dat-file
	 * @return OniSplit output
	 */
	public static ApplicationInvocationResult packLevel(
			Vector<File> sourceFoldersFiles, File targetFile) {
		Vector<String> params = new Vector<String>();
		params.add(getPackParam());
		params.add(getPackTypeParam());
		params.add("-out");
		params.add(targetFile.getPath());
		for (File f : sourceFoldersFiles)
			params.add(f.getPath());
		ApplicationInvocationResult res = null;
		try {
			res = ApplicationInvoker.executeAndWait(EExeType.DOTNET, null,
					getProgramFile(), params, false);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ERuntimeNotInstalledException e) {
			e.printStackTrace();
		}
		return res;
	}

	/**
	 * Move files from one location to another using OniSplit so relations are
	 * handled
	 * 
	 * @param targetFolder
	 *            Target folder for files
	 * @param input
	 *            Files to move, can contain wildcards
	 * @param moveParameter
	 *            e.g. overwrite, delete
	 * @return OniSplit output
	 */
	public static ApplicationInvocationResult move(File targetFolder,
			String input, String moveParameter) {
		if (!targetFolder.exists())
			targetFolder.mkdir();

		Vector<String> params = new Vector<String>();
		params.add("-move" + (moveParameter != null ? ":" + moveParameter : ""));
		params.add(targetFolder.getPath());
		params.add(input);
		ApplicationInvocationResult res = null;
		try {
			res = ApplicationInvoker.executeAndWait(EExeType.DOTNET, null,
					getProgramFile(), params, false);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ERuntimeNotInstalledException e) {
			e.printStackTrace();
		}
		return res;
	}

	/**
	 * Convert given .oni-files to XML and put them in target folder
	 * 
	 * @param targetFolder
	 *            Target folder
	 * @param inputFiles
	 *            .oni files
	 * @return OniSplit output
	 */
	public static ApplicationInvocationResult convertOniToXML(
			File targetFolder, Vector<File> inputFiles) {
		if (!targetFolder.exists())
			targetFolder.mkdirs();

		Vector<String> params = new Vector<String>();
		params.add("-extract:xml");
		params.add(targetFolder.getPath());
		for (File f : inputFiles) {
			params.add(f.getPath());
		}
		ApplicationInvocationResult res = null;
		try {
			res = ApplicationInvoker.executeAndWait(EExeType.DOTNET, null,
					getProgramFile(), params, false);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ERuntimeNotInstalledException e) {
			e.printStackTrace();
		}
		return res;
	}

	/**
	 * Convert given XML-files to .oni and put them in target folder
	 * 
	 * @param targetFolder
	 *            Target folder
	 * @param inputFiles
	 *            XML-files
	 * @return OniSplit output
	 */
	public static ApplicationInvocationResult convertXMLtoOni(
			File targetFolder, Vector<File> inputFiles) {
		if (!targetFolder.exists())
			targetFolder.mkdirs();

		Vector<String> params = new Vector<String>();
		params.add("-create");
		params.add(targetFolder.getPath());
		for (File f : inputFiles) {
			params.add(f.getPath());
		}
		ApplicationInvocationResult res = null;
		try {
			res = ApplicationInvoker.executeAndWait(EExeType.DOTNET, null,
					getProgramFile(), params, false);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ERuntimeNotInstalledException e) {
			e.printStackTrace();
		}
		return res;
	}

	private static String getImportParam() {
		if (PlatformInformation.getPlatform() == Platform.MACOS)
			return "-import:sep";
		else
			return "-import:nosep";
	}

	private static String getPackParam() {
		return "pack";
	}

	private static String getPackTypeParam() {
		if (PlatformInformation.getPlatform() == Platform.MACOS)
			return "-type:macintel";
		else
			return "-type:pc";
	}

	private static File getProgramFile() {
		File toolsPath = CaseInsensitiveFile.getCaseInsensitiveFile(
				Paths.getEditionBasePath(), "Tools");
		return CaseInsensitiveFile.getCaseInsensitiveFile(toolsPath,
				"Onisplit.exe");
	}
}
