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

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.Order;
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.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.util.FileUtils;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.PropertiesUtil;

public abstract class ConfigurationFactory {
    public static final String CONFIGURATION_FACTORY_PROPERTY = "log4j.configurationFactory";
    public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile";
    protected static final Logger LOGGER = StatusLogger.getLogger();
    protected static final String TEST_PREFIX = "log4j2-test";
    protected static final String DEFAULT_PREFIX = "log4j2";
    private static final String CLASS_LOADER_SCHEME = "classloader";
    private static final String CLASS_PATH_SCHEME = "classpath";
    private static volatile List<ConfigurationFactory> factories = null;
    private static ConfigurationFactory configFactory = new Factory();
    protected final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator());
    private static final Lock LOCK = new ReentrantLock();

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public static ConfigurationFactory getInstance() {
        if (factories == null) {
            LOCK.lock();
            try {
                if (factories == null) {
                    ArrayList<ConfigurationFactory> list = new ArrayList<ConfigurationFactory>();
                    String factoryClass = PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FACTORY_PROPERTY);
                    if (factoryClass != null) {
                        ConfigurationFactory.addFactory(list, factoryClass);
                    }
                    PluginManager manager = new PluginManager("ConfigurationFactory");
                    manager.collectPlugins();
                    Map<String, PluginType<?>> plugins = manager.getPlugins();
                    TreeSet<WeightedFactory> ordered = new TreeSet<WeightedFactory>();
                    for (PluginType<?> type : plugins.values()) {
                        try {
                            Class<ConfigurationFactory> clazz = type.getPluginClass();
                            Order order = clazz.getAnnotation(Order.class);
                            if (order == null) continue;
                            int weight = order.value();
                            ordered.add(new WeightedFactory(weight, clazz));
                        }
                        catch (Exception ex) {
                            LOGGER.warn("Unable to add class {}", type.getPluginClass(), ex);
                        }
                    }
                    for (WeightedFactory wf : ordered) {
                        ConfigurationFactory.addFactory(list, wf.factoryClass);
                    }
                    factories = Collections.unmodifiableList(list);
                }
            }
            finally {
                LOCK.unlock();
            }
        }
        LOGGER.debug("Using configurationFactory {}", configFactory);
        return configFactory;
    }

    private static void addFactory(Collection<ConfigurationFactory> list, String factoryClass) {
        try {
            ConfigurationFactory.addFactory(list, Loader.loadClass(factoryClass));
        }
        catch (Exception ex) {
            LOGGER.error("Unable to load class {}", factoryClass, ex);
        }
    }

    private static void addFactory(Collection<ConfigurationFactory> list, Class<ConfigurationFactory> factoryClass) {
        try {
            list.add(factoryClass.getConstructor(new Class[0]).newInstance(new Object[0]));
        }
        catch (Exception ex) {
            LOGGER.error("Unable to create instance of {}", factoryClass.getName(), ex);
        }
    }

    public static void setConfigurationFactory(ConfigurationFactory factory) {
        configFactory = factory;
    }

    public static void resetConfigurationFactory() {
        configFactory = new Factory();
    }

    public static void removeConfigurationFactory(ConfigurationFactory factory) {
        if (configFactory == factory) {
            configFactory = new Factory();
        }
    }

    protected abstract String[] getSupportedTypes();

    protected boolean isActive() {
        return true;
    }

    public abstract Configuration getConfiguration(ConfigurationSource var1);

    public Configuration getConfiguration(String name, URI configLocation) {
        ConfigurationSource source;
        if (!this.isActive()) {
            return null;
        }
        if (configLocation != null && (source = this.getInputFromUri(configLocation)) != null) {
            return this.getConfiguration(source);
        }
        return null;
    }

    protected ConfigurationSource getInputFromUri(URI configLocation) {
        ClassLoader loader;
        String path;
        ConfigurationSource source;
        boolean isClassPathScheme;
        String scheme;
        File configFile = FileUtils.fileFromUri(configLocation);
        if (configFile != null && configFile.exists() && configFile.canRead()) {
            try {
                return new ConfigurationSource((InputStream)new FileInputStream(configFile), configFile);
            }
            catch (FileNotFoundException ex) {
                LOGGER.error("Cannot locate file {}", configLocation.getPath(), ex);
            }
        }
        boolean isClassLoaderScheme = (scheme = configLocation.getScheme()) != null && scheme.equals(CLASS_LOADER_SCHEME);
        boolean bl = isClassPathScheme = scheme != null && !isClassLoaderScheme && scheme.equals(CLASS_PATH_SCHEME);
        if ((scheme == null || isClassLoaderScheme || isClassPathScheme) && (source = this.getInputFromResource(path = isClassLoaderScheme || isClassPathScheme ? configLocation.getSchemeSpecificPart() : configLocation.getPath(), loader = Loader.getThreadContextClassLoader())) != null) {
            return source;
        }
        if (!configLocation.isAbsolute()) {
            LOGGER.error("File not found in file system or classpath: {}", configLocation.toString());
            return null;
        }
        try {
            return new ConfigurationSource(configLocation.toURL().openStream(), configLocation.toURL());
        }
        catch (MalformedURLException ex) {
            LOGGER.error("Invalid URL {}", configLocation.toString(), ex);
        }
        catch (Exception ex) {
            LOGGER.error("Unable to access {}", configLocation.toString(), ex);
        }
        return null;
    }

    protected ConfigurationSource getInputFromString(String config, ClassLoader loader) {
        try {
            URL url = new URL(config);
            return new ConfigurationSource(url.openStream(), FileUtils.fileFromUri(url.toURI()));
        }
        catch (Exception ex) {
            ConfigurationSource source = this.getInputFromResource(config, loader);
            if (source == null) {
                try {
                    File file = new File(config);
                    return new ConfigurationSource((InputStream)new FileInputStream(file), file);
                }
                catch (FileNotFoundException fnfe) {
                    LOGGER.catching(Level.DEBUG, fnfe);
                }
            }
            return source;
        }
    }

    protected ConfigurationSource getInputFromResource(String resource, ClassLoader loader) {
        URL url = Loader.getResource(resource, loader);
        if (url == null) {
            return null;
        }
        InputStream is = null;
        try {
            is = url.openStream();
        }
        catch (IOException ioe) {
            LOGGER.catching(Level.DEBUG, ioe);
            return null;
        }
        if (is == null) {
            return null;
        }
        if (FileUtils.isFile(url)) {
            try {
                return new ConfigurationSource(is, FileUtils.fileFromUri(url.toURI()));
            }
            catch (URISyntaxException ex) {
                LOGGER.catching(Level.DEBUG, ex);
            }
        }
        return new ConfigurationSource(is, url);
    }

    private static class Factory
    extends ConfigurationFactory {
        private Factory() {
        }

        @Override
        public Configuration getConfiguration(String name, URI configLocation) {
            Object config;
            if (configLocation == null) {
                config = this.substitutor.replace(PropertiesUtil.getProperties().getStringProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY));
                if (config != null) {
                    ConfigurationSource source = null;
                    try {
                        source = this.getInputFromUri(FileUtils.getCorrectedFilePathUri((String)config));
                    }
                    catch (Exception ex) {
                        LOGGER.catching(Level.DEBUG, ex);
                    }
                    if (source == null) {
                        ClassLoader loader = this.getClass().getClassLoader();
                        source = this.getInputFromString((String)config, loader);
                    }
                    if (source != null) {
                        for (ConfigurationFactory factory : factories) {
                            String[] types = factory.getSupportedTypes();
                            if (types == null) continue;
                            for (String type : types) {
                                Configuration c;
                                if (!type.equals("*") && !((String)config).endsWith(type) || (c = factory.getConfiguration(source)) == null) continue;
                                return c;
                            }
                        }
                    }
                }
            } else {
                for (ConfigurationFactory factory : factories) {
                    String[] types = factory.getSupportedTypes();
                    if (types == null) continue;
                    for (String type : types) {
                        Configuration config2;
                        if (!type.equals("*") && !configLocation.toString().endsWith(type) || (config2 = factory.getConfiguration(name, configLocation)) == null) continue;
                        return config2;
                    }
                }
            }
            if ((config = this.getConfiguration(true, name)) == null && (config = this.getConfiguration(true, null)) == null && (config = this.getConfiguration(false, name)) == null) {
                config = this.getConfiguration(false, null);
            }
            return config != null ? config : new DefaultConfiguration();
        }

        private Configuration getConfiguration(boolean isTest, String name) {
            boolean named = name != null && name.length() > 0;
            ClassLoader loader = this.getClass().getClassLoader();
            for (ConfigurationFactory factory : factories) {
                String prefix = isTest ? ConfigurationFactory.TEST_PREFIX : ConfigurationFactory.DEFAULT_PREFIX;
                String[] types = factory.getSupportedTypes();
                if (types == null) continue;
                for (String suffix : types) {
                    String configName;
                    ConfigurationSource source;
                    if (suffix.equals("*") || (source = this.getInputFromResource(configName = named ? prefix + name + suffix : prefix + suffix, loader)) == null) continue;
                    return factory.getConfiguration(source);
                }
            }
            return null;
        }

        @Override
        public String[] getSupportedTypes() {
            return null;
        }

        @Override
        public Configuration getConfiguration(ConfigurationSource source) {
            if (source != null) {
                String config = source.getLocation();
                for (ConfigurationFactory factory : factories) {
                    String[] types = factory.getSupportedTypes();
                    if (types == null) continue;
                    for (String type : types) {
                        if (!type.equals("*") && (config == null || !config.endsWith(type))) continue;
                        Configuration c = factory.getConfiguration(source);
                        if (c != null) {
                            LOGGER.debug("Loaded configuration from {}", source);
                            return c;
                        }
                        LOGGER.error("Cannot determine the ConfigurationFactory to use for {}", config);
                        return null;
                    }
                }
            }
            LOGGER.error("Cannot process configuration, input source is null");
            return null;
        }
    }

    private static class WeightedFactory
    implements Comparable<WeightedFactory> {
        private final int weight;
        private final Class<ConfigurationFactory> factoryClass;

        public WeightedFactory(int weight, Class<ConfigurationFactory> clazz) {
            this.weight = weight;
            this.factoryClass = clazz;
        }

        @Override
        public int compareTo(WeightedFactory wf) {
            int w = wf.weight;
            if (this.weight == w) {
                return 0;
            }
            if (this.weight > w) {
                return -1;
            }
            return 1;
        }
    }
}
