/*
 * blanco Framework
 * Copyright (C) 2004-2007 IGA Tosiki
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.log.logging;

import java.util.logging.LogRecord;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import blanco.log.BlancoLogConstants;

/**
 * java.util.logging の出力を Apache log4j にリダイレクトするためのハンドラクラスの内部実装。
 * 
 * @author IGA Tosiki
 */
class BlancoLogLog4jHandlerInternal {
    /**
     * 初期化を実施します。
     * 
     * 実際には、ここで Apache log4j 存在確認のためにルートロガーを取得します。
     */
    public void init() {
        // Apache log4j 存在確認のためにルートロガーを取得します。
        final Logger logger = Logger.getRootLogger();

        logger.trace("BlancoLogLog4jHandler(" + BlancoLogConstants.VERSION
                + "): start redirecting: java.util.logging -> Apache log4j");
    }

    /**
     * 与えられたログレコードをロギングします。
     * 
     * @param argLogRecord
     *            ログレコード。
     */
    public void publish(final LogRecord argLogRecord) {
        String message = argLogRecord.getMessage();
        Level level = null;

        switch (argLogRecord.getLevel().intValue()) {
        case BlancoLogLoggingConstants.FINEST:
        case BlancoLogLoggingConstants.FINER:
            // マップ先が無いので FINEST と FINER のいずれも trace にマップ。
            level = Level.TRACE;
            break;
        case BlancoLogLoggingConstants.FINE:
            // FINE は debug にマップ。
            level = Level.DEBUG;
            break;
        case BlancoLogLoggingConstants.CONFIG:
            // マップ先が無いので CONFIG は infoにマップ。
            level = Level.DEBUG;
            message = "config: " + message;
            break;
        case BlancoLogLoggingConstants.INFO:
            level = Level.INFO;
            break;
        case BlancoLogLoggingConstants.WARNING:
            level = Level.WARN;
            break;
        case BlancoLogLoggingConstants.SEVERE:
            level = Level.ERROR;
            if (argLogRecord.getMessage().length() >= 5) {
                final String head = argLogRecord.getMessage().substring(0, 5);
                if ("fatal".equals(head.toLowerCase())) {
                    // メッセージが fatal または FATAL で開始される場合にのみ fatal にマッピング。
                    level = Level.FATAL;
                }
            }
            break;
        default:
            // しょうがないのでinfoにマップ。
            level = Level.INFO;
            message = "[" + argLogRecord.getLevel().intValue() + "]"
                    + argLogRecord.getMessage();
            break;
        }

        // このメソッド内でロガーを取得するのは、argLogRecord.getLoggerName()
        // が与えることができるのがこのタイミングだからです。
        // この処理をコンストラクタで実施することは出来ません。
        // フィールド変数として Loggerを保持することもできません。
        final Logger log4jLogger = Logger.getLogger(argLogRecord
                .getLoggerName());

        if (argLogRecord.getThrown() == null) {
            log4jLogger.log(level, message);
        } else {
            log4jLogger.log(level, message, argLogRecord.getThrown());
        }
    }

    /**
     * ロガーをフラッシュします。
     */
    public void flush() {
        // 特に何もしません。
    }

    /**
     * ロガーをクローズします。
     * 
     * @throws SecurityException
     *             セキュリティ例外が発生した場合。
     */
    public void close() throws SecurityException {
        // 特に何もしません。
    }
}
