package de.renew.plugin.locate;

import java.io.File;
import java.io.FileInputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Vector;

import de.renew.plugin.PluginProperties;


/**
 * This class implements the PluginLocationFinder interface.
 * It searches Plugin configurations based on a given directory URL <i>u</i>
 * by searching in all the subdirectories for a file "plugin.cfg".
 *
 * The URL contained in the resulting PluginProperties object will
 * be a file URL to the found plugin.cfg file.
 *
 * This file must be a properties file as described in the java.util.Property documentation.
 * Note: The base url itself is NOT searched!
 */
public class PluginSubDirFinder 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(PluginSubDirFinder.class);

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

    /**
     * return a list of directories contained in the given directory.
     */
    @Override
    protected File[] getPluginFiles(File dir) {
        File[] plugins = dir.listFiles(file -> file.isDirectory());
        return plugins;
    }

    @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 = getPluginConfigFromDirectory(plugins[i]);
            if (cfg != null) {
                pluginURLv.add(cfg);
            }
        }
        return pluginURLv;
    }

    /**
     * Creates a PluginConfiguration object from the given directory.
     * This is done by looking in for a plugin.cfg file which is then
     * used to construct the result object.
     *
     * @param location the directory where the PluginConfiguration is created from
     * @return a PluginConfiguration if a plugin.cfg is found. Otherwise, null.
     */
    protected PluginProperties getPluginConfigFromDirectory(File location) {
        if (location.isDirectory()) {
            File[] cfgFiles = location.listFiles((dir, file) -> file.equals("plugin.cfg"));
            File loc = null;
            if (cfgFiles.length > 0) {
                loc = cfgFiles[0];
                if (cfgFiles.length > 1) {
                    LOGGER.warn(
                        "PluginSubDirFinder: " + location + " contains more than one "
                            + "plugin.cfg file! using only " + location);
                }

                // logger.debug ("added to class loader: " + jarFile.toURL());
            } else {
                LOGGER.debug("PluginSubDirFinder: no plugin.cfg found in " + location);
            }

            if (loc != null) {
                return createPluginConfig(loc);
            }
        }
        return null;
    }

    /**
     * Tries to create a <code>PluginProperties</code> from the given file.
     * <p>
     * The supplied file must contain a <strong>plugin.cfg</strong>.
     *
     * @param loc   The 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) {
        URL url;
        try {
            url = loc.toURI().toURL();
            try (FileInputStream stream = new FileInputStream(loc)) {
                // load setting from the given file
                PluginProperties props = new PluginProperties(url, stream);
                return props;
            } catch (Exception e) {
                LOGGER.error("PluginSubDirFinder: " + e);
            }
        } catch (MalformedURLException e) {
            LOGGER.error("PluginSubDirFinder: could not create URL from " + loc + ": " + e);
        }
        return null;
    }

    private static void list(Collection<?> l) {
        for (Object o : l) {
            System.out.println(o);
        }
    }
}