package de.lcag.common;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import routines.LcagFileTools;
import routines.LcagLogger;
import routines.LcagStringTools;

/*
 * Implements Java properties whose values can contain variables point to other property variables or operating system environment variables
 * First, it checks if variable is defined in the property file itself.  If not it checks if it can be resolved as system OS variable 
 * Variables are reference as ${varName} in the values.
 */
public class LcagProperties {
	private static LcagLogger logger = LcagLogger.getLogger(LcagProperties.class);

//	private Class<?> clazz = null;
	private String fileName = null;
	private Properties properties = null;
	private String propFilePath = null;

	/*
	 * Use this to locate the properties file via the class loader.
	 */
//	public LcagProperties(Class<?> pClass, String pFileName) {
//		this.clazz = pClass;
//		this.fileName = pFileName;
//	}

	public LcagProperties(String pPropFilePath, String pFileName) {
		this.propFilePath = pPropFilePath;
		this.fileName = pFileName;
	}

	public LcagProperties(String pPropFilePath) {
		this.fileName = LcagFileTools.getName(pPropFilePath);
		this.propFilePath = LcagFileTools.getPath(pPropFilePath);
	}

	private String getProperty(String pPropertyName, boolean pIsOptional) {
		String result = null;
		String formatPropPath = null;

		load();

		if (this.properties != null) {
			result = this.properties.getProperty(pPropertyName);

			if (result == null) {
				if (pIsOptional) {
					logger.debug("Property '%s' not defined in properties file %s", pPropertyName, this.fileName);
				} else {
					logger.error("Property '%s' not defined in properties file %s", pPropertyName, this.fileName);
				}
			} else {
				result = LcagStringTools.resolveVariables(result, this.properties);
				result = LcagStringTools.resolveEnvironmentVariables(result);
			}

		}

		return result;
	}

	public Map<String, String> getProperties() {
		Map<String, String> result = new HashMap<>();

		load();
		final Set<String> propertyNames = this.properties.stringPropertyNames();

		for (String p : propertyNames) {
			String value = this.getProperty(p);

			result.put(p, value);
		}

		return result;
	}

	private void load() {
		String formatPropPath;

		if (this.properties == null) {
			try {
				String filePath = this.propFilePath + this.fileName;

				formatPropPath = LcagStringTools.resolveEnvironmentVariables(filePath);
				logger.info("Properties file path =%s", formatPropPath);
				InputStream input = new FileInputStream(formatPropPath);

				this.properties = new Properties();

				if (input == null)
					logger.error("Sorry, unable to find property file %s", this.fileName);

				this.properties.load(input);
			} catch (IOException ex) {
				logger.error("Error while reading properties file %s\n" + ex, this.fileName);
			}
		}
	}

	public String getProperty(String pPropertyName) {
		return getProperty(pPropertyName, false);
	}

	public String getOptionalProperty(String pPropertyName) {
		return getProperty(pPropertyName, true);
	}

	public Path getFilePathProperty(String pPropertyName) {
		Path result = null;
		String path = getProperty(pPropertyName);

		if (LcagStringTools.isEmpty(path)) {
			logger.error("File path cannot be an empty string");
		} else {
			result = Path.of(path);
		}
		return result;
	}

	public Path getOptionalFilePathProperty(String pPropertyName) {
		Path result = null;
		String path = getOptionalProperty(pPropertyName);

		if (!LcagStringTools.isEmpty(path))
			result = Path.of(path);

		return result;
	}

	public String getProperty(String pPropertyName, String pDefaultValue) {
		String result = this.getProperty(pPropertyName, false);

		if (result == null)
			result = pDefaultValue;

		return result;
	}

	public String resolveIn(String pText) {
		String result = null;

		final Map<String, String> resolvedProperties = this.getProperties();
		result = LcagStringTools.resolveVariables(pText, resolvedProperties);

		return result;
	}
}
