/*
 *    LibraryAddressProperties.java
 *    Copyright (C) 2024 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.gatherer.greenstone3;

import java.util.Properties;

/*
 * This uses properties from the build.properties Properties instance provided to generate the 
localhost http address, and the external http/https address. 
 */
public class LibraryAddressProperties {   

    private static final String FALLBACK_PROTOCOL = "http";
    private static final String FALLBACK_HTTP_PORT = "8383";
    private static final String FALLBACK_HTTPS_PORT = "8443";

    private String defaultPortPropertyName = "localhost.port.http";
    private String localHttpURL;
  private String externalURL;

/*    // default protocol if multiple supported
    public String getProtocol() { return protocol; } 
    // default port (port for default protocol)
    public String getPort() { return port; }

    // httpPort is always set, but http may or may not be public
    public String getHttpPort() { return httpPort; }
    // httpsPort is null if https not supported
    public String getHttpsPort() { return httpsPort; }
    public int getPortNum() { return Integer.parseInt(port); }  

    // http is always available locally (over 127.0.0.1). But http may or may not be public.
    // Returns true if public http support requested
    public boolean supportsHttp() { return !httpRestrictedToLocal; }
    // true if https is supported
    public boolean supportsHttps() { return supportsHttps; }

    // used by Server3.java to know the name of the port property to load
    public String getDefaultPortPropertyName() { return defaultPortPropertyName; }

    public String getErrorMsg() { return errorMsg; }
    public int getErrorCode() { return errorCode; }

    public boolean hadError() { return errorCode != ALL_CORRECT; }
*/
  //public String getErrorMsg() { return errorMsg; }
    // returns the local http base URL, something like http://127.0.0.1:<httpPort>
    public String getLocalHttpAddress() {
	return localHttpURL;	
    }

  public String getExternalAddress() {
    return externalURL;
  }

    public LibraryAddressProperties(Properties props) 
    {
	StringBuffer msg = new StringBuffer();

        String protocol = null;
        String port = null;
        String httpPort = null;
        String httpsPort = null;

        // not used currently
        boolean httpRestrictedToLocal = true;
        boolean supportsHttps = false;

	httpPort = props.getProperty("localhost.port.http");
	if(httpPort == null || httpPort.equals("")) {
	    msg.append("compulsory property localhost.port.http has no value (must be set to a valid port number not already in use). Falling back to "+FALLBACK_HTTP_PORT);
	    httpPort = FALLBACK_HTTP_PORT;
	}

	String supportedProtocols = props.getProperty("server.protocols");
	if(supportedProtocols == null || supportedProtocols.equals("")) {
	    msg.append("\nserver.protocols not set. Falling back to " +FALLBACK_PROTOCOL);
	    protocol = FALLBACK_PROTOCOL; // fallback to http as default (and sole) protocol
	    port = httpPort; // set default port to httpPort
	}
	else { // supportedProtocols was assigned something

	    if(!supportedProtocols.contains("http")) {
		msg.append("server.protocols must contain http or https, or both (in order of preference) separated by commas. Falling back to  "+FALLBACK_PROTOCOL);
		protocol = FALLBACK_PROTOCOL;
		port = httpPort;
	    } 

	    // set available protocols with their ports
	    if(supportedProtocols.contains("https")) {
		supportsHttps = true;
		httpsPort = props.getProperty("tomcat.port.https");
		if(httpsPort == null || httpsPort.equals("")) {
		    msg.append("server.protocols includes https but property tomcat.port.https has no value (must be set to a valid port number not already in use). Falling back to "+FALLBACK_HTTPS_PORT);
		    httpsPort = FALLBACK_HTTPS_PORT;
		}
	    }
	    if(supportedProtocols.matches("http(,|\\s+|$)")) {
		httpRestrictedToLocal = false;
	    }
	
	    // set default protocol and default port: the first protocol in the supportedProtocols list
	    if(supportedProtocols.matches("^[,\\s]*https")) {
		protocol = "https";
		port = httpsPort;		
	    } else {
		protocol = "http";
		port = httpPort;
	    }
	}

        String greenstone_context = props.getProperty("greenstone.context", "greenstone3");
        boolean use_revproxy = false;
        String revproxy_domain = props.getProperty("revproxy.domain");
        String revproxy_protocol = props.getProperty("revproxy.protocol");
        String revproxy_port = props.getProperty("revproxy.opt_port");
        String revproxy_context = props.getProperty("revproxy.context");
        if (revproxy_domain != null && revproxy_domain.equals("")) {
          use_revproxy = true;
          if (!revproxy_protocol.matches("^https?$")) {
              msg.append("\nInvalid revproxy.protocol, setting it to https");
              revproxy_protocol = "https";
          }
          if (revproxy_context == null || revproxy_context.equals("")) {
            revproxy_context = greenstone_context;
          }
          if (revproxy_port == null || revproxy_port.equals("")) {
            revproxy_port = null;
          }
        }
        // now check whether port values are numbers
        if(httpPort != null) {
          try {
            Integer.parseInt(httpPort);
          } catch(NumberFormatException nfe) {
            msg.append("\nInvalid localhost.port.http specified: must be numeric.");
            if(port == httpPort) {
              port = httpPort = FALLBACK_HTTP_PORT; // recovery values that can work with default protocol			
            } else { // secondary protocol's port is non-numeric, not fatal
              httpPort = null;
              msg.append("\nNot using this port");
            }
          }
        }
	
        if(httpsPort != null) {
          try {
            Integer.parseInt(httpsPort);
          } catch(NumberFormatException nfe) {
            msg.append("\nInvalid port specified for over https (tomcat.port.https): must be numeric.");
            if(port == httpsPort) {
              port = httpsPort = FALLBACK_HTTPS_PORT; // recovery values that work with default protocol	
            } else { // non primary port is invalid/non-numeric, not fatal 
              httpsPort = null;
              msg.append("\nNot using this port");
            }
          }
        }
        if(use_revproxy && revproxy_port != null) {
          try {
            Integer.parseInt(revproxy_port);
          } catch(NumberFormatException nfe) {
            msg.append("\nInvalid port specified for revproxy.opt_port: must be numeric.");
            msg.append("\nSetting it to be empty.");
            revproxy_port = null;
          }
        }
      
	// if the default port is the httpsPort, then modify the defaultPortPropertyName to match
	// (else it will remain at the property name for the http port)
	if(port == httpsPort) {
	    defaultPortPropertyName = "tomcat.port.https";
	}
        
        msg.append("\nUsing port ").append(port).append(" and protocol ").append(protocol).append(".");
	

        // ok, wev'e checked all the values, now generate the two urls

        
        
	// Setting the internal/local access url, which has to be over http (see
	// https://letsencrypt.org/docs/certificates-for-localhost/)
	// localhost.server.http defaults to 127.0.0.1 instead of localhost, since
	// localhost is unsafe as it can be mapped to something other than 127.0.0.1.
	localHttpURL = "http://" + props.getProperty("localhost.server.http", "127.0.0.1");
	if(!httpPort.equals("80")) {
          localHttpURL = localHttpURL + ":" + httpPort; 
	}
      localHttpURL += "/" + greenstone_context;


        if (use_revproxy) {
          String opt_port_string = "";
          if (revproxy_port != null) {
            opt_port_string = ":"+revproxy_port;
          }
          externalURL = revproxy_protocol+"://"+revproxy_domain+opt_port_string+"/"+revproxy_context;
        } else {
          externalURL = protocol+"://"+props.getProperty("tomcat.server", "127.0.0.1")+":"+port+"/"+greenstone_context;
        }

        System.err.println("LibraryAddressProperties Initialisation info/errors:");
        System.err.println(msg.toString());
    }
}
    

