package eu.dnetlib.functionality.modular.ui;

import com.google.common.collect.Maps;
import eu.dnetlib.conf.PropertyFetcher;
import eu.dnetlib.conf.WebappContextPropertyLocationFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jparsec.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.ui.ModelMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

/**
 * Modular UI that displays collected properties and shows winning ones.
 *
 * @author Andrea Mannocci
 */
public class ContainerPropertiesController extends ModuleEntryPoint {

    private static final Log log = LogFactory.getLog(ContainerPropertiesController.class);

    private final ResourcePatternResolver pathResolver = new PathMatchingResourcePatternResolver();

    @Autowired
    private PropertyFetcher propertyFetcher;

    private Properties propertyFetcherProps;

    @Autowired
    private WebappContextPropertyLocationFactory propertyLocations;

    @Override
    protected void initialize(final ModelMap map, final HttpServletRequest request, final HttpServletResponse response) throws Exception {
        propertyFetcherProps = propertyFetcher.getProps();
        map.addAttribute("properties", fetchProperties());
    }

    private Map<String, List<PropertyInfo>> fetchProperties() throws IOException {
        final Map<String, List<PropertyInfo>> propertiesMap = Maps.newTreeMap();

        // cycle over all property locations know to dnet
        for (String location : propertyLocations.getLocations()) {
            log.debug(String.format("Loading properties from %s", location));
            // loop over all *.properties files matching the location
            for (Resource propertyFile : pathResolver.getResources(location)) {
                Properties properties = new Properties();
                log.debug(String.format("URL: %s", propertyFile.getURL()));
                properties.load(propertyFile.getInputStream());

                // loop over all properties set within a property file file
                for (Entry<Object, Object> property : properties.entrySet()) {
                    List<PropertyInfo> propertyInfoList;
                    if (propertiesMap.containsKey(property.getKey())) {
                        propertyInfoList = propertiesMap.get(property.getKey());
                    } else {
                        propertyInfoList = Lists.arrayList();
                    }

                    propertyInfoList.add(new PropertyInfo((String) property.getValue(), propertyFile.getFilename(), isWinning((String) property.getKey(), (String) property.getValue())));
                    propertiesMap.put((String) property.getKey(), propertyInfoList);
                }
            }
        }

        // Scans the Map just created for properties overridden externally (e.g. by Tomcat)
        /*        for (String property : propertiesMap.keySet()) {
                    List<PropertyInfo> propertyInfoList = propertiesMap.get(property);
                    boolean isOverridden = true;
                    for (PropertyInfo propInfo : propertyInfoList) {
                        // Checks for a checker
                        if (propInfo.isChecked) {
                            isOverridden = false;
                        }
                    }

                    // If none of the pairs has been checked, then the property has been overridden externally.
                    if (isOverridden && propertyFetcherProps.getProperty(property) != null) {
                        // Adds the current property value (which is the override) as the current one.
                        propertyInfoList.add(new PropertyInfo(propertyFetcherProps.getProperty(property), "Overridden externally", true));
                        propertiesMap.put(property, propertyInfoList);
                    }
                }*/

        return propertiesMap;
    }

    /**
     * Checks whether a given property-value is the one currently in use.
     *
     * @param property The property key
     * @param value    The property value
     * @return true/false
     */
    private Boolean isWinning(final String property, final String value) {
        String winningPropertyValue = propertyFetcherProps.getProperty(property);
        return value.equals(winningPropertyValue);
    }


    private class PropertyInfo {

        String value;
        String sourcePropertyFile;
        Boolean isChecked;

        public PropertyInfo(final String value, final String sourcePropertyFile, final Boolean isChecked) {
            this.value = value;
            this.sourcePropertyFile = sourcePropertyFile;
            this.isChecked = isChecked;
        }

        public String getValue() {
            return value;
        }

        public String getSourcePropertyFile() {
            return sourcePropertyFile;
        }

        public Boolean getIsChecked() {
            return isChecked;
        }
    }
}
