/*
 * Copyright (c) 2005- Shinji Kashihara.
 * All rights reserved. This program are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies
 * this distribution, and is available at epl-v10.html.
 */
package jp.sourceforge.mergedoc.pleiades.generator.nls;

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

import jp.sourceforge.mergedoc.pleiades.generator.Generator;
import jp.sourceforge.mergedoc.pleiades.log.Logger;
import jp.sourceforge.mergedoc.pleiades.log.Logger.Level;
import jp.sourceforge.mergedoc.pleiades.log.SystemOutLogger;
import jp.sourceforge.mergedoc.pleiades.resource.Files;
import jp.sourceforge.mergedoc.pleiades.resource.PropertySet;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;

/**
 * 言語パックから日本語訳を抽出し Pleiades 形式の
 * プロパティー・ファイルに出力するための抽象クラスです。
 * <p>
 * @author cypher256
 */
abstract public class AbstractExtractor {

	/** ロガー */
	protected static final Logger log = Logger.getLogger("Extractor", SystemOutLogger.class, Level.INFO);

	/** 言語パックとそのプラグイン本体が格納されたフォルダー */
	protected static File inNlsFolder = Files.getFile("../../Pleiades.nls/90.current");

	/** 一時フォルダー・ルート (SVN 管理外) */
	protected final String tempRoot = "props/temp";

	/** 抽出フォルダー (SVN 管理外) */
	protected File extractTempFolder;

	/** 出力プロパティー・パス */
	protected String extractPropPath;

	/** 処理エントリー数 */
	protected int count;

	/** NLS 取得元プラグイン確認デバッグ・ログ出力用の英語リソース文字列 */
	protected String debugEnValue;

	/** NLS マージ時に日本語プロパティーが無いエントリーを格納するプロパティー */
	protected final PropertySet missingProp = new PropertySet();

	/**
	 * 抽出を実行します。
	 * <p>
	 * @param outFolderName 出力フォルダー名
	 * @param args NLS 取得元プラグイン確認デバッグ・ログ出力用の英語リソース文字列
	 * @throws IOException 入出力例外が発生した場合
	 */
	protected void run(String outFolderName, String... args) throws IOException {

		// 引数処理
		if (args.length != 0 && StringUtils.isNotBlank(args[0])) {
			debugEnValue = args[0];
			log.info("引数に指定された [" + debugEnValue +
					"] の NLS 取得元プラグインを確認します。プロパティーは出力されません。");
		}
		if (!inNlsFolder.exists()) {
			String msg = "言語パックとそのプラグイン本外が格納された " +
				inNlsFolder + " が存在しないため実行できません。";
			log.error(msg);
			throw new IllegalStateException(msg);
		}
		extractTempFolder = Files.getFile(tempRoot + "/" + outFolderName);

		// 抽出
		doExtract();

		// 出力するプロパティー・パス
		extractPropPath = tempRoot + "/nls-" + outFolderName + ".properties";
		String missingPropPath = tempRoot + "/nls-" + outFolderName + "-missing.properties";

		// 抽出したプロパティーをロードし、翻訳ルールを適用
		extractTempFolder.mkdirs();
		PropertySet extracteProp = new PropertySet(extractTempFolder);

		// デバッグ文字列が設定されていない場合は出力
		if (StringUtils.isBlank(debugEnValue)) {

			// 1 つのプロパティー・ファイルとして保管
			Generator.storeHistory(extracteProp, extractPropPath,
				"eclipse.org 言語パック " + outFolderName + " 抽出プロパティー\n\n" +
				"  プラグイン別の言語パック辞書をマージしたものです。\n" +
				"  入力元ファイル：props/temp/" + outFolderName + "/*.properties");

			// 訳が見つからなかったプロパティーを保管
			Generator.storeHistory(missingProp, missingPropPath,
				"eclipse.org 言語パック抽出未翻訳プロパティー\n\n" +
				"  言語パック抽出時に訳が見つからなかった項目のプロパティーです。\n" +
				"  入力元ファイル：nls/*/*/*");
		}

		log.info(extractPropPath + " " + extracteProp.size() + " (" + count + ")");
		log.info(missingPropPath + " " + missingProp.size());

		// 後処理
		afterExtract(extracteProp);
	}

	/**
	 * 言語パックから翻訳リソースをプロパティーとして抽出します。
	 * @throws IOException 入出力例外が発生した場合
	 */
	protected void doExtract() throws IOException {

		// 一時フォルダー削除 (SVN 管理外なので .svn は考慮不要)
		if (StringUtils.isBlank(debugEnValue)) {
			FileUtils.deleteDirectory(extractTempFolder);
			extractTempFolder.mkdirs();
		}

		// 言語パックからプロパティーを抽出し、出力先フォルダーに出力
		extract(inNlsFolder);
	}

	/**
	 * 抽出後処理を行います。
	 * <p>
	 * @param extractProp 抽出プロパティー
	 * @throws IOException 入出力例外が発生した場合
	 */
	protected void afterExtract(PropertySet extractProp) throws IOException {
	}

	/**
	 * 指定されたフォルダーに存在する言語パックを再帰的にロードし、
	 * プロパティーを生成します。
	 * <p>
	 * @param nlsFolder NLS フォルダー
	 * @throws IOException 入出力例外が発生した場合
	 */
	protected void extract(File nlsFolder) throws IOException {

		File[] dirs = nlsFolder.listFiles(Files.createDirectoryFilter());
		Arrays.sort(dirs); // 昇順

		for (File dir : dirs) {

			String name = dir.getName();
			if (name.equals("plugins") || name.equals("features")) {
				extractPlugins(dir);
			} else {
				extract(dir); // 再帰
			}
		}
	}

	/**
	 * 指定されたプラグイン・フォルダーに存在する言語パックをロードし、
	 * プロパティーを生成します。
	 * <p>
	 * @param pluginsFolder プラグイン・フォルダー
	 * @throws IOException 入出力例外が発生した場合
	 */
	abstract protected void extractPlugins(File pluginsFolder) throws IOException;
}
