package com.atlassian.stash.internal.logback;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.selector.ContextSelector;
import ch.qos.logback.classic.util.ContextSelectorStaticBinder;
import ch.qos.logback.core.joran.spi.JoranException;
import org.springframework.util.ResourceUtils;
import org.springframework.util.SystemPropertyUtils;

import java.io.FileNotFoundException;
import java.net.URL;

/**
 * Convenience class that features simple methods for custom Logback configuration.
 * <p>
 * Only needed for non-default Logback initialization with a custom config location. By default, Logback will simply
 * read its configuration from a "logback.xml" or "logback-test.xml" file in the root of the class path.
 * <p>
 * For web environments, the analogous {@link com.atlassian.stash.internal.logback.web.LogbackWebConfigurer} can be found in
 * the web package, reading in its configuration from {@code context-params} in {@code web.xml}. In a web application,
 * Logback is usually set up via {@link com.atlassian.stash.internal.logback.web.LogbackConfigListener}, delegating to
 * {@code LogbackWebConfigurer} underneath.
 *
 * @see com.atlassian.stash.internal.logback.web.LogbackWebConfigurer
 * @see com.atlassian.stash.internal.logback.web.LogbackConfigListener
 */
public class LogbackConfigurer {

    private LogbackConfigurer() {
    }

    /**
     * Initialize Logback from the given file.
     *
     * @param location the location of the config file: either a "classpath:" location
     *                 (e.g. "classpath:logback.xml"), an absolute file URL
     *                 (e.g. "file:C:/logback.xml), or a plain absolute path in the file system
     *                 (e.g. "C:/logback.xml")
     * @throws FileNotFoundException Thrown if the location specifies an invalid file path
     * @throws JoranException Thrown if the location specifies an invalid configuration file
     */
    public static void initLogging(String location) throws FileNotFoundException, JoranException {
        String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
        URL url = ResourceUtils.getURL(resolvedLocation);
        ContextSelector selector = ContextSelectorStaticBinder.getSingleton().getContextSelector();
        LoggerContext loggerContext = selector.getLoggerContext();
        // in the current version Logback automatically configures the context at startup, so we have to reset it
        loggerContext.reset();
        JoranConfigurator configurator = new JoranConfigurator();
        configurator.setContext(loggerContext);
        configurator.doConfigure(url);
    }

    /**
     * Shut down Logback.
     * <p>
     * This isn't strictly necessary, but recommended for shutting down Logback in a scenario where the host VM stays
     * alive (for example, when shutting down an application in a J2EE environment).
     */
    public static void shutdownLogging() {
        ContextSelector selector = ContextSelectorStaticBinder.getSingleton().getContextSelector();
        LoggerContext loggerContext = selector.getLoggerContext();
        String loggerContextName = loggerContext.getName();
        LoggerContext context = selector.detachLoggerContext(loggerContextName);
        context.reset();
    }
}
