package com.idega.core.ldap.client.cbutil;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;

/**
 *   <p>Sun, in their fairly limited wisdom, decided to disable
 *   the ability to get system environment variables in java.
 *   (Apart from a couple that they kindly decided to let through
 *   that are fairly useless).  Apparently it wasn't platform
 *   independent enough, and might have screwed up their revenue
 *   stream.  Or something.</p>
 *
 *   <p>Anyway, this class contains a filthy hack to get the
 *   information anyway, come hell, Sun, or high water.  
 *   basically it shells a 'set' command, and attempts to do
 *   this on both unix and windows.</p>
 *
 *   <p>This is needed by some JX plugins, that rely on user-set system
 *   environment variables to do stuff.</p>
 */
 
public class CBSystemProperties
{
    private static boolean debug = false;
    
    public static void setDebug(boolean status) 
    {
        debug = status;
    }
    
    /**
     *    A simple minded test to see if we are running on a windows machine.
     *    @return true if on windows, false if not.
     */
             
    public static boolean isWindows()
    {
        String os = System.getProperty("os.name");
        if (os != null && os.toLowerCase().indexOf("windows") > -1) 
        {
            if (debug) {
				System.out.println("this is a windows machine.");
			}
            return true;
        }   
         
        if (debug) {
			System.out.println("this is a unix machine.");
		}
        return false;
    }
    
    
    /**
     *    This writes a file called 'runset.bat' (or 'runset.sh' on unix)
     *    that can then be 'exec'-ed to read the system property list.
     *    @param batchFileName - the name of the batch file to create, e.g. 'runset.bat' or 'runset.sh'
     */
     
    private static void writeBatchFile(String batchFileName)
        throws IOException
    {                            
        File setBatch = new File(batchFileName); 
        
        // only write the batch file once.
        if (setBatch.exists() == false)
        {   
            FileWriter out = new FileWriter(setBatch);
            out.write("set", 0, 3);
            out.flush();
            out.close();
        }            
    }
    
    /**
     *    Cleans up - deletes the batch file afterwards...
     *    @param batchFileName - the name of the batch file to delete, e.g. 'runset.bat' or 'runset.sh'
     */
     
    private static void deleteBatchFile(String batchFileName)
    {
        File setBatch = new File(batchFileName);
        
        // nb. - catch exception locally, since this is not
        // fatal; if everything else has worked we probably 
        // don't care if we can't clean up.
        try
        {
            setBatch.delete();
        }    
        catch (Exception e)
        {
            CBUtility.log("unable to delete batch file " + batchFileName + "\n" + e); 
        }
    }
    
    /**
     *    This takes the batch file generated by writeBatchFile() and
     *    exec()s it to read the system dependent list of properties. 
     *    (which is then added to the java system properties list...)
     *    @param batchFileName - the name of the batch file to use, e.g. 'runset.bat' or 'runset.sh'
     */
     
    private static void readSystemProperties(String batchFileName)  
        throws IOException     
    {            
        // use the batch file...
        Process bloop = Runtime.getRuntime().exec(batchFileName);
        
        BufferedReader input = new BufferedReader(new InputStreamReader(bloop.getInputStream()));
        BufferedReader errors = new BufferedReader(new InputStreamReader(bloop.getErrorStream()));
        
        // run through the batch file, spliting names and value on the '=' sign
        // (e.g DXHOME=c:\dxserver => DXHOME  and 'c:\dxserver' )
        
        String line = "";
        //int pos;
        
        if (debug) {
			System.out.println("reading output from batch file");
		}

        setSystemPropertiesFromBufferedReader(input);


        while ((line = errors.readLine()) != null)
        {
            System.out.println("ERRORS: " + line);
        }
        
        
    }

    private static void setSystemPropertiesFromBufferedReader(BufferedReader input) throws IOException
    {
        String line;
        int pos;
        String name;
        String value;
        while ((line = input.readLine()) != null)
        {
            if (debug) {
				System.out.println("read raw line: " + line);
			}

            if ((pos=line.indexOf('='))>0)
            {
                name = line.substring(0, pos);
                if (line.length()>pos) {
					value = line.substring(pos+1).trim();
				}
				else {
					value = "";
				}


                if (System.getProperty(name) == null)
                {
                    System.setProperty(name, value);
                    if (debug) {
						System.out.println("SET setting property '" + name + "' equal '" + value + "'");
					}
                }
                else
                    if (debug) {
						System.out.println("skipping existing value for: " + name);
					}

            }
        }
    }

    /**
     * for debugging - dumps the full system properties list...
     */    
     
    private static void dumpProperties()
    {
    
        Enumeration keys = System.getProperties().propertyNames();
        while (keys.hasMoreElements())
        {
            String key = (String)keys.nextElement();
            System.out.println(debug + "SYSPROPS: " + key + " : " + System.getProperty(key));
        }
    }

    /**
     *   This method relies on the system properties having been pre-written to
     *   a particular file (in the normal 'property=value' format used by both
     *   java properties files, and the results of 'set' on unix and windows).
     *   If it fails to find this property file, it will revert to trying to
     *   automatically run 'set' using the other 'loadSystemProperties()'
     *   method below.
     */
    public static boolean loadSystemProperties(File propertiesListFile)
    {
        if (propertiesListFile.exists() == false)
        {
            CBUtility.log("Unable to find system properties file: '" + propertiesListFile.toString() + "' - attempting batch load instead");
            return loadSystemProperties();
        }

        try
        {
            setSystemPropertiesFromBufferedReader(new BufferedReader(new FileReader(propertiesListFile)));
            if (debug) {
				dumpProperties();
			}

            return true;
        }
        catch (IOException e)
        {
            CBUtility.log("Error trying to load system properties file '" + propertiesListFile.toString() + "' - - attempting batch load instead.\n(error was: "+ e.toString() + ")");
            return loadSystemProperties();
        }
    }

    /**
     *    This method reads the system environment property list,
     *    and adds them directly to the System.getProperties() 
     *    global property list.
     *    
     *    @return whether the operation was successfull, or
     *    whether an error (usually an IOException) occurred.
     */
     
    public static boolean loadSystemProperties()
    {
        try
        {
            // get a batch (or shell) script name
            // nb - don't call it 'set.bat' -> fails on nt!
            String batchFileName = isWindows()?"runset.bat":"runset.sh";
            
            
            // write it out with the single command 'set' inside...
            writeBatchFile(batchFileName);
            
            // execute it, to read the system properties, and append
            // them to the global system list...
            readSystemProperties(batchFileName);
    
            // for debugging, dump the list of read properties...
            if (debug) {
				dumpProperties();
			}
                
            // cleanup - delete the file...
            deleteBatchFile(batchFileName);                
            
            return true;
        }
        catch (Exception e)
        {
            CBUtility.log("Error reading system properties...\n" + e);
            // In this case calling programs should either make 
            // inspired guesses, or prompt users for missing values.
            
            return false;
        }
    }
    
    /**
     *    Main method for stand alone testing.
     *    @param argsv - not used.
     */
    
    public static void main(String argsv[])
    {
        setDebug(true);
        loadSystemProperties();
    }
    
}