package eu.dnetlib.functionality.modular.ui;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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 com.google.common.collect.Maps;

import eu.dnetlib.conf.PropertyFetcher;
import eu.dnetlib.conf.WebappContextPropertyLocationFactory;

/**
 * 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 {
		this.propertyFetcherProps = this.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 (final String location : this.propertyLocations.getLocations()) {
			log.debug(String.format("Loading properties from %s", location));
			// loop over all *.properties files matching the location
			for (final Resource propertyFile : this.pathResolver.getResources(location)) {
				final 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 (final Entry<Object, Object> property : properties.entrySet()) {
					List<PropertyInfo> propertyInfoList;
					if (propertiesMap.containsKey(property.getKey())) {
						propertyInfoList = propertiesMap.get(property.getKey());
					} else {
						propertyInfoList = new 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) {
		final String winningPropertyValue = this.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 this.value;
		}

		public String getSourcePropertyFile() {
			return this.sourcePropertyFile;
		}

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