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

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAliases;
import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
import org.apache.logging.log4j.core.util.ClassLoaderResourceLoader;
import org.apache.logging.log4j.core.util.Closer;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.core.util.ResourceLoader;
import org.apache.logging.log4j.status.StatusLogger;

public class PluginManager {
    private static final PluginRegistry<PluginType<?>> REGISTRY = new PluginRegistry();
    private static final CopyOnWriteArrayList<String> PACKAGES = new CopyOnWriteArrayList();
    private static final String LOG4J_PACKAGES = "org.apache.logging.log4j.core";
    private static final Logger LOGGER = StatusLogger.getLogger();
    private Map<String, PluginType<?>> plugins = new HashMap();
    private final String category;

    public PluginManager(String category) {
        this.category = category;
    }

    @Deprecated
    public static void main(String[] args) {
        System.err.println("WARNING: this tool is superseded by the annotation processor included in log4j-core.");
        System.exit(-1);
    }

    public static void addPackage(String p) {
        if (PACKAGES.addIfAbsent(p)) {
            REGISTRY.clear();
        }
    }

    public PluginType<?> getPluginType(String name) {
        return this.plugins.get(name.toLowerCase());
    }

    public Map<String, PluginType<?>> getPlugins() {
        return this.plugins;
    }

    public void collectPlugins() {
        this.collectPlugins(true);
    }

    public void collectPlugins(boolean preLoad) {
        if (REGISTRY.hasCategory(this.category)) {
            this.plugins = REGISTRY.getCategory(this.category);
            preLoad = false;
        }
        long start = System.nanoTime();
        if (preLoad) {
            ClassLoaderResourceLoader loader = new ClassLoaderResourceLoader(Loader.getClassLoader());
            PluginManager.loadPlugins(loader);
        }
        this.plugins = REGISTRY.getCategory(this.category);
        this.loadFromPackages(start, preLoad);
        long elapsed = System.nanoTime() - start;
        this.reportPluginLoadDuration(preLoad, elapsed);
    }

    private void loadFromPackages(long start, boolean preLoad) {
        if (!(this.plugins != null && this.plugins.size() != 0 || PACKAGES.contains(LOG4J_PACKAGES))) {
            PACKAGES.add(LOG4J_PACKAGES);
        }
        ResolverUtil resolver = new ResolverUtil();
        ClassLoader classLoader = Loader.getClassLoader();
        if (classLoader != null) {
            resolver.setClassLoader(classLoader);
        }
        Class<?> cls = null;
        PluginTest test = new PluginTest(cls);
        for (String string : PACKAGES) {
            resolver.findInPackage(test, string);
        }
        for (Class clazz : resolver.getClasses()) {
            Plugin plugin = clazz.getAnnotation(Plugin.class);
            String pluginCategory = plugin.category();
            ConcurrentMap<String, PluginType<?>> map = REGISTRY.getCategory(pluginCategory);
            String type = plugin.elementType().equals("") ? plugin.name() : plugin.elementType();
            PluginType pluginType = new PluginType(clazz, type, plugin.printObject(), plugin.deferChildren());
            map.put(plugin.name().toLowerCase(), pluginType);
            PluginAliases pluginAliases = clazz.getAnnotation(PluginAliases.class);
            if (pluginAliases == null) continue;
            for (String alias : pluginAliases.value()) {
                type = plugin.elementType().equals("") ? alias : plugin.elementType();
                pluginType = new PluginType(clazz, type, plugin.printObject(), plugin.deferChildren());
                map.put(alias.trim().toLowerCase(), pluginType);
            }
        }
        this.plugins = REGISTRY.getCategory(this.category);
    }

    private void reportPluginLoadDuration(boolean preLoad, long elapsed) {
        StringBuilder sb = new StringBuilder("Generated plugins in ");
        DecimalFormat numFormat = new DecimalFormat("#0.000000");
        double seconds = (double)elapsed / 1.0E9;
        sb.append(numFormat.format(seconds)).append(" seconds, packages: ");
        sb.append(PACKAGES);
        sb.append(", preload: ");
        sb.append(preLoad);
        sb.append(".");
        LOGGER.debug(sb.toString());
    }

    public static void loadPlugins(ResourceLoader loader) {
        PluginRegistry<PluginType<?>> registry = PluginManager.decode(loader);
        if (registry != null) {
            for (Map.Entry<String, ConcurrentMap<String, PluginType<?>>> entry : registry.getCategories()) {
                REGISTRY.getCategory(entry.getKey()).putAll((Map)entry.getValue());
            }
        } else {
            LOGGER.info("Plugin preloads not available from class loader {}", loader);
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private static PluginRegistry<PluginType<?>> decode(ResourceLoader loader) {
        Enumeration<URL> resources;
        try {
            resources = loader.getResources("META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat");
            if (resources == null) {
                return null;
            }
        }
        catch (IOException ioe) {
            LOGGER.warn("Unable to preload plugins", (Throwable)ioe);
            return null;
        }
        PluginRegistry map = new PluginRegistry();
        while (resources.hasMoreElements()) {
            InputStream is;
            URL url = resources.nextElement();
            LOGGER.debug("Found Plugin Map at {}", url.toExternalForm());
            try {
                is = url.openStream();
            }
            catch (IOException e) {
                LOGGER.warn("Unable to open {}", url.toExternalForm(), e);
                continue;
            }
            DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
            try {
                int count = dis.readInt();
                for (int j = 0; j < count; ++j) {
                    String category = dis.readUTF();
                    int entries = dis.readInt();
                    ConcurrentMap<String, PluginType<?>> types = map.getCategory(category);
                    for (int i = 0; i < entries; ++i) {
                        String key = dis.readUTF();
                        String className = dis.readUTF();
                        String name = dis.readUTF();
                        boolean printable = dis.readBoolean();
                        boolean defer = dis.readBoolean();
                        try {
                            Class<?> clazz = loader.loadClass(className);
                            PluginType pluginType = new PluginType(clazz, name, printable, defer);
                            types.put(key, pluginType);
                            continue;
                        }
                        catch (ClassNotFoundException e) {
                            LOGGER.info("Plugin [{}] could not be loaded due to missing classes.", className, e);
                            continue;
                        }
                        catch (VerifyError e) {
                            LOGGER.info("Plugin [{}] could not be loaded due to verification error.", className, e);
                        }
                    }
                }
            }
            catch (IOException ex) {
                LOGGER.warn("Unable to preload plugins", (Throwable)ex);
            }
            finally {
                Closer.closeSilently(dis);
            }
        }
        return map.isEmpty() ? null : map;
    }

    public static class PluginTest
    implements ResolverUtil.Test {
        private final Class<?> isA;

        public PluginTest(Class<?> isA) {
            this.isA = isA;
        }

        @Override
        public boolean matches(Class<?> type) {
            return type != null && type.isAnnotationPresent(Plugin.class) && (this.isA == null || this.isA.isAssignableFrom(type));
        }

        public String toString() {
            StringBuilder msg = new StringBuilder("annotated with @" + Plugin.class.getSimpleName());
            if (this.isA != null) {
                msg.append(" is assignable to " + this.isA.getSimpleName());
            }
            return msg.toString();
        }

        @Override
        public boolean matches(URI resource) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean doesMatchClass() {
            return true;
        }

        @Override
        public boolean doesMatchResource() {
            return false;
        }
    }
}
