package org.positrium.chikarawo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlrpc.XmlRpcException;

import ow.routing.RoutingException;

import com.dokukino.genkidama.DHTManager;
import com.dokukino.genkidama.VersionInfo;

import dareka.Main;
import dareka.Server;
import dareka.common.CloseUtil;
import dareka.common.Config;
import dareka.processor.impl.Cache;

/**
 * use SystemTray widget. this is presentation version. because, extends
 * dareka.Main .
 * 
 * @author token , 2009 CC BY-SA
 * @version $Rev: 69 $
 * 
 */
public class SysTrayStart extends Main {
	// public static TrayIcon trayIcon;

	public static Log logger = LogFactory.getLog(SysTrayStart.class);

	// public so that external tools can read.
	// public static final String VER_STRING = "Genkidama 0.03";

	// accessor for avoiding static link
	// public static String getVersion() {
	// return VER_STRING;
	// }

	private static Server server;
	private static Gokuu gokuu;

	public static void stop() throws RoutingException {
		logger.info("Shutting down");
		if (server != null) {
			server.stop();
		}
		if (DHTManager.getInstance().isConnected())
			DHTManager.getInstance().disconnect();
	}

	public static void main(String[] args) {
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				try {
					Main.stop();
				} catch (RoutingException e) {
					// TODO Auto-generated catch block
					logger.error("Error Occurs:", e);
				}
			}
		});

		gokuu = new Gokuu();
		gokuu.shout();

		try {
			mainBody();
		} catch (XmlRpcException e) {
			logger.debug(e);
		} catch (Exception e) {
			logger.error("Error Occurs:", e);
		}
	}

	private static void mainBody() throws Exception {
		// [nl] iniにしたい人用。でも正確にはiniファイルじゃないよ
		File configFile = new File("config.ini");
		if (!configFile.exists()) {
			configFile = new File("config.properties");
		}

		// 設定ファイルがなくてデフォルト設定ファイルがあるならリネームして使う
		if (!configFile.exists()) {
			File defFile = new File("config.properties.default");
			if (defFile.exists()) {
				defFile.renameTo(configFile);
			}
		}

		Config config = configure(configFile);
		StringBuilder setting_status = new StringBuilder("User configuration")
				.append("\n");
		setting_status.append("  version: ").append(
				VersionInfo.getFullVersion()).append("\n");
		setting_status.append("  primary proxy: ").append(
				Integer.getInteger("listenPort")).append("\n");

		if (System.getProperty("proxyHost").equals("")) {
			setting_status.append("  secondary proxy: none").append("\n");
		} else {
			setting_status.append("  secondary proxy: ").append(
					System.getProperty("proxyHost")).append(": ").append(
					Integer.getInteger("proxyPort")).append("\n");
		}

		setting_status.append("  title name fetch: ").append(
				Boolean.getBoolean("title")).append("\n");

		setting_status.append("  resume suspended download: ").append(
				Boolean.getBoolean("resumeDownload")).append("\n");

		setting_status.append("  touch cache file: ").append(
				Boolean.getBoolean(("touchCache"))).append("\n");

		logger.info(setting_status.toString());

		// if (Boolean.getBoolean("dareka.debug")) {//
		// logger.info("debug mode");
		// }

		DHTManager.getInstance().connect();
		Cache.init();
		// for resume
		// Cache.cleanup();
		logger.info(String.format("total self cache size=%,dbytes\n", Long
				.valueOf(Cache.size())));

		server = new Server(config);

		// gokuu.switchTrayIcon();
		server.start();
	}

	@SuppressWarnings("deprecation")
	private static Config configure(File configFile) throws IOException {
		Properties p = new Properties();
		setDefaults(p);

		Config config = new Config();
		if (configFile.exists()) {
			loadFrom(configFile, p);

			String v;

			v = p.getProperty(Config.LISTEN_PORT);
			if (v != null) {
				config.setListenPort(Integer.parseInt(v));
			}

			v = p.getProperty(Config.PROXY_HOST);
			if (v != null) {
				config.setProxyHost(v);
			}

			v = p.getProperty(Config.PROXY_PORT);
			if (v != null) {
				config.setProxyPort(Integer.parseInt(v));
			}

			v = p.getProperty(Config.TITLE);
			if (v != null) {
				config.setTitle(Boolean.parseBoolean(v));
			}
		} else {
			p
					.setProperty("dhtSecret", RandomStringUtils
							.randomAlphanumeric(40));
			FileOutputStream out = new FileOutputStream(configFile);
			try { // ensure closing out
				p.store(out, "NicoCache config file");
			} finally {
				CloseUtil.close(out);
			}
		}

		for (Map.Entry<Object, Object> entry : p.entrySet()) {
			String key = (String) entry.getKey();
			String value = (String) entry.getValue();
			System.setProperty(key, value.trim());
		}

		return config;
	}

	private static void loadFrom(File configFile, Properties p)
			throws FileNotFoundException, IOException {
		FileInputStream in = new FileInputStream(configFile);
		try { // ensure closing in
			p.load(in);
		} finally {
			CloseUtil.close(in);
		}
	}

	private static void setDefaults(Properties p) {
		try {
			setDefaultsFromFiles(p);
			if (p.size() > 0) {
				return;
			}
		} catch (IOException e) {
			logger.debug(e);
		}

		p.setProperty("listenPort", "8080");
		p.setProperty("proxyHost", "");
		p.setProperty("proxyPort", "8081");
		p.setProperty("title", "true");
		p.setProperty("touchCache", "true");
	}

	private static void setDefaultsFromFiles(Properties p) throws IOException {
		File defaultsDir = new File("defaults");

		File[] files = defaultsDir.listFiles(new FilenameFilter() {
			public boolean accept(File dir, String name) {
				if (name.endsWith(".properties")) {
					return true;
				} else {
					return false;
				}
			}
		});

		if (files == null) {
			throw new IOException("failed to read: " + defaultsDir);
		}

		Arrays.sort(files);
		for (File f : files) {
			loadFrom(f, p);
		}
	}
}
