package com.yammer.dropwizard.config;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.jul.LevelChangePropagator;
import ch.qos.logback.classic.spi.LoggerContextListener;
import com.google.common.base.Optional;
import com.yammer.dropwizard.logging.AsyncAppender;
import com.yammer.dropwizard.logging.LogbackFactory;
import com.yammer.dropwizard.logging.LoggingBean;
import com.yammer.metrics.logback.InstrumentedAppender;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.util.Map;
import java.util.TimeZone;

import static com.yammer.dropwizard.config.LoggingConfiguration.*;

// TODO: 11/7/11 <coda> -- document LoggingFactory
// TODO: 11/7/11 <coda> -- test LoggingFactory

public class LoggingFactory {
    public static void bootstrap() {
        // initially configure for WARN+ console logging
        final ConsoleConfiguration console = new ConsoleConfiguration();
        console.setEnabled(true);
        console.setTimeZone(TimeZone.getDefault());
        console.setThreshold(Level.WARN);

        final Logger root = getCleanRoot();
        root.addAppender(LogbackFactory.buildConsoleAppender(console,
                                                             root.getLoggerContext(),
                                                             Optional.<String>absent()));
    }

    private final LoggingConfiguration config;
    private final String name;

    public LoggingFactory(LoggingConfiguration config, String name) {
        this.config = config;
        this.name = name;
    }

    public void configure() {
        hijackJDKLogging();

        final Logger root = configureLevels();

        final ConsoleConfiguration console = config.getConsoleConfiguration();
        if (console.isEnabled()) {
            root.addAppender(AsyncAppender.wrap(LogbackFactory.buildConsoleAppender(console,
                                                                                    root.getLoggerContext(),
                                                                                    console.getLogFormat())));
        }

        final FileConfiguration file = config.getFileConfiguration();
        if (file.isEnabled()) {
            root.addAppender(AsyncAppender.wrap(LogbackFactory.buildFileAppender(file,
                                                                                 root.getLoggerContext(),
                                                                                 file.getLogFormat())));
        }

        final SyslogConfiguration syslog = config.getSyslogConfiguration();
        if (syslog.isEnabled()) {
            root.addAppender(AsyncAppender.wrap(LogbackFactory.buildSyslogAppender(syslog,
                                                                                   root.getLoggerContext(),
                                                                                   name,
                                                                                   syslog.getLogFormat())));
        }

        final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        try {
            ObjectName name = new ObjectName("com.yammer:type=Logging");
            if (!server.isRegistered(name)) {
                server.registerMBean(new LoggingBean(), name);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        configureInstrumentation(root);
    }

    private void configureInstrumentation(Logger root) {
        final InstrumentedAppender appender = new InstrumentedAppender();
        appender.setContext(root.getLoggerContext());
        appender.start();
        root.addAppender(appender);
    }

    private void hijackJDKLogging() {
        final java.util.logging.Logger root = java.util.logging.Logger.getLogger("");
        for (java.util.logging.Handler handler : root.getHandlers()) {
            root.removeHandler(handler);
        }
        root.addHandler(new SLF4JBridgeHandler());
    }

    private Logger configureLevels() {
        final Logger root = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
        root.getLoggerContext().reset();

        final LevelChangePropagator levelChangePropagator = new LevelChangePropagator();
        levelChangePropagator.setResetJUL(true);

        root.getLoggerContext().addListener(levelChangePropagator);

        root.setLevel(config.getLevel());

        for (Map.Entry<String, Level> entry : config.getLoggers().entrySet()) {
            ((Logger) LoggerFactory.getLogger(entry.getKey())).setLevel(entry.getValue());
        }

        return root;
    }

    private static Logger getCleanRoot() {
        final Logger root = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
        root.detachAndStopAllAppenders();
        return root;
    }
}

@@ -141,134 +141,32 @@
 sic.
-LoggerContext;%0Aimport ch.qos.logback.classic.jul.LevelChangePropagator;%0Aimport ch.qos.logback.classic.spi.LoggerContextListene
+jul.LevelChangePropagato
 r;%0Ai
@@ -3243,16 +3243,22 @@
         
+final 
 ObjectNa
@@ -3260,17 +3260,23 @@
 ectName 
-n
+objectN
 ame = ne
@@ -3353,17 +3353,23 @@
 istered(
-n
+objectN
 ame)) %7B%0A
@@ -3424,17 +3424,23 @@
 Bean(), 
-n
+objectN
 ame);%0A  
@@ -4356,28 +4356,17 @@
 pagator 
-levelChangeP
+p
 ropagato
@@ -4406,28 +4406,73 @@
         
-levelChangeP
+propagator.setContext(root.getLoggerContext());%0A        p
 ropagato
@@ -4541,20 +4541,9 @@
 ner(
-levelChangeP
+p
 ropa

Set the context for the j.u.l. propagator.