package net.oni2.aeinstaller.backend.packages.download;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;

import net.oni2.aeinstaller.backend.Paths;
import net.oni2.aeinstaller.backend.packages.Package;
import net.oni2.httpfiledownloader.FileDownloadListener;
import net.oni2.httpfiledownloader.FileDownloader;
import net.oni2.httpfiledownloader.FileDownloader.EState;
import net.oni2.aeinstaller.backend.packages.unpack.UnpackListener;
import net.oni2.aeinstaller.backend.packages.unpack.Unpacker;

/**
 * @author Christian Illy
 */
public class ModDownload implements FileDownloadListener, UnpackListener {
	/**
	 * @author Christian Illy
	 */
	public enum ModDownloadState {
		/**
		 * Downloader initialized but not started
		 */
		INIT,
		/**
		 * Download running
		 */
		RUNNING,
		/**
		 * Aborted because of an error
		 */
		ERROR,
		/**
		 * Download interrupted
		 */
		INTERRUPTED,
		/**
		 * Download finished successfully
		 */
		DOWNLOADED,
		/**
		 * Package unzipped successfully
		 */
		UNPACKED
	};

	private Package mod;
	private FileDownloader downloader;
	private Unpacker unpacker;
	private File zipFile;
	private File targetFolder;
	private ModDownloadListener listener;
	private int size;

	private ModDownloadState state = ModDownloadState.INIT;

	/**
	 * Create a mod download
	 * 
	 * @param mod
	 *            Mod to download
	 * @param listener
	 *            Listener for progress
	 */
	public ModDownload(Package mod, ModDownloadListener listener) {
		this.mod = mod;
		this.listener = listener;

		zipFile = new File(Paths.getDownloadPath(),
				mod.getPackageNumberString() + ".zip");
		targetFolder = mod.getLocalPath();
		try {
			downloader = new FileDownloader(mod.getFileUrl(), zipFile);
			downloader.addListener(this);
			unpacker = new Unpacker(zipFile, targetFolder, this);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * @return Size of this download
	 */
	public int getSize() {
		return mod.getZipSize();
	}

	/**
	 * Start this download
	 */
	public void start() {
		state = ModDownloadState.RUNNING;
		downloader.start();
	}

	/**
	 * Abort this download
	 */
	public void abort() {
		switch (state) {
			case UNPACKED:
			case INIT:
			case ERROR:
			case INTERRUPTED:
				break;
			case RUNNING:
				downloader.stop();
				break;
			case DOWNLOADED:
				unpacker.stop();
				break;
		}
		state = ModDownloadState.INTERRUPTED;
	}

	/**
	 * @return the mod object handled by this download
	 */
	public Package getMod() {
		return mod;
	}

	private void writeTimestamp() {
		File logFile = new File(targetFolder, "aei.cfg");
		PrintWriter log = null;
		try {
			log = new PrintWriter(logFile);
			log.println("Timestamp -> " + mod.getUpdatedMillis());
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		if (log != null)
			log.close();
	}

	@Override
	public void statusUpdate(FileDownloader source, EState state, int done,
			int total) {
		switch (state) {
			case INIT:
				break;
			case RUNNING:
				listener.modDownloadStatusUpdate(this, this.state, done, total);
				break;
			case PAUSED:
				break;
			case INTERRUPTED:
				break;
			case ERROR:
				this.state = ModDownloadState.ERROR;
				listener.modDownloadStatusUpdate(this, this.state, done, total);
				break;
			case FINISHED:
				this.state = ModDownloadState.DOWNLOADED;
				listener.modDownloadStatusUpdate(this, this.state, done, total);
				this.size = done;
				unpacker.start();
				break;
		}
	}

	@Override
	public void statusUpdate(Unpacker source,
			net.oni2.aeinstaller.backend.packages.unpack.Unpacker.EState state) {
		switch (state) {
			case INIT:
				break;
			case RUNNING:
				break;
			case INTERRUPTED:
				this.state = ModDownloadState.INTERRUPTED;
				listener.modDownloadStatusUpdate(this, this.state, size, size);
				break;
			case FINISHED:
				this.state = ModDownloadState.UNPACKED;
				writeTimestamp();
				zipFile.delete();
				listener.modDownloadStatusUpdate(this, this.state, size, size);
				break;
		}
	}
}
