/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package textkeymatcher.util.log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import org.jdesktop.application.Application;
import org.jdesktop.application.ApplicationContext;

/**
 *
 * @author seraphy
 */
public class ApplicationLoggerConfigurator {

    private static final String LOGGING_PROPERTIES = "logging.properties";
    
    private ApplicationLoggerConfigurator() {
        super();
    }

    public static void configure() {
        // ログマネージャ.
        // 初期時にJRE等にある初期設定がなされている.
        LogManager logManager = LogManager.getLogManager();

        // 設定を一旦クリアする.
        // ルートロガーがInfoになり、ハンドラはすべてリセット。ルートロガー以外の設定は空にされる.
        logManager.reset();

        // ユーザーごとのアプリケーション設定ディレクトリ上の設定ファイルを取得する.
        Application application = Application.getInstance();
        ApplicationContext context = application.getContext();
        File appDataDir = context.getLocalStorage().getDirectory();

        // ロギングプロパティをロードする
        // (なければリソースからコピーして使用する.)
        ArrayList<Throwable> configurationErrors = new ArrayList<Throwable>();
        try {
            File logConfig = new File(appDataDir, LOGGING_PROPERTIES);
            if ( !logConfig.exists()) {
                try {
                    // ユーザ指定のロギングプロパティがない場合、リソースからコピーする
                    copyDefaultLogProperty(logConfig);

                } catch (Throwable ex) {
                    // 初期化に失敗した場合はログに記録するために例外を保存するが、
                    // 処理は継続する.
                    configurationErrors.add(ex);
                }
            }

            InputStream is = null;
            if (logConfig.exists()) {
                try {
                    // ユーザー指定のロギングプロパティがある場合
                    is = new FileInputStream(logConfig);

                } catch (Throwable ex) {
                    // 初期化に失敗した場合はログに記録するために例外を保存するが、
                    // 処理は継続する.
                    configurationErrors.add(ex);
                }
            }
            if (is == null) {
                // リソース上のロギングプロパティ
                is = ApplicationLoggerConfigurator.class.getResourceAsStream("/" + LOGGING_PROPERTIES);
            }
            try {
                // ログを再設定する.
                logManager.readConfiguration(is);

            } finally {
                is.close();
            }

        } catch (Throwable ex) {
            // 初期化に失敗した場合はログに記録するために例外を保存するが、
            // 処理は継続する.
            configurationErrors.add(ex);
        }

        // ロガーを取得
        Logger logger = Logger.getLogger(ApplicationLoggerConfigurator.class.getName());

        // 初期化時に失敗した場合、デフォルトのコンソールハンドラを設定し、ログに出力する.
        if ( !configurationErrors.isEmpty()) {
            // ロガーの初期化に失敗している場合はコンソールとファイルの双方を有効にする.
            // (設定ファイルが読み込めてないのでロガーがなにもないことになるため)
            logger.addHandler(new ConsoleHandler());
            logger.addHandler(new ApplicationLogHandler());
            for (Throwable ex : configurationErrors) {
                logger.log(Level.WARNING, "LogConfigurationFailed", ex);
            }
        }

        // 初期化時のログ
        logger.log(Level.INFO, "open logger.");
        logger.log(Level.INFO, "application configuration: localStorage={0}", appDataDir);
        
        // ログのパージ
        try {
            ApplicationLogHandler.purgeLogs();
            
        } catch (Exception ex) {
            logger.log(Level.WARNING, "purge logs failed.", ex);
        }
    }
    
    /**
     * デフォルトのログプロパティをユーザディレクトリにコピーする.
     * @param logConfig ユーザディレクトリ上のログプロパティファイル位置
     */
    protected static void copyDefaultLogProperty(File logConfig) throws IOException {
        InputStream is = ApplicationLoggerConfigurator.class.getResourceAsStream("/" + LOGGING_PROPERTIES);
        if (is == null) {
            return;
        }
        try {
            // ディレクトリの準備
            File parent = logConfig.getParentFile();
            if ( !parent.exists()) {
                parent.mkdirs();
            }

            // リソースからファイルへのコピー
            FileOutputStream fos = new FileOutputStream(logConfig);
            try {
                byte buf[] = new byte[4096];
                for (;;) {
                    int rd = is.read(buf);
                    if (rd <= 0) {
                        break;
                    }
                    fos.write(buf, 0, rd);
                }
            } finally {
                fos.close();
            }
        } finally {
            is.close();
        }
    }

}
