/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

package org.apache.sling.distribution.component.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.distribution.resources.impl.OsgiUtils;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Manager implementation which represents the distribution configurations as OSGI configuration.
 */
public class OsgiConfigurationManager implements DistributionConfigurationManager {
    private final ConfigurationAdmin configurationAdmin;
    private final Logger log = LoggerFactory.getLogger(getClass());

    private final DistributionComponentFactoryMap componentFactoryMap;

    public OsgiConfigurationManager(ConfigurationAdmin configurationAdmin, DistributionComponentFactoryMap componentFactoryMap) {

        this.configurationAdmin = configurationAdmin;
        this.componentFactoryMap = componentFactoryMap;
    }


    public List<DistributionConfiguration> getConfigs(ResourceResolver resolver, DistributionComponentKind kind) {
        List<Configuration> configurations = getOsgiConfigurations(kind, null);

        List<DistributionConfiguration> result = new ArrayList<DistributionConfiguration>();
        if (configurations == null || configurations.isEmpty()) {
            return result;
        }


        for (Configuration configuration : configurations) {
            @SuppressWarnings( "unchecked" )
            Dictionary<String, Object> propertiesDict = configuration.getProperties();
            Map<String, Object> properties = OsgiUtils.fromDictionary(propertiesDict);

            properties = filterBeforeRead(properties);
            String name = PropertiesUtil.toString(properties.get(DistributionComponentConstants.PN_NAME), null);
            result.add(new DistributionConfiguration(kind, name, properties));

        }

        return result;
    }

    public DistributionConfiguration getConfig(ResourceResolver resolver, DistributionComponentKind kind, String name) {
        List<Configuration> configurations = getOsgiConfigurations(kind, name);

        if (configurations == null || configurations.isEmpty()) {
            return null;
        }

        if (configurations.size() > 1) {
            log.warn("Found more than one configuration of kind: {} and with name: {}",
                    new String[]{kind.getName(), name});
        }

        Configuration configuration = configurations.get(0);

        if (configuration != null) {
            @SuppressWarnings( "unchecked" )
            Dictionary<String, Object> properties = configuration.getProperties();
            Map<String, Object> result = OsgiUtils.fromDictionary(properties);

            String factoryPid = PropertiesUtil.toString(result.get(ConfigurationAdmin.SERVICE_FACTORYPID), null);
            String type = componentFactoryMap.getType(kind, factoryPid);

            result.put(DistributionComponentConstants.PN_TYPE, type);
            result = filterBeforeRead(result);
            return new DistributionConfiguration(kind, name, result);
        }

        return null;
    }

    public void saveConfig(ResourceResolver resolver, DistributionConfiguration config) {
        String componentName = config.getName();
        DistributionComponentKind componentKind = config.getKind();
        Map<String, Object> properties = config.getProperties();
        String componentType = PropertiesUtil.toString(properties.get(DistributionComponentConstants.PN_TYPE), null);

        if (componentKind == null || componentType == null) {
            throw new IllegalArgumentException("kind and type are required " + componentKind + componentType);
        }

        String factoryPid = componentFactoryMap.getFactoryPid(componentKind, componentType);
        if (factoryPid != null) {

            // SLING-5872 - Management of agent configurations must identify configurations by name
            // Remove the agents with the same name wich are not bind to the same factory.
            List<Configuration> configs = getOsgiConfigurations(componentKind, componentName);
            for (Iterator<Configuration> iter = configs.iterator() ; iter.hasNext() ; ) {
                Configuration conf = iter.next();
                if (factoryPid.equals(conf.getFactoryPid())) {
                    iter.remove();
                }
            }
            deleteOsgiConfigs(configs);

            properties.put(DistributionComponentConstants.PN_NAME, componentName);
            saveOsgiConfig(factoryPid, componentName, properties);
        }

    }

    public void deleteConfig(ResourceResolver resolver, DistributionComponentKind kind, String name) {
        List<Configuration> configs = getOsgiConfigurations(kind, name);

        deleteOsgiConfigs(configs);

        log.info("Delete component {}", name);

    }


    private void deleteOsgiConfigs(List<Configuration> configurations) {
        for (Configuration configuration : configurations) {
            String pid = configuration.getPid();

            try {
                configuration.delete();
                log.info("Deleted configuration {}", pid);
            } catch (IOException e) {
                log.warn("Cannot delete configuration {}", pid, e);
            }
        }
    }

    private List<Configuration> getOsgiConfigurations(DistributionComponentKind kind, String componentName) {
        List<String> factoryPids = componentFactoryMap.getFactoryPids(kind);

        List<Configuration> allConfigurations = new ArrayList<Configuration>();
        for (String factoryPid : factoryPids) {
            List<Configuration> configurations = getOsgiConfigurationsFromFactory(factoryPid, componentName);
            allConfigurations.addAll(configurations);
        }

        return allConfigurations;
    }


    private Configuration saveOsgiConfig(String factoryPid, String componentName, Map<String, Object> properties) {
        try {
            List<Configuration> configurations = getOsgiConfigurationsFromFactory(factoryPid, componentName);
            Configuration configuration = null;
            if (configurations == null || configurations.isEmpty()) {
                configuration = configurationAdmin.createFactoryConfiguration(factoryPid);
            } else {
                configuration = configurations.get(0);
            }

            properties = filterBeforeSave(properties);

            configuration.update(OsgiUtils.toDictionary(properties));

            return configuration;
        } catch (IOException e) {
            log.error("Cannot create configuration with factory {}", factoryPid, e);
        }

        return null;
    }

    private List<Configuration> getOsgiConfigurationsFromFactory(String factoryPid, String componentName) {
        List<Configuration> result = new ArrayList<Configuration>();

        try {
            String filter = OsgiUtils.getFilter(factoryPid, DistributionComponentConstants.PN_NAME, componentName);

            Configuration[] configurations = configurationAdmin.listConfigurations(filter);
            if (configurations != null) {
                result.addAll(Arrays.asList(configurations));
            }
        } catch (IOException e) {
            log.error("cannot get osgi configs", e);
        } catch (InvalidSyntaxException e) {
            log.error("cannot parse filter", e);
        }

        return result;
    }

    private Map<String, Object> filterBeforeSave(Map<String, Object> properties) {
        Map<String, Object> result = new HashMap<String, Object>();

        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            if (entry.getKey().endsWith(".target")) {
                String entryValue = (String) entry.getValue();
                entryValue = packOsgiFilter(entryValue);
                if (entryValue != null) {
                    result.put(entry.getKey(), entryValue);
                }
            } else {
                result.put(entry.getKey(), entry.getValue());
            }

        }

        result = OsgiUtils.sanitize(result);
        return result;
    }

    private Map<String, Object> filterBeforeRead(Map<String, Object> properties) {
        Map<String, Object> result = new HashMap<String, Object>();

        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            if (entry.getKey().endsWith(".target")) {
                String entryValue = (String) entry.getValue();
                entryValue = unpackOsgiFilter(entryValue);
                if (entryValue != null) {
                    result.put(entry.getKey(), entryValue);
                }
            } else {
                result.put(entry.getKey(), entry.getValue());
            }

        }

        result = OsgiUtils.sanitize(result);
        return result;
    }


    private String unpackOsgiFilter(String propertyValue) {

        String result = null;

        String namePattern = "\\(" + DistributionComponentConstants.PN_NAME + "=(.*?)\\)";

        Pattern r = Pattern.compile(namePattern);
        Matcher m = r.matcher(propertyValue);

        if (m.matches()) {
            result = m.group(1);
        }

        return result;
    }

    private String packOsgiFilter(String propertyValue) {
        return "(" + DistributionComponentConstants.PN_NAME + "=" + OsgiUtils.escape(propertyValue) + ")";
    }
}
