/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.core.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.regex.Pattern;


/**
 * @author martin.heinemann@tudor.lu
 * 28.03.2008
 * 09:16:58
 *
 *
 * @version
 * <br>$Log: ServerConfig.java,v $
 * <br>Revision 1.14  2014-01-09 10:26:49  ferring
 * <br>URI read correctly to handle spaces in filename
 * <br>
 * <br>Revision 1.13  2013-11-12 12:48:22  donak
 * <br>Document upload:
 * <br>* conversion to pdf/a using open office has been moved to the server. OpenOffice 4 has to be located in the jboss work directory. ATTENTION: it still has to be evaluated if the license agreement dialog occurs when instance is started the first time on the server.
 * <br>* If document contains a description, the first forty characters of the description followed by three dots will be used as title instead of the filename
 * <br>* Upload of incident type letters has been fixed
 * <br>* upload for docx files has been added
 * <br>
 * <br>Upload parameters:
 * <br>* database does now support storage of user dependent properties
 * <br>* The system will automatically remember the last chosen values for confidentiality, facility type, and speciality and propose them as default when the next document will be uploaded.
 * <br>
 * <br>Inactivity Monitor:
 * <br>* the event mouse wheel scrolling is now taken into account for resetting the logoff timer
 * <br>* the logoff delay is now stored in the database. If the database does not contain this parameter, it will be created
 * <br>
 * <br>General:
 * <br>* Optimized incident entry bean handling. Caching will now avoid copying the binary content and the generated pdf content of an incident entry as these elements should only be loaded when needed. Now it should be save to re-implement a proper getBinaryContent() handling.
 * <br>
 * <br>Revision 1.12  2013-07-19 13:39:47  ferring
 * <br>LABO_DIR not used
 * <br>
 * <br>Revision 1.11  2013-05-08 14:30:35  ferring
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.10  2010-06-24 13:14:50  hermen
 * <br>Incomplete - # 498: Robusterere File URI für die Fille-Attach Operation
 * <br>http://santec.tudor.lu/trac/gecamed/ticket/498
 * <br>
 * <br>Revision 1.9  2010-04-20 07:24:39  hermen
 * <br>added show server log to tools menu
 * <br>
 * <br>Revision 1.8  2009-05-29 13:51:21  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.7  2009-05-13 13:20:58  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.6  2009-05-13 12:54:01  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.5  2009-05-08 07:59:27  hermen
 * <br>open help website on firstrun
 * <br>
 * <br>Revision 1.4  2008-11-25 16:29:33  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.3  2008-09-25 09:43:06  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.2  2008-04-14 12:39:02  hermen
 * <br>fixed small path bug
 * <br>
 * <br>Revision 1.1  2008-03-28 13:29:24  heinemann
 * <br>*** empty log message ***
 * <br>
 *   
 */

public class ServerConfig {
	
	
	/** the logger Object for this class */
	private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ServerConfig.class.getName());
	
	/**
	 * The file where the properties are stored
	 */
	public static final String PROPERTY_FILE = "gecamed_server.properties";
	
	/**
	 * The dir of the config files
	 */
	public static final String CONFIG_URI 	 = System.getProperty("jboss.server.config.url").replaceAll(" ", "%20");
	
	
	/**
	 * The dir of the config files
	 */
//	public static final String CONFIG_DIR 	 = CONFIG_URI.replaceAll("file:\\\\", "").replaceAll("file:", "");
	
	/**
	 * The home-dir of the jboss
	 */
	public static final String JBOSS_DIR  = getFileForUri(CONFIG_URI).getParentFile().getParentFile().getParent().replaceAll("file:\\\\", "").replaceAll("file:", "");
	
	/**
	 * The home-dir of the Open Office 4 installation, relative to the {@link #JBOSS_DIR}
	 */
//	private static final String OPEN_OFFICE_BASE_DIR  = "/server/default/work/OpenOffice4/";
	public static final String OPEN_OFFICE_BASE_DIR  = "/OpenOffice4/";
	
	/**
	 * The home-dir of the gecamed installation
	 */
	public static final String GECAMED_DIR  = getGECAMedDir();
	
	
	/**
	 * Username of the uses database
	 */
	public static final String DB_USERNAME 		 = "DB_USERNAME";
	/**
	 * Password for the database
	 */
	public static final String DB_PASSWORD 		 = "DB_PASSWORD";
	/**
	 * Script that will do the backup
	 */
	public static final String DB_BACKUP_SCRIPT  = "DB_BACKUP_SCRIPT";
	/**
	 * Folder in which the backup files will be stored
	 */
	public static final String DB_BACKUP_DIR     = "DB_BACKUP_DIR";
	
	/**
	 * Base dir to store files
	 */
	public static final String FILE_BASE_DIR 	 = "FILE_BASE_DIR";
	
	/**
	 * Folder for files related to patients
	 */
	public static final String PATIENT_FILES_DIR = "PATIENT_FILES_DIR";
	
	/**
	 * Folder for letter templates etc
	 */
	public static final String TEMPLATE_DIR 	 = "TEMPLATE_DIR"; 
	
	/**
	 * Folder to store dicom files
	 */
	public static final String DICOM_DIR		 = "DICOM_DIR";
	
//	/**
//	 * Folder to store labo files like the root certificates
//	 */
//	public static final String LABO_DIR			 = "LABO_DIR";
	
	private static final String	LOCALHOST = "localhost";
	private static Pattern	IPV4_PATTERN;
	private static Pattern	IPV4_LOCALHOST_PATTERN;
	private static Pattern	IPV6_LOCALHOST_PATTERN;
	
	
	public static String openOfficeDir;
	
	private static Properties properties;
	
	
	private static void loadProperties() {
		/* ------------------------------------------------------- */
		properties = new Properties();
		try {
			File fileConfigDir = new File(new URI(CONFIG_URI));
			File fileConfigFile = new File(fileConfigDir, PROPERTY_FILE);
			properties.load(new FileInputStream(fileConfigFile));
			
			/* ------------------------------------------------------- */
			String fileBaseDir = getProperty(FILE_BASE_DIR);
			
			/* ------------------------------------------------------- */
			for (Object key : properties.keySet()) {
				/* ------------------------------------------------------- */
				String prop = properties.getProperty((String) key);
				if (prop == null)
					continue;
				/* ------------------------------------------------------- */
				prop = prop.replaceAll("\\$"+FILE_BASE_DIR, fileBaseDir);
				// remove double slashes
				prop = prop.replaceAll("//", "/");
				properties.setProperty((String) key, prop);
				/* ------------------------------------------------------- */
			}
			
			
			/* ------------------------------------------------------- */
		} catch (URISyntaxException e) {
			e.printStackTrace();
			properties = null;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			properties = null;
		} catch (IOException e) {
			e.printStackTrace();
			properties = null;
		}
		/* ------------------------------------------------------- */
	}
	
	
	private static String getGECAMedDir ()
	{
		try
		{
			if (GECAMedUtils.getOS() == GECAMedUtils.OS_LINUX)
			{
				// this is the linux GECAMed dir
				File f = new File("/usr/share/gecamed");
				if (f.exists())
				{
					return f.getAbsolutePath();
				}
				else
				{
					logger.warn("Default GECAMed home dir \"/usr/share/gecamed\" seems not to exist.");
					return new File(JBOSS_DIR).getParent().replaceAll("file:\\\\", "").replaceAll("file:", "");
				}
			}
			else
				// for all other OS, the JBoss dir is a subfolder of the GECAMed dir
				return new File(JBOSS_DIR).getParent().replaceAll("file:\\\\", "").replaceAll("file:", "");
		}
		catch (Exception e)
		{
			logger.error("Error while trying to set thte GECAMed Dir", e);
			return System.getProperty("user.dir");
		}
	}


	private static File getFileForUri (String uri)
	{
		File file;
		
		try
		{
			file = new File(new URI(CONFIG_URI));
		}
		catch (URISyntaxException uriSE)
		{
			try
			{
				file = new File(uri);
			}
			catch (Exception e)
			{
				logger.error("Couldn't create file from URI: " + uri, uriSE);
				file = null;
			}
		}
		
		return file;
	}


	public static String getServerLog() {
	    StringBuffer sb = new StringBuffer();
	    try {
		File logDir = new File(JBOSS_DIR + "/server/default/log");
		File logFile = new File(logDir, "server.log");
	        RandomAccessFile raf = new RandomAccessFile(logFile, "r");
	        
	        if (logFile.length() > (1024*1024*2))
	           raf.seek(logFile.length() - (1024*1024*2));
	        
	        String line = null;
	        do {
		    line = raf.readLine();
	            sb.append(line).append("\n");
		} while (line != null);
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	    return sb.toString();
	}
	
	
	
	
	/**
	 * Read the property from the gecamed_server.properties
	 * 
	 * @param key
	 * @return
	 */
	public static String getProperty(String key) {
		/* ================================================== */
		if (properties == null)
			loadProperties();
		if (properties.size() < 1) {
			return null;
		}
		/* ------------------------------------------------------- */
		return properties.getProperty(key);
		/* ================================================== */
	}


	public static String getOpenOfficeDir ()
	{
		if (openOfficeDir == null)
		{
			StringBuilder ood = new StringBuilder(JBOSS_DIR)
					.append(OPEN_OFFICE_BASE_DIR);
			if (GECAMedUtils.getOS() == GECAMedUtils.OS_MAC)
				ood.append("Contents/");
			openOfficeDir = ood.toString();
		}
		
		return openOfficeDir;
	}
	
	public static String[] getRMIIP() {
		String[] retVal = new String[4];
		try {
			String rmiAddress		= System.getProperty("java.rmi.server.codebase");
			retVal[0] = rmiAddress;
			rmiAddress = new URL(rmiAddress).getHost();
			retVal[1] = rmiAddress;
			InetAddress address = InetAddress.getByName(rmiAddress); 
			String rmiIP = address.getHostAddress();
			retVal[2] = rmiIP;
		} catch (Exception e) {
			retVal[3] =  "Error resolving RMI Codebase Hostname and IP Address!";
		}
		return retVal;
	}
	
	public static String checkRMIIP() {
		StringBuffer sb = new StringBuffer();
		
		String[] ips = getRMIIP();
		sb.append("RMI Codebase: \t\t" + ips[0] + "\n");
		sb.append("RMI Bind Name: \t\t" + ips[1] + "\n");
		sb.append("RMI Bind IP: \t\t" + ips[2] + "\n");

		if (ips[2] != null && ips[2].startsWith("127")) {
			sb.append("\nYour GECAMed Server is bound to Address: " + ips[2] + "\n" +
					"Meaning your Installation will only be usable from the Machine the GECAMed server is installed on!\n" +
					"GECAMed Clients on other machines will not be able to connect to your server!\n");
		}

		if (ips[3] != null && ips[3].length() > 0) {
			sb.append(ips[3]).append("\n");
		}

		return sb.toString();
	}
	
	public static String getJBossIPs()
	{
		
		StringBuffer sb = new StringBuffer();
		
		String bindAddress		= System.getProperty("jboss.bind.address");
		sb.append("JBoss Bind Address: " + bindAddress + "\n");
		
		sb.append("-----------------------------------" + "\n");
		
		sb.append(checkRMIIP());
		
		sb.append("-----------------------------------" + "\n");
		try {
			InetAddress addr =  InetAddress.getLocalHost();
			sb.append("Local Host Address: " + addr.getHostAddress() + " " + addr.getHostName() + " " + addr.getCanonicalHostName() + " " + (addr.isLoopbackAddress()?"=loopack":"") + "\n");
			
        	Enumeration<NetworkInterface> n = NetworkInterface.getNetworkInterfaces();
        	for (; n.hasMoreElements();)
        	{
        		NetworkInterface e = n.nextElement();
        		sb.append("Interface: " + e.getName() + "\n");
        		Enumeration<InetAddress> a = e.getInetAddresses();
        		for (; a.hasMoreElements();)
        		{
        			addr = a.nextElement();
        			sb.append("\t" + addr.getHostAddress() + " " + addr.getHostName() + " " + addr.getCanonicalHostName() + " " + (addr.isLoopbackAddress()?"=loopack":"") + "\n");
        		}
        	}	
		} catch (Throwable e) {
			sb.append("Error Listing Network Interfaces and IPs: " + e.getMessage());
		}
		
        return sb.toString();
	}
	
}
