package de.renew.plugin.locate;

import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import de.renew.plugin.PluginProperties;
import de.renew.plugin.PropertyHelper;


/**
 * A Composition of PluginLocationFinders so several Finders can be used
 * to look for plugin configuration objects.
 */
public class PluginLocationFinders implements PluginLocationFinder {
    private static PluginLocationFinders _instance;
    private Collection<PluginLocationFinder> _finders = new Vector<>();

    private PluginLocationFinders() {}

    /**
     * Return a singleton instance of this <code>PluginLocationFinder</code>.
     *
     * @return The current instance
     */
    public static PluginLocationFinders getInstance() {
        if (_instance == null) {
            _instance = new PluginLocationFinders();
        }
        return _instance;
    }

    /**
     * Adds the given <code>PluginLocationFinder</code> to this composition.
     *
     * @param f The <code>PluginLocationFinder</code> to add
     */
    public void addLocationFinder(PluginLocationFinder f) {
        _finders.add(f);
    }

    /**
     * Removes the given <code>PluginLocationFinder</code> from this composition.
     *
     * @param f The <code>PluginLocationFinder</code> to remove
     */
    public void removeLocationFinder(PluginLocationFinder f) {
        _finders.remove(f);
    }

    /**
     * Calls findPluginLocations() for all contained PluginLocationFinders,
     * merging the result lists.
     */
    @Override
    public Collection<PluginProperties> findPluginLocations() {
        Collection<PluginProperties> result = new Vector<>();
        for (PluginLocationFinder finder : _finders) {
            //        logger.debug (finder + " looking for plug-in locations");
            Collection<PluginProperties> locations = finder.findPluginLocations();
            result.addAll(locations);
        }

        PluginProperties userProperties = PluginProperties.getUserProperties();

        if (userProperties.getBoolProperty("de.renew.plugin.autoLoad", true)) {
            // remove all items that the user didn't want to load
            Collection<String> noLoad = PropertyHelper
                .parseListString(userProperties.getProperty("de.renew.plugin.noLoad", ""));
            Iterator<PluginProperties> cleanedList = result.iterator();
            while (cleanedList.hasNext()) {
                PluginProperties props = cleanedList.next();
                if (noLoad.contains(props.getName())) {
                    cleanedList.remove();
                }
            }
        } else {
            Collection<String> load = PropertyHelper
                .parseListString(userProperties.getProperty("de.renew.plugin.load", ""));
            Iterator<PluginProperties> cleanedList = result.iterator();
            while (cleanedList.hasNext()) {
                PluginProperties props = cleanedList.next();
                if (!load.contains(props.getName())) {
                    cleanedList.remove();
                }
            }
        }

        return result;
    }

    /**
     * Calls <code>checkPluginLocation(url)</code> for all contained
     * <code>PluginLocationFinder</code>s, returning the first result
     * that differs from <code>null</code> (if there is any).
     **/
    @Override
    public PluginProperties checkPluginLocation(URL url) {
        PluginProperties props = null;
        for (PluginLocationFinder finder : _finders) {
            // logger.debug (finder + " checking plug-in location");
            if (props == null) {
                props = finder.checkPluginLocation(url);
            }
        }
        return props;
    }

    @Override
    public PluginProperties findPluginByProvides(String provides) {
        PluginProperties props = null;
        for (PluginLocationFinder finder : _finders) {
            if (props == null) {
                props = finder.findPluginByProvides(provides);
            }
        }
        return props;
    }

    @Override
    public PluginProperties findPluginByName(String pluginName) {
        PluginProperties props = null;
        for (PluginLocationFinder finder : _finders) {
            if (props == null) {
                props = finder.findPluginByName(pluginName);
            }
        }
        return props;
    }

    @Override
    public Collection<URL> getLocations() {
        Collection<URL> locations = new ArrayList<>();
        for (PluginLocationFinder finder : _finders) {
            if (!locations.containsAll(finder.getLocations())) {
                locations.addAll(finder.getLocations());
            }
        }
        return locations;
    }


}