/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library 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
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Greg Richardson
 *  
 ***********************************************************************/

import java.io.*;
import java.util.*;

/**
 * Summary description for Program
 */
public class InitConfigFile
{
   final static int ERROR_NO_ERROR                    = 0;
   final static int ERROR_INVALID_NUMBER_OF_PARAMS    = -1;
   final static int ERROR_MISSING_TEMPLATE            = -3;
   final static int ERROR_MISSING_TEMPLATE_FILE       = -8;
   final static int ERROR_OUTPUT_PROPERTY_MISSING     = -9;
   final static int ERROR_OUTPUT_COPY_FAILED          = -12;
   final static int ERROR_IO_EXCEPTION                = -13;
   final static int ERROR_MISSING_PROPERTIES          = -15;
   final static int ERROR_UNABLE_TO_READ_PROPERTIES   = -16;
   final static int ERROR_PROPERTIES_FILE_IS_EMPTY    = -17;
   final static int ERROR_MISSING_INSTALL_DIR         = -18;
   final static int ERROR_INSTALL_DIR_NOT_A_DIR       = -19;
   final static int ERROR_BAD_INSTALL_DIR_PARAM       = -20;
   final static int ERROR_BAD_PROPERTY_FILE_PARAM     = -21;
   final static int ERROR_MISSING_PROPERTIES_FILE     = -22;
   final static int ERROR_MISSING_INSTALL_DIR_PARAM   = -23;
   final static int ERROR_MISSING_PROPERTY_FILE_PARAM = -24;
   final static int ERROR_BAD_TEMPLATE_FILE_PARAM     = -25;
   final static int ERROR_BAD_OUTPUT_FILE_PARAM       = -26;
   final static int ERROR_MISSING_TEMPLATE_FILE_PARAM = -27;
   final static int ERROR_MISSING_OUTPUT_FILE_PARAM   = -28;
   final static int ERROR_BAD_PROPERTY_PARAM          = -29;
   final static int ERROR_UNABLE_TO_OPEN_TEMPLATE     = -30;
   final static int ERROR_FILEWRITER_CREATE_FAILED    = -31;

   final static String TEMPLATE_FILE_PARAM   = "template=";
   final static String OUTPUT_FILE_PARAM     = "output=";
   final static String INSTALL_DIR_PARAM     = "ATS_INSTALL_DIR=";
   final static String INSTALL_DIR_PROPERTY  = "ATS_INSTALL_DIR";
   final static String PROPERTY_FILE_PARAM   = "propertyfile=";
   final static String ESCAPE_PATH_CHARS     = "escape_path_chars=";

   Properties        properties;
   File              fileProperties;
   FileInputStream   fisProperties;
   File              fileTemplate;
   File              fileOutput;
   File              file;
   //FileWriter      fw;
   RandomAccessFile  raf;
   String[]          rgsSearchFor;
   String[]          rgsReplaceWith;
   String            sInstallDir;
   String            sTemplate;
   String            sOutput;
   int               rc;
   boolean           escapePathCharsInReplaceString = false;

   public static void main(String[] args)
   {
      InitConfigFile p = new InitConfigFile(args);
      System.exit(p.rc);
   }

   InitConfigFile(String[] args)
   {
      rc = ERROR_NO_ERROR;

      properties = new Properties();
      fileProperties = null;
      fisProperties = null;
      fileTemplate = null;
      fileOutput = null;

      try
      {
         file = new File("c:\\test.log");
         //fw = new FileWriter(file);

         raf = new RandomAccessFile(file, "rw");
         raf.seek(raf.length());

         // Process the arguments
         if (ERROR_NO_ERROR == (rc = processArgs(args)))
         {
            // Process the properties
            if (ERROR_NO_ERROR == (rc = processProperties()))
            {
               rc = createOutputFile();
            }
         }

      }
      catch (IOException e)
      {
         rc = ERROR_IO_EXCEPTION;
      }
      finally
      {
         try
         {
            log(rc, "  " + sOutput + "\n\n\n");
            raf.close();
         }
         catch (Exception e1)
         {
         }
      }
   }

   int processArgs(String[] argsOld)
   {
      String sProperties;
      File fileInstallDir = null;
      int iEquals;
      String sKey;
      String sValue;
      int iOld;
      int i;
      String args[] = new String[argsOld.length];
      int iNew;

      log("Original arg count " + argsOld.length);
      for (i = 0; i < argsOld.length; i++)
      {
         log("Arg " + i + " = " + argsOld[i] + "\r\n");
      }

      // Validate the number of parameters
      if (argsOld.length < 2)
      {
         return ERROR_INVALID_NUMBER_OF_PARAMS;
      }

      iNew = -1;
      for (iOld = 0; iOld < argsOld.length; iOld++)
      {
         if (0 <= argsOld[iOld].indexOf("="))
         {
            iNew++;
            args[iNew] = argsOld[iOld];
            for (i = iOld + 1; i < argsOld.length && (-1 == argsOld[i].indexOf("=")); i++)
            {
               args[iNew] += " " + argsOld[i];
            }
         }
      }

      log("New arg count " + args.length);
      for (i = 0; i < args.length; i++)
      {
         if (null == args[i])
         {
            continue;
         }

         log("arg[" + i + "] = " +args[i]);

         // is this the install dir param?
         if (args[i].startsWith(INSTALL_DIR_PARAM))
         {
            // Make sure it is more the the param tag
            if (args[i].length() <= INSTALL_DIR_PARAM.length())
            {
               return ERROR_BAD_INSTALL_DIR_PARAM;
            }

            sInstallDir = args[i].substring(INSTALL_DIR_PARAM.length()).trim();
            fileInstallDir = new File(sInstallDir);

            // Make sure the install dir can be found
            if (!fileInstallDir.exists())
            {
               return ERROR_MISSING_INSTALL_DIR;
            }

            // Make sure the install dir is a directory
            if (!fileInstallDir.isDirectory())
            {
               return ERROR_INSTALL_DIR_NOT_A_DIR;
            }

            log("Adding property (key = " + INSTALL_DIR_PROPERTY + " - value = " + sInstallDir);
            properties.setProperty(INSTALL_DIR_PROPERTY, sInstallDir);
         }

         // is this the properties file param?
         else if (args[i].startsWith(PROPERTY_FILE_PARAM))
         {
            // Make sure it is more than the param tag
            if (args[i].length() <= PROPERTY_FILE_PARAM.length())
            {
               return ERROR_BAD_PROPERTY_FILE_PARAM;
            }

            sProperties = args[i].substring(PROPERTY_FILE_PARAM.length()).trim();
            fileProperties = new File(sProperties);

            // Make sure the properties file can be found
            if (!fileProperties.exists())
            {
               return ERROR_MISSING_PROPERTIES_FILE;
            }

            // Read the properties
            try
            {
               fisProperties = new FileInputStream(fileProperties);
               properties.load(fisProperties);
            }
            catch (IOException ioe)
            {
               return ERROR_UNABLE_TO_READ_PROPERTIES;
            }
         }

         else if (args[i].startsWith(TEMPLATE_FILE_PARAM))
         {
            // Make sure it is more than the param tag
            if (args[i].length() <= TEMPLATE_FILE_PARAM.length())
            {
               return ERROR_BAD_TEMPLATE_FILE_PARAM;
            }

            sTemplate = args[i].substring(TEMPLATE_FILE_PARAM.length()).trim();
            fileTemplate = new File(sTemplate);

            // Make sure the template file can be found
            if (!fileTemplate.exists())
            {
               log(ERROR_MISSING_TEMPLATE_FILE, sTemplate);
               return ERROR_MISSING_TEMPLATE_FILE;
            }
         }

         else if (args[i].startsWith(OUTPUT_FILE_PARAM))
         {
            // Make sure it is more than the param tag
            if (args[i].length() <= OUTPUT_FILE_PARAM.length())
            {
               return ERROR_BAD_OUTPUT_FILE_PARAM;
            }

            sOutput = args[i].substring(OUTPUT_FILE_PARAM.length()).trim();
            fileOutput = new File(sOutput);
         }

         else if (args[i].startsWith(ESCAPE_PATH_CHARS))
         {
            // Make sure it is more than the param tag
            if (args[i].length() <= OUTPUT_FILE_PARAM.length())
            {
               return ERROR_BAD_OUTPUT_FILE_PARAM;
            }

            String value = args[i].substring(OUTPUT_FILE_PARAM.length()).trim();
            if (value.equalsIgnoreCase("true"))
            {
                escapePathCharsInReplaceString = true;
            }
         }

         // Handle additional parameters
         else
         {
            if (-1 == (iEquals = args[i].indexOf("=")) ||
               0 == iEquals ||
               args[i].length() == iEquals)
            {
               return ERROR_BAD_PROPERTY_PARAM;
            }
            sKey = args[i].substring(0, iEquals);
            sValue = args[i].substring(iEquals + 1);
            log("Adding property (key = " + sKey + " - value = " + sValue);
            properties.setProperty(sKey, sValue);
         }
      }

      // Make sure we got an install dir
      if (null == fileInstallDir)
      {
         return ERROR_MISSING_INSTALL_DIR_PARAM;
      }

      // Make sure we got a template file
      if (null == fileTemplate)
      {
         return ERROR_MISSING_TEMPLATE_FILE_PARAM;
      }

      // Make sure we got an output file
      if (null == fileOutput)
      {
         return ERROR_MISSING_OUTPUT_FILE_PARAM;
      }

      // Note: the properties file parameter is optional

      return ERROR_NO_ERROR;
   }

   int processProperties()
   {
      try
      {
         Enumeration e;
         String sKey;
         String sValue;
         int i = 0;

         e = properties.propertyNames();

         rgsSearchFor = new String[properties.size()];
         rgsReplaceWith = new String[properties.size()];

         log("property count = " + properties.size());
         while (e.hasMoreElements())
         {
            sKey = (String)e.nextElement();
            sValue = (String)properties.get(sKey);

            log("Property key = " + sKey + "  Value = " + sValue);

            rgsSearchFor[i] = sKey;
            if (escapePathCharsInReplaceString)
            {
               rgsReplaceWith[i] = sValue.replace("\\", "\\\\");
            }
            else
            {
               rgsReplaceWith[i] = sValue;
            }
            i++;
         }
      }
      catch (Exception ex1)
      {
         return -111;
      }

      return ERROR_NO_ERROR;
   }

   int createOutputFile()
   {
      LineNumberReader lnr = null;
      FileWriter fwOutput = null;
      String sLineTemplate;
      String sLineOutput;
      int iSearchFor;
      int i;

      try
      {
         // Open the files
         lnr = new LineNumberReader(new FileReader(fileTemplate));
      }
      catch (Exception e)
      {
         return ERROR_UNABLE_TO_OPEN_TEMPLATE;
      }

      try
      {
         fwOutput = new FileWriter(fileOutput);
      }
      catch (Exception e)
      {
         return ERROR_FILEWRITER_CREATE_FAILED;
      }
      try
      {
         // For each line of text in the template file...
         while (null != (sLineTemplate = lnr.readLine()))
         {
            sLineOutput = sLineTemplate;
            log("<-- " + sLineOutput);

            // For each term to be replaced...
            for (i = 0; i < rgsSearchFor.length; i++)
            {
               log("searching for " + rgsSearchFor[i]);
               // Replace all instances of the term on the line
               while (-1 != (iSearchFor = sLineOutput.indexOf(rgsSearchFor[i])))
               {
                  log("replacing " + rgsSearchFor[i] + " at position " + iSearchFor + " with " + rgsReplaceWith[i]);
                  sLineOutput = sLineOutput.substring(0, iSearchFor) + rgsReplaceWith[i] +
                        sLineOutput.substring(iSearchFor + rgsSearchFor[i].length());
               }
            }
            try
            {
               fwOutput.write(sLineOutput + "\r\n");
               log("--> " + sLineOutput);
            }
            catch (Exception e)
            {
               return -42;
            }
         }

         // Clean up
         fwOutput.flush();
         fwOutput.close();
         lnr.close();
      }
      catch (Exception e)
      {
         return ERROR_OUTPUT_COPY_FAILED;
      }
      return ERROR_NO_ERROR;
   }

   void log(int err)
   {
      log(err, null);
   }

   void log(int err, String s)
   {
      String sMessage = "";

      switch (err)
      {
         case ERROR_NO_ERROR:
            sMessage = "No error";
            break;
         case ERROR_INVALID_NUMBER_OF_PARAMS:
            sMessage = "Invalid number of parameters: 4 expected";
            break;
         case ERROR_MISSING_TEMPLATE:
            sMessage = "Template file not found";
            break;
         case ERROR_OUTPUT_PROPERTY_MISSING:
            sMessage = "Output file parameter missing";
            break;
         case ERROR_OUTPUT_COPY_FAILED:
            sMessage = "Unable to create output file";
            break;
         case ERROR_IO_EXCEPTION:
            sMessage = "IOException";
            break;
         case ERROR_MISSING_PROPERTIES:
            sMessage = "Properties file not found";
            break;
         case ERROR_MISSING_TEMPLATE_FILE:
            sMessage = "Missing template file";
            break;
         case ERROR_PROPERTIES_FILE_IS_EMPTY:
            sMessage = "Properties file is empty";
            break;
         case ERROR_MISSING_INSTALL_DIR:
            sMessage = "Missing install dir";
            break;
         case ERROR_INSTALL_DIR_NOT_A_DIR:
            sMessage = "Install directory is not a directory";
            break;
         case ERROR_BAD_INSTALL_DIR_PARAM:
            sMessage = "Bad install directory parameter";
            break;
         case ERROR_BAD_PROPERTY_FILE_PARAM:
            sMessage = "Bad property file parameter";
            break;
         case ERROR_MISSING_PROPERTIES_FILE:
            sMessage = "Missing properties file";
            break;
         case ERROR_MISSING_INSTALL_DIR_PARAM:
            sMessage = "Missing install directory parameter";
            break;
         case ERROR_MISSING_PROPERTY_FILE_PARAM:
            sMessage = "Missing property file parameter";
            break;
         case ERROR_BAD_TEMPLATE_FILE_PARAM:
            sMessage = "Bad template file parameter";
            break;
         case ERROR_BAD_OUTPUT_FILE_PARAM:
            sMessage = "Bad output file parameter";
            break;
         case ERROR_MISSING_TEMPLATE_FILE_PARAM:
            sMessage = "Missing template file parameter";
            break;
         case ERROR_MISSING_OUTPUT_FILE_PARAM:
            sMessage = "Missing output file parameter";
            break;
         case ERROR_BAD_PROPERTY_PARAM:
            sMessage = "Bad property parameter";
            break;
         case ERROR_UNABLE_TO_READ_PROPERTIES:
            sMessage = "Unable to read properties file";
            break;
         case ERROR_UNABLE_TO_OPEN_TEMPLATE:
            sMessage = "Unable to open template";
            break;
         case ERROR_FILEWRITER_CREATE_FAILED:
            sMessage = "FileWriter create failed";
            break;
         default:
            sMessage = "Unknown error: " + err;
            break;
      }

      if (null != s)
      {
         sMessage = sMessage + s;
      }
      log(sMessage);
   }

   void log(String s)
   {
      try
      {
         raf.writeUTF(this.getClass().getName() + ": " + s + "\r\n");
      }
      catch (IOException ioe)
      {
      }
   }
}