/*
 * Decompiled with CFR 0.152.
 */
package org.apache.logging.log4j.core.config;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.AsyncAppender;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.async.AsyncLoggerConfig;
import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationListener;
import org.apache.logging.log4j.core.config.ConfigurationMonitor;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.DefaultAdvertiser;
import org.apache.logging.log4j.core.config.DefaultConfigurationMonitor;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.Loggers;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.plugins.util.PluginBuilder;
import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
import org.apache.logging.log4j.core.filter.AbstractFilterable;
import org.apache.logging.log4j.core.impl.Log4jContextFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.MapLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.net.Advertiser;
import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.core.util.Assert;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.core.util.NameUtil;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.util.PropertiesUtil;

public abstract class AbstractConfiguration
extends AbstractFilterable
implements Configuration {
    private static final int BUF_SIZE = 16384;
    protected Node rootNode;
    protected final List<ConfigurationListener> listeners = new CopyOnWriteArrayList<ConfigurationListener>();
    protected ConfigurationMonitor monitor = new DefaultConfigurationMonitor();
    private Advertiser advertiser = new DefaultAdvertiser();
    private Node advertiserNode = null;
    private Object advertisement;
    protected boolean isShutdownHookEnabled = true;
    private String name;
    private ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<String, Appender>();
    private ConcurrentMap<String, LoggerConfig> loggers = new ConcurrentHashMap<String, LoggerConfig>();
    private final ConcurrentMap<String, String> properties = new ConcurrentHashMap<String, String>();
    private final StrLookup tempLookup = new Interpolator(this.properties);
    private final StrSubstitutor subst = new StrSubstitutor(this.tempLookup);
    private LoggerConfig root = new LoggerConfig();
    private final ConcurrentMap<String, Object> componentMap = new ConcurrentHashMap<String, Object>();
    protected PluginManager pluginManager;
    private final ConfigurationSource configurationSource;

    protected AbstractConfiguration(ConfigurationSource configurationSource) {
        this.configurationSource = Assert.requireNonNull(configurationSource, "configurationSource is null");
        this.componentMap.put("ContextProperties", this.properties);
        this.pluginManager = new PluginManager("Core");
        this.rootNode = new Node();
    }

    @Override
    public ConfigurationSource getConfigurationSource() {
        return this.configurationSource;
    }

    @Override
    public Map<String, String> getProperties() {
        return this.properties;
    }

    @Override
    public void start() {
        LOGGER.debug("Starting configuration {}", this);
        this.setStarting();
        this.pluginManager.collectPlugins();
        PluginManager levelPlugins = new PluginManager("Level");
        levelPlugins.collectPlugins();
        Map<String, PluginType<?>> plugins = levelPlugins.getPlugins();
        if (plugins != null) {
            for (PluginType<?> type : plugins.values()) {
                try {
                    Loader.initializeClass(type.getPluginClass().getName(), type.getPluginClass().getClassLoader());
                }
                catch (Exception e) {
                    LOGGER.error("Unable to initialize {} due to {}", type.getPluginClass().getName(), e.getClass().getSimpleName(), e);
                }
            }
        }
        this.setup();
        this.setupAdvertisement();
        this.doConfigure();
        HashSet<LoggerConfig> alreadyStarted = new HashSet<LoggerConfig>();
        for (LoggerConfig logger : this.loggers.values()) {
            logger.start();
            alreadyStarted.add(logger);
        }
        for (Appender appender : this.appenders.values()) {
            appender.start();
        }
        if (!alreadyStarted.contains(this.root)) {
            this.root.start();
        }
        super.start();
        LOGGER.debug("Started configuration {} OK.", this);
    }

    @Override
    public void stop() {
        ContextSelector selector;
        this.setStopping();
        LOGGER.trace("Stopping {}...", this);
        LoggerContextFactory factory = LogManager.getFactory();
        if (!(factory instanceof Log4jContextFactory) || (selector = ((Log4jContextFactory)factory).getSelector()) instanceof AsyncLoggerContextSelector) {
            // empty if block
        }
        HashSet<LoggerConfig> alreadyStopped = new HashSet<LoggerConfig>();
        int asyncLoggerConfigCount = 0;
        for (LoggerConfig logger : this.loggers.values()) {
            if (!(logger instanceof AsyncLoggerConfig)) continue;
            logger.stop();
            ++asyncLoggerConfigCount;
            alreadyStopped.add(logger);
        }
        if (this.root instanceof AsyncLoggerConfig) {
            this.root.stop();
            ++asyncLoggerConfigCount;
            alreadyStopped.add(this.root);
        }
        LOGGER.trace("AbstractConfiguration stopped {} AsyncLoggerConfigs.", asyncLoggerConfigCount);
        Appender[] array = this.appenders.values().toArray(new Appender[this.appenders.size()]);
        int asyncAppenderCount = 0;
        for (int i = array.length - 1; i >= 0; --i) {
            if (!(array[i] instanceof AsyncAppender)) continue;
            array[i].stop();
            ++asyncAppenderCount;
        }
        LOGGER.trace("AbstractConfiguration stopped {} AsyncAppenders.", asyncAppenderCount);
        int appenderCount = 0;
        for (int i = array.length - 1; i >= 0; --i) {
            if (!array[i].isStarted()) continue;
            array[i].stop();
            ++appenderCount;
        }
        LOGGER.trace("AbstractConfiguration stopped {} Appenders.", appenderCount);
        int loggerCount = 0;
        for (LoggerConfig logger : this.loggers.values()) {
            logger.clearAppenders();
            if (alreadyStopped.contains(logger)) continue;
            logger.stop();
            ++loggerCount;
        }
        LOGGER.trace("AbstractConfiguration stopped {} Loggers.", loggerCount);
        if (!alreadyStopped.contains(this.root)) {
            this.root.stop();
        }
        super.stop();
        if (this.advertiser != null && this.advertisement != null) {
            this.advertiser.unadvertise(this.advertisement);
        }
        LOGGER.debug("Stopped {} OK", this);
    }

    @Override
    public boolean isShutdownHookEnabled() {
        return this.isShutdownHookEnabled;
    }

    protected void setup() {
    }

    protected Level getDefaultStatus() {
        String statusLevel = PropertiesUtil.getProperties().getStringProperty("Log4jDefaultStatusLevel", Level.ERROR.name());
        try {
            return Level.toLevel(statusLevel);
        }
        catch (Exception ex) {
            return Level.ERROR;
        }
    }

    protected void createAdvertiser(String advertiserString, ConfigurationSource configSource, byte[] buffer, String contentType) {
        if (advertiserString != null) {
            Node node = new Node(null, advertiserString, null);
            Map<String, String> attributes = node.getAttributes();
            attributes.put("content", new String(buffer));
            attributes.put("contentType", contentType);
            attributes.put("name", "configuration");
            if (configSource.getLocation() != null) {
                attributes.put("location", configSource.getLocation());
            }
            this.advertiserNode = node;
        }
    }

    private void setupAdvertisement() {
        String name;
        PluginType<?> type;
        if (this.advertiserNode != null && (type = this.pluginManager.getPluginType(name = this.advertiserNode.getName())) != null) {
            Class<?> clazz = type.getPluginClass();
            try {
                this.advertiser = (Advertiser)clazz.newInstance();
                this.advertisement = this.advertiser.advertise(this.advertiserNode.getAttributes());
            }
            catch (InstantiationException e) {
                LOGGER.error("InstantiationException attempting to instantiate advertiser: {}", name, e);
            }
            catch (IllegalAccessException e) {
                LOGGER.error("IllegalAccessException attempting to instantiate advertiser: {}", name, e);
            }
        }
    }

    @Override
    public <T> T getComponent(String name) {
        return (T)this.componentMap.get(name);
    }

    @Override
    public void addComponent(String name, Object obj) {
        this.componentMap.putIfAbsent(name, obj);
    }

    protected void doConfigure() {
        Object l;
        if (this.rootNode.hasChildren() && this.rootNode.getChildren().get(0).getName().equalsIgnoreCase("Properties")) {
            Node first = this.rootNode.getChildren().get(0);
            this.createConfiguration(first, null);
            if (first.getObject() != null) {
                this.subst.setVariableResolver((StrLookup)first.getObject());
            }
        } else {
            Map map = (Map)this.componentMap.get("ContextProperties");
            MapLookup lookup = map == null ? null : new MapLookup(map);
            this.subst.setVariableResolver(new Interpolator(lookup));
        }
        boolean setLoggers = false;
        boolean setRoot = false;
        for (Node node : this.rootNode.getChildren()) {
            if (node.getName().equalsIgnoreCase("Properties")) {
                if (this.tempLookup != this.subst.getVariableResolver()) continue;
                LOGGER.error("Properties declaration must be the first element in the configuration");
                continue;
            }
            this.createConfiguration(node, null);
            if (node.getObject() == null) continue;
            if (node.getName().equalsIgnoreCase("Appenders")) {
                this.appenders = (ConcurrentMap)node.getObject();
                continue;
            }
            if (node.getObject() instanceof Filter) {
                this.addFilter((Filter)node.getObject());
                continue;
            }
            if (node.getName().equalsIgnoreCase("Loggers")) {
                l = (Loggers)node.getObject();
                this.loggers = ((Loggers)l).getMap();
                setLoggers = true;
                if (((Loggers)l).getRoot() == null) continue;
                this.root = ((Loggers)l).getRoot();
                setRoot = true;
                continue;
            }
            LOGGER.error("Unknown object \"{}\" of type {} is ignored.", node.getName(), node.getObject().getClass().getName());
        }
        if (!setLoggers) {
            LOGGER.warn("No Loggers were configured, using default. Is the Loggers element missing?");
            this.setToDefault();
            return;
        }
        if (!setRoot) {
            LOGGER.warn("No Root logger was configured, creating default ERROR-level Root logger with Console appender");
            this.setToDefault();
        }
        for (Map.Entry entry : this.loggers.entrySet()) {
            l = (LoggerConfig)entry.getValue();
            for (AppenderRef ref : ((LoggerConfig)l).getAppenderRefs()) {
                Appender app = (Appender)this.appenders.get(ref.getRef());
                if (app != null) {
                    ((LoggerConfig)l).addAppender(app, ref.getLevel(), ref.getFilter());
                    continue;
                }
                LOGGER.error("Unable to locate appender {} for logger {}", ref.getRef(), ((LoggerConfig)l).getName());
            }
        }
        this.setParents();
    }

    private void setToDefault() {
        this.setName("Default");
        PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n").withConfiguration(this).build();
        ConsoleAppender appender = ConsoleAppender.createAppender(layout, null, "SYSTEM_OUT", "Console", "false", "true");
        appender.start();
        this.addAppender(appender);
        LoggerConfig root = this.getRootLogger();
        root.addAppender(appender, null, null);
        String levelName = PropertiesUtil.getProperties().getStringProperty("org.apache.logging.log4j.level");
        Level level = levelName != null && Level.getLevel(levelName) != null ? Level.getLevel(levelName) : Level.ERROR;
        root.setLevel(level);
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void addListener(ConfigurationListener listener) {
        this.listeners.add(listener);
    }

    @Override
    public void removeListener(ConfigurationListener listener) {
        this.listeners.remove(listener);
    }

    @Override
    public Appender getAppender(String name) {
        return (Appender)this.appenders.get(name);
    }

    @Override
    public Map<String, Appender> getAppenders() {
        return this.appenders;
    }

    @Override
    public void addAppender(Appender appender) {
        this.appenders.putIfAbsent(appender.getName(), appender);
    }

    @Override
    public StrSubstitutor getStrSubstitutor() {
        return this.subst;
    }

    @Override
    public void setConfigurationMonitor(ConfigurationMonitor monitor) {
        this.monitor = monitor;
    }

    @Override
    public ConfigurationMonitor getConfigurationMonitor() {
        return this.monitor;
    }

    @Override
    public void setAdvertiser(Advertiser advertiser) {
        this.advertiser = advertiser;
    }

    @Override
    public Advertiser getAdvertiser() {
        return this.advertiser;
    }

    @Override
    public synchronized void addLoggerAppender(Logger logger, Appender appender) {
        String name = logger.getName();
        this.appenders.putIfAbsent(appender.getName(), appender);
        LoggerConfig lc = this.getLoggerConfig(name);
        if (lc.getName().equals(name)) {
            lc.addAppender(appender, null, null);
        } else {
            LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), lc.isAdditive());
            nlc.addAppender(appender, null, null);
            nlc.setParent(lc);
            this.loggers.putIfAbsent(name, nlc);
            this.setParents();
            logger.getContext().updateLoggers();
        }
    }

    @Override
    public synchronized void addLoggerFilter(Logger logger, Filter filter) {
        String name = logger.getName();
        LoggerConfig lc = this.getLoggerConfig(name);
        if (lc.getName().equals(name)) {
            lc.addFilter(filter);
        } else {
            LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), lc.isAdditive());
            nlc.addFilter(filter);
            nlc.setParent(lc);
            this.loggers.putIfAbsent(name, nlc);
            this.setParents();
            logger.getContext().updateLoggers();
        }
    }

    @Override
    public synchronized void setLoggerAdditive(Logger logger, boolean additive) {
        String name = logger.getName();
        LoggerConfig lc = this.getLoggerConfig(name);
        if (lc.getName().equals(name)) {
            lc.setAdditive(additive);
        } else {
            LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), additive);
            nlc.setParent(lc);
            this.loggers.putIfAbsent(name, nlc);
            this.setParents();
            logger.getContext().updateLoggers();
        }
    }

    public synchronized void removeAppender(String name) {
        for (LoggerConfig logger : this.loggers.values()) {
            logger.removeAppender(name);
        }
        Appender app = (Appender)this.appenders.remove(name);
        if (app != null) {
            app.stop();
        }
    }

    @Override
    public LoggerConfig getLoggerConfig(String name) {
        if (this.loggers.containsKey(name)) {
            return (LoggerConfig)this.loggers.get(name);
        }
        String substr = name;
        while ((substr = NameUtil.getSubName(substr)) != null) {
            if (!this.loggers.containsKey(substr)) continue;
            return (LoggerConfig)this.loggers.get(substr);
        }
        return this.root;
    }

    public LoggerConfig getRootLogger() {
        return this.root;
    }

    @Override
    public Map<String, LoggerConfig> getLoggers() {
        return Collections.unmodifiableMap(this.loggers);
    }

    public LoggerConfig getLogger(String name) {
        return (LoggerConfig)this.loggers.get(name);
    }

    @Override
    public synchronized void addLogger(String name, LoggerConfig loggerConfig) {
        this.loggers.putIfAbsent(name, loggerConfig);
        this.setParents();
    }

    @Override
    public synchronized void removeLogger(String name) {
        this.loggers.remove(name);
        this.setParents();
    }

    @Override
    public void createConfiguration(Node node, LogEvent event) {
        PluginType<?> type = node.getType();
        if (type != null && type.isDeferChildren()) {
            node.setObject(this.createPluginObject(type, node, event));
        } else {
            for (Node child : node.getChildren()) {
                this.createConfiguration(child, event);
            }
            if (type == null) {
                if (node.getParent() != null) {
                    LOGGER.error("Unable to locate plugin for {}", node.getName());
                }
            } else {
                node.setObject(this.createPluginObject(type, node, event));
            }
        }
    }

    private <T> Object createPluginObject(PluginType<T> type, Node node, LogEvent event) {
        Class<T> clazz = type.getPluginClass();
        if (Map.class.isAssignableFrom(clazz)) {
            try {
                return AbstractConfiguration.createPluginMap(node, clazz);
            }
            catch (Exception e) {
                LOGGER.warn("Unable to create Map for {} of class {}", type.getElementName(), clazz, e);
            }
        }
        if (Collection.class.isAssignableFrom(clazz)) {
            try {
                return AbstractConfiguration.createPluginCollection(node, clazz);
            }
            catch (Exception e) {
                LOGGER.warn("Unable to create List for {} of class {}", type.getElementName(), clazz, e);
            }
        }
        return new PluginBuilder<T>(type).withConfiguration(this).withConfigurationNode(node).forLogEvent(event).build();
    }

    private static <T> Object createPluginMap(Node node, Class<T> clazz) throws InstantiationException, IllegalAccessException {
        Map map = (Map)clazz.newInstance();
        for (Node child : node.getChildren()) {
            map.put(child.getName(), child.getObject());
        }
        return map;
    }

    private static <T> Object createPluginCollection(Node node, Class<T> clazz) throws InstantiationException, IllegalAccessException {
        Collection list = (Collection)clazz.newInstance();
        for (Node child : node.getChildren()) {
            list.add(child.getObject());
        }
        return list;
    }

    private void setParents() {
        for (Map.Entry entry : this.loggers.entrySet()) {
            LoggerConfig logger = (LoggerConfig)entry.getValue();
            String name = (String)entry.getKey();
            if (name.isEmpty()) continue;
            int i = name.lastIndexOf(46);
            if (i > 0) {
                LoggerConfig parent = this.getLoggerConfig(name = name.substring(0, i));
                if (parent == null) {
                    parent = this.root;
                }
                logger.setParent(parent);
                continue;
            }
            logger.setParent(this.root);
        }
    }

    protected static byte[] toByteArray(InputStream is) throws IOException {
        int nRead;
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] data = new byte[16384];
        while ((nRead = is.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }
        return buffer.toByteArray();
    }
}
