package de.renew.plugin.locate;

import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Vector;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import de.renew.plugin.CollectionLister;
import de.renew.plugin.PluginProperties;


/**
 * This class is used to find the jar files in a directory
 * that contain a "plugin.cfg" entry.
 *
 * This is used to create the resulting PluginProperties object.
 *
 */
public class PluginJarLocationFinder extends PluginFileFinder {
    /**
     * Logger of this class for logging purposes as specified by Apache Log4j
     */
    public static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(PluginJarLocationFinder.class);

    /**
     * Creates a new <code>PluginJarLocationFinder</code> instance, which will
     * try to locate plugin jars at the given <code>basedir</code>.
     * <p>
     * Calling this constructor with <code>null</code> will be handled as
     * specified in {@link PluginFileFinder}.
     *
     * @param basedir   A <code>URL</code> pointing to a location where plugins
     *                  are to be located, or <code>null</code>
     */
    public PluginJarLocationFinder(URL basedir) {
        super(basedir);
    }

    @Override
    protected File[] getPluginFiles(File dir) {
        return dir.listFiles(file -> {
            String name = file.getName();
            return file.isFile() && name.endsWith(".jar");
        });
    }

    @Override
    protected Collection<PluginProperties> getPluginConfigurations(File[] plugins) {
        // convert to urls so URLClassloader can be used
        Vector<PluginProperties> pluginURLv = new Vector<>();
        for (int i = 0; i < plugins.length; i++) {
            PluginProperties cfg = createPluginConfig(plugins[i]);
            if (cfg != null) {
                pluginURLv.add(cfg);
            }
        }
        return pluginURLv;
    }

    /**
     * Tries to create a <code>PluginProperties</code> from the given jar file.
     * <p>
     * The supplied jar file must contain a <strong>plugin.cfg</strong>.
     *
     * @param loc   The jar file in which to look for plugin information
     * @return      The <code>PluginProperties</code> object, or <code>null</code>
     *              if the necessary information could not be retrieved
     */
    protected PluginProperties createPluginConfig(File loc) {
        if (!loc.exists()) {
            LOGGER.debug("jar file " + loc + " does not exist.");
            return null;
        }
        LOGGER.debug("looking for plugin.cfg in jar file " + loc + "...");

        try {
            URL url = loc.toURI().toURL();
            PluginProperties props = null;
            JarFile jarFile = new JarFile(loc);
            ZipEntry entry = jarFile.getEntry("plugin.cfg");
            if (entry != null) {
                InputStream stream = jarFile.getInputStream(entry);
                props = new PluginProperties(url, stream);
                LOGGER.debug("zip entry " + entry + " found in " + jarFile.getName());
            } else {
                LOGGER.debug("no zip entry found in " + jarFile.getName());
            }
            return props;
        } catch (MalformedURLException e) {
            LOGGER.error("PluginJarLocationFinder: could not create URL from " + loc);
        } catch (Exception e) {
            LOGGER.error("PluginJarLocationFinder: " + e);
        }
        return null;
    }

    /**
     * @param args (Not used)
     * @deprecated TODO This should be incorporated into a unit test
     */
    @Deprecated
    public static void main(String[] args) {
        PluginProperties.getUserProperties().setProperty("debug", "false");
        PluginJarLocationFinder finder = new PluginJarLocationFinder(null);
        Collection<PluginProperties> found = finder.findPluginLocations();
        System.out.println("found the following locations:");
        System.out.println(CollectionLister.toString(found));
    }
}