package charactermanaj.model.util;

import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;

import charactermanaj.model.AppConfig;
import charactermanaj.model.io.WorkingSetPersist;
import charactermanaj.util.ApplicationLogHandler;
import charactermanaj.util.ConfigurationDirUtilities;


/**
 * 開始前の事前準備するためのサポートクラス
 *
 * @author seraphy
 */
public abstract class StartupSupport {

	private static StartupSupport inst;

	/**
	 * インスタンスを取得する.
	 *
	 * @return シングルトンインスタンス
	 */
	public static synchronized StartupSupport getInstance() {
		if (inst == null) {
			inst = new StartupSupport() {
				private final Logger logger = Logger.getLogger(StartupSupport.class.getName());

				@Override
				public void doStartup() {
					StartupSupport[] startups = {
							new MoveAppDataToLocalAppData(),
							new PurgeOldLogs(),
							new PurgeOldWorkingSetXml(),
							//new ConvertRecentCharDirsSerToXmlProps(),
							//new ConvertWorkingSetSerToXml(),
							//new PurgeOldCaches(),
					};
					for (StartupSupport startup : startups) {
						logger.log(Level.FINE, "startup operation start. class="
								+ startup.getClass().getSimpleName());
						try {
							startup.doStartup();
							logger.log(Level.FINE, "startup operation is done.");

						} catch (Exception ex) {
							logger.log(Level.WARNING, "startup operation failed.", ex);
						}
					}
				}
			};
		}
		return inst;
	}

	/**
	 * スタートアップ処理を実施します.
	 */
	public abstract void doStartup();
}

/**
 * APPDATAフォルダにあったワーキングセット類をLOCALAPPDATAに移動する。
 */
class MoveAppDataToLocalAppData extends StartupSupport {

	/**
	 * ロガー
	 */
	private final Logger logger = Logger.getLogger(getClass().getName());

	@Override
	public void doStartup() {
		File appDataDir = ConfigurationDirUtilities.getUserDataDir();
		File localAppDataDir = ConfigurationDirUtilities.getLocalUserDataDir();
		if (appDataDir.equals(localAppDataDir)) {
			// 移動元・移動先が同一であれば何もしない。
			return;
		}

		// ログフォルダ、ログ設定はすでにログが開始されているので移動しない。
		String[] files = {"recent-characterdirs.xml", "workingset"};
		for (String file : files) {
			try {
				File target = new File(localAppDataDir, file);
				if (target.exists()) {
					// すでにあれば何もしない
					continue;
				}
				File source = new File(appDataDir, file);
				if (source.exists()) {
					// まだ移動されていない場合であれば移動を試みる
					boolean result = source.renameTo(target);
					logger.log(Level.INFO, "Move " + source + " to " + target +
							". result=" + (result ? "succeeded" : "failed"));
				}
			} catch (Exception ex) {
				logger.log(Level.SEVERE, "Failed to move file. " + file, ex);
			}
		}
	}
}

/**
 * 使われていないWorkingset.xmlを削除する
 */
class PurgeOldWorkingSetXml extends StartupSupport {

	@Override
	public void doStartup() {
		AppConfig appConfig = AppConfig.getInstance();
		long purgeOldLogsMillSec = appConfig.getPurgeLogDays() * 24L * 3600L * 1000L;
		if (purgeOldLogsMillSec <= 0) {
			return;
		}

		// ワーキングセットの掃除判定日時
		// これよりも新しいものは実際に使われているかを問わず、削除判定しない。
		final long expireDate = System.currentTimeMillis() - purgeOldLogsMillSec;

		// 指定した日時以前のワーキングセットについて本体データが削除されているものは
		// ワーキングセットも削除する。
		WorkingSetPersist persist = new WorkingSetPersist();
		persist.purge(expireDate);
	}
}

// ver0.999で廃止。
///**
// * シリアライズによるキャラクターディレクトリリストの保存をXML形式のPropertiesにアップグレードします。
// *
// * @author seraphy
// *
// */
//class ConvertRecentCharDirsSerToXmlProps extends StartupSupport {
//	/**
//	 * ロガー
//	 */
//	private final Logger logger = Logger.getLogger(getClass().getName());
//
//	@Override
//	public void doStartup() {
//		// 旧形式(ver0.991以前)
//		UserDataFactory factory = UserDataFactory.getInstance();
//
//		final String FILENAME = "recent-characterdirs.ser";
//		File prevFile = new File(factory.getSpecialDataDir(FILENAME), FILENAME);
//
//		try {
//			if (prevFile.exists()) {
//				FileUserData recentCharDirs = new FileUserData(prevFile);
//				RecentCharactersDir obj = (RecentCharactersDir) recentCharDirs
//						.load();
//
//				// 新しい形式で保存する.
//				obj.saveRecents();
//
//				// 古いファイルを削除する
//				prevFile.delete();
//			}
//
//		} catch (Exception ex) {
//			logger.log(Level.WARNING, FILENAME + " convert failed.", ex);
//		}
//	}
//}

//ver0.999で廃止。
///**
// * シリアライズによるキャラクターディレクトリリストの保存をXML形式のPropertiesにアップグレードします。
// *
// * @author seraphy
// *
// */
//class ConvertWorkingSetSerToXml extends StartupSupport {
//	/**
//	 * ロガー
//	 */
//	private final Logger logger = Logger.getLogger(getClass().getName());
//
//	@Override
//	public void doStartup() {
//		final String FILENAME = "workingset.ser";
//		try {
//			UserDataFactory userDataFactory = UserDataFactory.getInstance();
//			File dir = userDataFactory.getSpecialDataDir(FILENAME);
//			if (!dir.exists()) {
//				return;
//			}
//			File[] files = dir.listFiles(new FileFilter() {
//				public boolean accept(File pathname) {
//					String name = pathname.getName();
//					return name.endsWith(FILENAME);
//				}
//			});
//			if (files == null) {
//				logger.log(Level.WARNING, "cache-dir access failed. " + dir);
//				return;
//			}
//			WorkingSetXMLWriter wr = new WorkingSetXMLWriter();
//			for (File file : files) {
//				FileUserData fileData = new FileUserData(file);
//				if (fileData.exists()) {
//					try {
//						// serファイルをデシリアライズする.
//						WorkingSet ws = (WorkingSet) fileData.load();
//						URI docBase = ws.getCharacterDocBase();
//						if (docBase != null) {
//							// XML形式で保存しなおす.
//							UserData workingSetXmlData = userDataFactory
//									.getMangledNamedUserData(docBase,
//											WorkingSetPersist.WORKINGSET_FILE_SUFFIX);
//							if (!workingSetXmlData.exists()) {
//								// XML形式データがまだない場合のみ保存しなおす.
//								OutputStream outstm = workingSetXmlData
//										.getOutputStream();
//								try {
//									wr.writeWorkingSet(ws, outstm);
//								} finally {
//									outstm.close();
//								}
//							}
//						}
//
//						// serファイルは削除する.
//						fileData.delete();
//
//					} catch (Exception ex) {
//						logger.log(Level.WARNING,
//								FILENAME + " convert failed.", ex);
//					}
//				}
//			}
//
//		} catch (Exception ex) {
//			logger.log(Level.WARNING, FILENAME + " convert failed.", ex);
//		}
//	}
//}

/**
 * 古いログファイルを消去する.
 *
 * @author seraphy
 */
class PurgeOldLogs extends StartupSupport {

	@Override
	public void doStartup() {
		AppConfig appConfig = AppConfig.getInstance();
		long purgeOldLogsMillSec = appConfig.getPurgeLogDays() * 24L * 3600L * 1000L;
		if (purgeOldLogsMillSec > 0) {
			// 期限切れのログファイルを削除する
			long expiredDate = System.currentTimeMillis() - purgeOldLogsMillSec;
			ApplicationLogHandler.purge(expiredDate);
		}
	}
}

//ver0.999で廃止。
///**
// * 古いキャッシュファイルを消去する.<br>
// * -character.xml-cache.ser, -favorites.serは、直接xmlでの読み込みになったため、 ただちに消去しても問題ない.<br>
// * recent-character.serは、使用されなくなったため、ただちに消去して良い.<br>
// * mangled_info.xmlは、*.serを消去したあとには不要となるため、消去する.<br>
// * (今後使われることはない)
// *
// * @author seraphy
// */
//class PurgeOldCaches extends StartupSupport {
//
//	/**
//	 * ロガー
//	 */
//	private final Logger logger = Logger.getLogger(getClass().getName());
//
//	@Override
//	public void doStartup() {
//		UserDataFactory userDataFactory = UserDataFactory.getInstance();
//		File cacheDir = userDataFactory.getSpecialDataDir(".ser");
//		if (cacheDir.exists()) {
//			File[] files = cacheDir.listFiles();
//			if (files == null) {
//				logger.log(Level.WARNING, "cache-dir access failed.");
//				return;
//			}
//			for (File file : files) {
//				try {
//					if (!file.isFile() || !file.canWrite()) {
//						// ファイルでないか、書き込み不可の場合はスキップする.
//						continue;
//					}
//					String name = file.getName();
//					if (name.endsWith("-character.xml-cache.ser")
//							|| name.endsWith("-favorites.ser")
//							|| name.equals("recent-character.ser")
//							|| name.equals("mangled_info.xml")) {
//						boolean result = file.delete();
//						logger.log(Level.INFO, "remove file " + file
//								+ "/succeeded=" + result);
//					}
//
//				} catch (Exception ex) {
//					logger.log(Level.WARNING, "remove file failed. " + file, ex);
//				}
//			}
//		}
//	}
//}
