package com.dtolabs.rundeck.core.common;

import com.dtolabs.rundeck.core.plugins.configuration.Description;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Created by rodrigo on 30-01-18.
 */
public class PluginControlServiceImpl implements PluginControlService {

    public static final String DISABLED_PLUGINS = "disabled.plugins";
    private final HashSet<String> disabledPlugins;

    private PluginControlServiceImpl(String config) {
        disabledPlugins = new HashSet<>(parseConfig(config));
    }

    public static PluginControlService forProject(IFramework framework, String project) {
        IRundeckProject frameworkProject = framework.getFrameworkProjectMgr().getFrameworkProject(project);
        String disabledPlugins =
                frameworkProject.hasProperty(DISABLED_PLUGINS)
                ? frameworkProject.getProperty(DISABLED_PLUGINS)
                : null;
        return new PluginControlServiceImpl(disabledPlugins);
    }

    /**
     * @return list of disabled plugins for the project, in Service:provider format
     */
    @Override
    public List<String> listDisabledPlugins() {
        return new ArrayList<>(disabledPlugins);
    }

    @Override
    public Set<String> getDisabledPlugins() {
        return disabledPlugins;
    }

    private static List<String> parseConfig(final String disabledPlugins) {
        if (disabledPlugins != null && !disabledPlugins.trim().isEmpty()) {
            return Arrays.asList(disabledPlugins.split("\\s*,\\s*"));
        }
        return new ArrayList<>();
    }

    /**
     * @param plugins     descriptions list
     * @param serviceName service name
     * @return list of enabled plugin descriptions
     */
    @Override
    public List<Description> filterEnabledPlugins(
        List<Description> plugins,
        final String serviceName
    ) {
        Set<String> strings = getDisabledPlugins();
        return plugins
            .stream()
            .filter(description -> !strings.contains(serviceName + ":" + description.getName()))
            .collect(Collectors.toList());
    }

    /**
     * @param serviceName service name
     * @return predicate for testing enabled providers for a service
     */
    @Override
    public Predicate<String> enabledPredicateForService(
        final String serviceName
    ) {
        Set<String> strings = getDisabledPlugins();
        return name -> !strings.contains(serviceName + ":" + name);
    }
    /**
     * @param serviceName service name
     * @return predicate for testing disabled providers for a service
     */
    @Override
    public Predicate<String> disabledPredicateForService(
        final String serviceName
    ) {
        return enabledPredicateForService(serviceName).negate();
    }

    /**
     * @param pluginName  provider name
     * @param serviceName service name
     * @return true if given plugin is disabled
     */
    @Override
    public boolean isDisabledPlugin(String pluginName, final String serviceName) {
        return getDisabledPlugins().contains(serviceName + ":" + pluginName);
    }

    /**
     * @param pluginName  provider name
     * @param serviceName service name
     * @throws PluginDisabledException if the given plugin is disabled
     */
    @Override
    public void checkDisabledPlugin(String pluginName, final String serviceName)
        throws PluginDisabledException {
        if (isDisabledPlugin(pluginName, serviceName)) {
            throw new PluginDisabledException(String.format(
                "%s Plugin '%s' is disabled",
                serviceName,
                pluginName
            ));
        }
    }
}

@@ -395,22 +395,16 @@
 private 
-final 
 HashSet%3C
@@ -432,123 +432,226 @@
 ns;%0A
-%0A    private PluginControlServiceImpl(String config) %7B%0A        disabledPlugins = new HashSet%3C%3E(parseConfig(config))
+    private final IFramework framework;%0A    private final String project;%0A%0A    private PluginControlServiceImpl(IFramework framework, String project) %7B%0A        this.framework = framework;%0A        this.project = project
 ;%0A  
@@ -651,24 +651,25 @@
 ect;%0A    %7D%0A%0A
+%0A
     public s
@@ -750,300 +750,8 @@
 ) %7B%0A
-        IRundeckProject frameworkProject = framework.getFrameworkProjectMgr().getFrameworkProject(project);%0A        String disabledPlugins =%0A                frameworkProject.hasProperty(DISABLED_PLUGINS)%0A                ? frameworkProject.getProperty(DISABLED_PLUGINS)%0A                : null;
 %0A   
@@ -791,31 +791,34 @@
 iceImpl(
-disabledPlugins
+framework, project
 );%0A    %7D
@@ -1012,17 +1012,20 @@
 yList%3C%3E(
-d
+getD
 isabledP
@@ -1030,16 +1030,18 @@
 dPlugins
+()
 );%0A    %7D
@@ -1094,32 +1094,612 @@
 bledPlugins() %7B%0A
+        if (null == disabledPlugins) %7B%0A            synchronized (this) %7B%0A                if (null == disabledPlugins) %7B%0A                    IRundeckProject frameworkProject = framework.getFrameworkProjectMgr().getFrameworkProject(project);%0A                    String config =%0A                            frameworkProject.hasProperty(DISABLED_PLUGINS)%0A                            ? frameworkProject.getProperty(DISABLED_PLUGINS)%0A                            : null;%0A                    disabledPlugins = new HashSet%3C%3E(parseConfig(config));%0A                %7D%0A            %7D%0A        %7D%0A
         return d
@@ -1778,31 +1778,28 @@
  String 
-disabledPlugins
+pluginConfig
 ) %7B%0A    
@@ -1810,51 +1810,45 @@
 if (
-disabledPlugins != null && !disabledPlugins
+pluginConfig != null && !pluginConfig
 .tri
@@ -1897,31 +1897,28 @@
 .asList(
-disabledPlugins
+pluginConfig
 .split(%22

refactor to lazy load config to facilitate testing