/*
 *    GlobalProperties.java
 *    Copyright (C) 2008 New Zealand Digital Library, http://www.nzdl.org
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.greenstone.util;

import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.Properties;

import org.apache.log4j.Logger;

/**
 * holds some global properties for the application. Read from a properties file
 * readsin global.properties. Can optionally read in servlet.properties
 */
public class GlobalProperties
{

	static Logger logger = Logger.getLogger(org.greenstone.util.GlobalProperties.class.getName());
	private static final Properties properties = new Properties();
  private static final Map<String, String> servlet_only_properties = new HashMap<>(); // stores properties that only came from the servlet.properties
	private static String properties_filename = "global.properties";
	private static String gsdl3_home = null;
	private static String gsdl3_writablehome = null;
  private static String gsdl3_datahome = null; // do we need writable version??
	private static String gsdl3_web_address = null;
	private static String full_gsdl3_web_address = null; // for the default protocol

	private static String http_full_gsdl3_web_address = null; // if http or both protocols supported
	private static String https_full_gsdl3_web_address = null; // if https or both protocols supported

	// The locally accessible url such as for solr is always available at http://127.0.0.1:<httpPort>
	// regardless of whether http is listed as one of the server protocols
	private static String localhost_http_web_address = null;

	/** get the value of the property 'key'. returns null if not found */
	public static String getProperty(String key)
	{
		return properties.getProperty(key);
	}

	/**
	 * get the value of the property 'key'. returns default_value if not found
	 */
	public static String getProperty(String key, String default_value)
	{
		return properties.getProperty(key, default_value);
	}
  /** get the set of only servlet ones */
  public static Map<String, String> getServletProperties() {
    return Collections.unmodifiableMap(servlet_only_properties);
  }

	/** some special ones */
  /** The web folder where sites and interfaces live */
	public static String getGSDL3Home()
	{
		return gsdl3_home;
	}
  /** the web folder which Tomcat uses - contains WEB-INF etc */
	public static String getGSDL3WritableHome()
	{
		return gsdl3_writablehome;
	}
  /** the data folder where lots of things live */
	public static String getGSDL3DataHome()
	{
		return gsdl3_datahome;
	}

	public static String getGS2Build()
	{
		return gsdl3_home + File.separator + ".." + File.separator + "gs2build";
	}

	public static String getGSDL3WebAddress()
	{
		return gsdl3_web_address;
	}

	public static String getFullGSDL3WebAddress()
	{
		return full_gsdl3_web_address;
	}

	public static String getLocalHttpBaseAddress()
	{
	    return localhost_http_web_address;
	}

  public static void loadServletProperties(String servlet_properties_filename) {
    Properties s_props = new Properties();
    if (loadPropertiesFromClassLoader(s_props, servlet_properties_filename)) {
      for (String key : s_props.stringPropertyNames()) {
        String value = s_props.getProperty(key);

        properties.setProperty(key, value); // override or add to main properties
        servlet_only_properties.put(key, value);        // track origin
      }
    }
    else {
      logger.error("Couldn't load servlet properties "+servlet_properties_filename);
    }
    
  }
    
  public static void loadGlobalProperties(String full_path_to_properties) {
    try {
      InputStream in  = new FileInputStream(full_path_to_properties);
      logger.info("Found properties file at '"+full_path_to_properties+"'");
      properties.load(in);
      in.close();
      setUpLocalVariables();

    } catch (Exception e) {
      logger.info("Unable to locate '" + full_path_to_properties + "'");
      logger.info("Fallback to default method");
      loadGlobalProperties();
    }
  }

  public static void loadGlobalProperties()
  {
    if (loadPropertiesFromClassLoader(properties, properties_filename)) {
      setUpLocalVariables();
    }
  }

  protected static boolean loadPropertiesFromClassLoader(Properties props, String filename) {
    try
    {
      
      InputStream in = Class.forName("org.greenstone.util.GlobalProperties").getClassLoader().getResourceAsStream(filename);
      
      if (in==null)
      {
        // Try to find it through gsdl3.writablehome
        logger.info("Couldn't find '" + filename + "' through ClassLoader");
        logger.info("Trying alternative path through System property gsdl3.writablehome");
        String sys_gsdl3_writablehome = System.getProperty("gsdl3.writablehome");
        if (sys_gsdl3_writablehome!=null) {
          
          String gp_full_filename = sys_gsdl3_writablehome + File.separator + "WEB-INF"
            + File.separator + "classes" 
            + File.separator + filename; 
          
          try {
            in = new FileInputStream(gp_full_filename);
            logger.info("Found '" + gp_full_filename + "'");
          }
          catch (Exception e) {
            logger.info("Unable to locate '" + gp_full_filename + "'");
          }
        }
        else {
          logger.info("Java property gsdl3.writablehome was not set");
        }
      }
      
      if (in != null)
      {
        logger.debug("Loading properties "+filename);
        props.load(in);
        in.close();
        return true;
        //setUpLocalVariables();
      }
      else {
        logger.error("Failed to find '" + filename + "'");
      }
    }
    catch (Exception e)
    {
      logger.error("Exception trying to load "+filename +": " + e);
      e.printStackTrace();
    } 
    return false;
  }

    public static void setUpLocalVariables() {
      
      gsdl3_home = properties.getProperty("gsdl3.home");

			if (gsdl3_home == null) { 
			    gsdl3_home = System.getenv("GSDL3SRCHOME") + File.separator + "web";
			    logger.warn("** Note: falling back to using GSDL3SRCHOME to set gsdl3.home to: " + gsdl3_home);
			}

			// make sure the path separators are correct
			// gsdl3_home may be null, e.g., when we are loading properties from Server3
			if (gsdl3_home != null)
			{
				File gs3_file = new File(gsdl3_home);
				gsdl3_home = gs3_file.getPath();
			}

			gsdl3_writablehome = properties.getProperty("gsdl3.writablehome");
			// if gsdl3_writablehome is null, then defaults to gsdl3_home
			if (gsdl3_writablehome == null) { 
			    gsdl3_writablehome = gsdl3_home;
			}

                        gsdl3_datahome = properties.getProperty("gsdl3.datahome");
                        if (gsdl3_datahome == null) {
                          gsdl3_datahome = System.getenv("GSDL3DATAHOME");
                        }
                          
			//build the gsdl3 web address, in a way resilient to errors and ommisions in global.properties, simplifying where possible
			//aiming for a string with no trailing slash, eg "http://localhost:8080/greenstone3" or "http://www.mygreenstonelibrary.com"
			String protocolSpecifier = null, hostSpecifier = null, portSpecifier = null, contextSpecifier = null;

			// default protocol
			protocolSpecifier = properties.getProperty("server.protocol");
			if (protocolSpecifier == null || protocolSpecifier.equals(""))
			{
				protocolSpecifier = "http://";
			}
			else if (!protocolSpecifier.endsWith("://"))
			{				
				protocolSpecifier = protocolSpecifier + "://";				
			}

			//hostname
			hostSpecifier = properties.getProperty("tomcat.server");
			if (hostSpecifier == null)
			{
				hostSpecifier = "localhost";
			}
			else
			{				
				while (hostSpecifier.endsWith("/"))
				{
					hostSpecifier = hostSpecifier.substring(0, hostSpecifier.length() - 1);
				}
			}

			//default port (port for the default protocol)
			portSpecifier = properties.getProperty("tomcat.port"); // support for legacy tomcat.port?
			if (portSpecifier == null || portSpecifier.equals("") 
			    || (protocolSpecifier.equals("http://") && portSpecifier.equals("80"))
			    || (protocolSpecifier.equals("https://") && portSpecifier.equals("443")))
			{
				portSpecifier = "";
			}
			else
			{
				portSpecifier = ":" + portSpecifier;
			}

			//context path
			contextSpecifier = properties.getProperty("tomcat.context");
			if (contextSpecifier == null || contextSpecifier.equals("") || contextSpecifier.equals("/"))
			{
				contextSpecifier = "";
			}
			else
			{				
				if (!contextSpecifier.startsWith("/"))
				{
					contextSpecifier = "/" + contextSpecifier;
				}
			}

			//string it all together
			full_gsdl3_web_address = protocolSpecifier + hostSpecifier + portSpecifier + contextSpecifier;
			gsdl3_web_address = contextSpecifier;

			// Set the always available internal root address that is locally accessible (http://127.0.0.1:<httpPort>)
			// Used by solr. 
			String httpPort = properties.getProperty("localhost.port.http");
			localhost_http_web_address = properties.getProperty("localhost.protocol.http") + "://"
			    + properties.getProperty("localhost.server.http", "127.0.0.1"); // 127.0.0.1 better as fallback rather than localhost, since localhost can be modified and is therefore unsafe
			if(httpPort != null && !httpPort.equals("") && !httpPort.equals("80")) { // no need to check 443, *http*Port can't be 443
			    localhost_http_web_address = localhost_http_web_address + ":" + httpPort;
			}

			// set the http and https variants of the full web address, if they're meant to be available
			// First check the default protocol, then set the web address for the other protocol too
			String supportedProtocols = properties.getProperty("server.protocols", "http");
			String isHttpRestrictedToLocal = properties.getProperty("restrict.http.to.local", "true");

			if(protocolSpecifier.startsWith("https")) {
			    https_full_gsdl3_web_address = full_gsdl3_web_address;

			    // and set http version of URL, if http is made public (if http is in server.protocols list)
			    if(isHttpRestrictedToLocal.equals("false")) {				
				http_full_gsdl3_web_address = "http://" + hostSpecifier + httpPort + contextSpecifier;
			    }
			} else { // default protocol was http
			    http_full_gsdl3_web_address = full_gsdl3_web_address;

			    // and set https version, if https enabled
			    if(supportedProtocols.contains("https")) {
				String httpsPort = properties.getProperty("tomcat.port.https");
				https_full_gsdl3_web_address = "https://" + hostSpecifier + httpsPort + contextSpecifier;
			    }
			}
		}
		
}

