/*
 * #%L
 * Fuse EAP :: Config
 * %%
 * Copyright (C) 2015 RedHat
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package org.jboss.fuse.eap.config;

import static org.wildfly.extension.camel.config.WildFlyCamelConfigPlugin.NS_DOMAIN;
import static org.wildfly.extension.camel.config.WildFlyCamelConfigPlugin.NS_LOGGING;
import static org.wildfly.extension.camel.config.WildFlyCamelConfigPlugin.NS_SECURITY;

import java.net.URL;
import java.util.Arrays;
import java.util.List;

import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.Text;
import org.wildfly.extras.config.ConfigContext;
import org.wildfly.extras.config.ConfigPlugin;
import org.wildfly.extras.config.ConfigSupport;
import org.wildfly.extras.config.LayerConfig;
import org.wildfly.extras.config.LayerConfig.Type;

public class SwitchyardConfigPlugin implements ConfigPlugin {

    private static final Namespace NS_INFINISPAN = Namespace.getNamespace("urn:jboss:domain:infinispan:1.5");
    private static final Namespace NS_SWITCHYARD = Namespace.getNamespace("urn:jboss:domain:switchyard:1.0");

    @Override
    public String getConfigName() {
        return "switchyard";
    }

    @Override
    public List<LayerConfig> getLayerConfigs() {
        return Arrays.asList(new LayerConfig("fuse", Type.INSTALLING, -10), new LayerConfig("bpms", Type.OPTIONAL, -9), new LayerConfig("soa", Type.INSTALLING, -8));
    }
    
    @Override
    public void applyStandaloneConfigChange(ConfigContext context, boolean enable) {
        String fileName = context.getConfiguration().getFileName().toString();
        updateExtension(context, enable);
        updateLogging(context, enable);
        updateSecurityDomain(context, enable);
        updateSubsystem(context, enable);
        if (fileName.contains("-ha")) {
            updateInfinispan(true, context);
        }
    }

    @Override
    public void applyDomainConfigChange(ConfigContext context, boolean enable) {
        applyStandaloneConfigChange(context, enable);
        updateInfinispan(enable, context);
    }

    private static void updateExtension(ConfigContext context, boolean enable) {
        Element extensions = context.getDocument().getRootElement().getChild("extensions", NS_DOMAIN);
        ConfigSupport.assertExists(extensions, "Did not find the <extensions> element");
        Element element = ConfigSupport.findElementWithAttributeValue(extensions, "extension", NS_DOMAIN, "module", "org.switchyard");
        if (enable && element == null) {
            extensions.addContent(new Text("    "));
            extensions.addContent(new Element("extension", NS_DOMAIN).setAttribute("module", "org.switchyard"));
            extensions.addContent(new Text("\n    "));
        }
        if (!enable && element != null) {
            element.getParentElement().removeContent(element);
        }
    }

    private static void updateLogging(ConfigContext context, boolean enable) {
        List<Element> profiles = ConfigSupport.findProfileElements(context.getDocument(), NS_DOMAIN);
        for (Element profile : profiles) {

            Element logging = profile.getChild("subsystem", NS_LOGGING);
            ConfigSupport.assertExists(logging, "Did not find the security subsystem");

            Element element = ConfigSupport.findElementWithAttributeValue(logging, "logger", NS_LOGGING, "category", "org.switchyard");
            if (enable && element == null) {
                URL resource = SwitchyardConfigPlugin.class.getResource("/logger-switchyard.xml");
                logging.addContent(new Text("    "));
                logging.addContent(ConfigSupport.loadElementFrom(resource));
                logging.addContent(new Text("\n    "));
            }
            if (!enable && element != null) {
                element.getParentElement().removeContent(element);
            }

            element = ConfigSupport.findElementWithAttributeValue(logging, "logger", NS_LOGGING, "category", "org.apache.deltaspike.core.api.provider.BeanManagerProvider");
            if (enable && element == null) {
                URL resource = SwitchyardConfigPlugin.class.getResource("/logger-deltaspike.xml");
                logging.addContent(new Text("    "));
                logging.addContent(ConfigSupport.loadElementFrom(resource));
                logging.addContent(new Text("\n    "));
            }
            if (!enable && element != null) {
                element.getParentElement().removeContent(element);
            }
        }
    }

    private static void updateSubsystem(ConfigContext context, boolean enable) {
        List<Element> profiles = ConfigSupport.findProfileElements(context.getDocument(), NS_DOMAIN);
        for (Element profile : profiles) {
            Element element = profile.getChild("subsystem", NS_SWITCHYARD);
            if (enable && element == null) {
                URL resource = SwitchyardConfigPlugin.class.getResource("/switchyard-subsystem.xml");
                profile.addContent(new Text("    "));
                profile.addContent(ConfigSupport.loadElementFrom(resource));
                profile.addContent(new Text("\n    "));
            }
            if (!enable && element != null) {
                element.getParentElement().removeContent(element);
            }
        }
    }

    private static void updateSecurityDomain(ConfigContext context, boolean enable) {
        List<Element> profiles = ConfigSupport.findProfileElements(context.getDocument(), NS_DOMAIN);
        for (Element profile : profiles) {
            Element security = profile.getChild("subsystem", NS_SECURITY);
            ConfigSupport.assertExists(security, "Did not find the security subsystem");
            Element domains = security.getChild("security-domains", NS_SECURITY);
            ConfigSupport.assertExists(domains, "Did not find the <security-domains> element");
            Element domain = ConfigSupport.findElementWithAttributeValue(domains, "security-domain", NS_SECURITY, "name", "bpel-console");
            if (enable && domain == null) {
                URL resource = SwitchyardConfigPlugin.class.getResource("/bpel-console-security-domain.xml");
                domains.addContent(new Text("    "));
                domains.addContent(ConfigSupport.loadElementFrom(resource));
                domains.addContent(new Text("\n            "));
            }
            if (!enable && domain != null) {
                domain.getParentElement().removeContent(domain);
            }
        }
    }

    private static void updateInfinispan(boolean enable, ConfigContext context) {
        List<Element> profiles = ConfigSupport.findProfileElements(context.getDocument(), NS_DOMAIN);
        for (Element profile : profiles) {
            Element infinispan = profile.getChild("subsystem", NS_INFINISPAN);
            ConfigSupport.assertExists(infinispan, "Did not find the cache subsystem");
            Element element = ConfigSupport.findElementWithAttributeValue(infinispan, "cache-container", NS_INFINISPAN, "name", "switchyard");
            if (enable && element == null) {
                URL resource = SwitchyardConfigPlugin.class.getResource("/switchyard-cache-container.xml");
                infinispan.addContent(new Text("    "));
                infinispan.addContent(ConfigSupport.loadElementFrom(resource));
                infinispan.addContent(new Text("\n    "));
            }
            if (!enable && element != null) {
                element.getParentElement().removeContent(element);
            }
        }
    }
}
