package com.taobao.arthas.core.util;

import java.io.File;
import java.util.Iterator;

import com.alibaba.arthas.deps.ch.qos.logback.classic.LoggerContext;
import com.alibaba.arthas.deps.ch.qos.logback.classic.joran.JoranConfigurator;
import com.alibaba.arthas.deps.ch.qos.logback.classic.spi.ILoggingEvent;
import com.alibaba.arthas.deps.ch.qos.logback.core.Appender;
import com.alibaba.arthas.deps.ch.qos.logback.core.rolling.RollingFileAppender;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.common.AnsiLog;
import com.taobao.arthas.core.env.ArthasEnvironment;

/**
 * 
 * @author hengyunabc
 *
 */
public class LogUtil {

    public static final String LOGGING_CONFIG_PROPERTY = "arthas.logging.config";
    public static final String LOGGING_CONFIG = "${arthas.logging.config:${arthas.home}/logback.xml}";

    /**
     * The name of the property that contains the name of the log file. Names can be
     * an exact location or relative to the current directory.
     */
    public static final String FILE_NAME_PROPERTY = "arthas.logging.file.name";
    public static final String ARTHAS_LOG_FILE = "ARTHAS_LOG_FILE";

    /**
     * The name of the property that contains the directory where log files are
     * written.
     */
    public static final String FILE_PATH_PROPERTY = "arthas.logging.file.path";
    public static final String ARTHAS_LOG_PATH = "ARTHAS_LOG_PATH";

    private static String logFile = "";

    /**
     * <pre>
     * 1. 尝试从 arthas.logging.config 这个配置里加载 logback.xml
     * 2. 尝试从 arthas.home 下面找 logback.xml
     * 
     * 可以用 arthas.logging.file.name 指定具体arthas.log的名字
     * 可以用 arthas.logging.file.path 指定具体arthas.log的目录
     * 
     * </pre>
     * 
     * @param env
     */
    public static LoggerContext initLogger(ArthasEnvironment env) {
        String loggingConfig = env.resolvePlaceholders(LOGGING_CONFIG);
        if (loggingConfig == null || loggingConfig.trim().isEmpty()) {
            return null;
        }
        AnsiLog.debug("arthas logging file: " + loggingConfig);
        File configFile = new File(loggingConfig);
        if (!configFile.isFile()) {
            AnsiLog.error("can not find arthas logging config: " + loggingConfig);
            return null;
        }

        try {
            LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
            loggerContext.reset();

            String fileName = env.getProperty(FILE_NAME_PROPERTY);
            if (fileName != null) {
                loggerContext.putProperty(ARTHAS_LOG_FILE, fileName);
            }
            String filePath = env.getProperty(FILE_PATH_PROPERTY);
            if (filePath != null) {
                loggerContext.putProperty(ARTHAS_LOG_PATH, filePath);
            }

            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(loggerContext);
            configurator.doConfigure(configFile.toURI().toURL()); // load logback xml file

            // 查找 arthas.log appender
            Iterator<Appender<ILoggingEvent>> appenders = loggerContext.getLogger("root").iteratorForAppenders();

            while (appenders.hasNext()) {
                Appender<ILoggingEvent> appender = appenders.next();
                if (appender instanceof RollingFileAppender) {
                    RollingFileAppender fileAppender = (RollingFileAppender) appender;
                    if ("ARTHAS".equalsIgnoreCase(fileAppender.getName())) {
                        logFile = new File(fileAppender.getFile()).getCanonicalPath();
                    }
                }
            }

            return loggerContext;
        } catch (Throwable e) {
            AnsiLog.error("try to load arthas logging config file error: " + configFile, e);
        }
        return null;
    }

    public static String loggingFile() {
        if (logFile == null || logFile.trim().isEmpty()) {
            return "arthas.log";
        }
        return logFile;
    }

    public static String loggingDir() {
        if (logFile != null && !logFile.isEmpty()) {
            String parent = new File(logFile).getParent();
            if (parent != null) {
                return parent;
            }
        }
        return new File("").getAbsolutePath();
    }

    public static String cacheDir() {
        File logsDir = new File(loggingDir()).getParentFile();
        if (logsDir.exists()) {
            File arthasCacheDir = new File(logsDir, "arthas-cache");
            arthasCacheDir.mkdirs();
            return arthasCacheDir.getAbsolutePath();
        } else {
            File arthasCacheDir = new File("arthas-cache");
            arthasCacheDir.mkdirs();
            return arthasCacheDir.getAbsolutePath();
        }
    }

    public static Logger getResultLogger() {
        return LoggerFactory.getLogger("result");
    }
}
