/***********************************************************************
 * 
 *  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 <grichardson@novell.com>
 *  
 ***********************************************************************/


import java.lang.Throwable;
import java.lang.NullPointerException;
import java.util.*;
import java.net.*;
import java.io.*;
import java.util.zip.*;
import java.util.jar.*;

/**
 * Summary description for UpdateWarFile
 */
public class UpdateWarFile
{
   final static String INSTALL_DIR_PARAM = "ATS_INSTALL_DIR=";

   final static int ERROR_NO_ERROR                    = 0;
   final static int ERROR_IO_EXCEPTION                = -1;
   final static int ERROR_INVALID_NUMBER_OF_PARAMS    = -2;
   final static int ERROR_BAD_INSTALL_DIR_PARAM       = -3;
   final static int ERROR_MISSING_INSTALL_DIR         = -4;
   final static int ERROR_INSTALL_DIR_NOT_A_DIR       = -5;
   final static int ERROR_MISSING_INSTALL_DIR_PARAM   = -6;
   final static int ERROR_WAR_TEMPLATE_FILE_MISSING   = -7;
   final static int ERROR_NEW_JAR_CANNOT_BE_REPLACED  = -8;
   final static int ERROR_JAR_COPY_FAILED             = -9;
   final static int ERROR_CREATE_WAR_FILE_FAILED      = -10;
   final static int ERROR_CREATE_WAR_FOS_FAILED       = -11;
   final static int ERROR_OPEN_JAR_TEMPLATE_FAILED    = -12;
   final static int ERROR_JOS_FLUSH_FAILED            = -13;
   final static int ERROR_ADD_FILE_TO_JAR_FAILED      = -14;
   final static int ERROR_JOS_CLOSE_FAILED            = -15;
   final static int ERROR_FOS_CLOSE_FAILED            = -16; 
   final static int ERROR_JFTEMPLATE_CLOSE_FAILED     = -17;
   final static int ERROR_EXCEPTION                   = -18;

   String         sInstallDir;
   //File         file;
   //FileWriter      fw;
   int            rc;

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

   UpdateWarFile(String[] args)
   {
      sInstallDir = null;

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

         log("Here we go: " + args.length);
         for (int i = 0; i < args.length; i++)
         {
            log("Arg " + i + " = " + args[i]);
         }

         // Process the arguments
         if (ERROR_NO_ERROR == (rc = processArgs(args)))
         {
            // Create the modified war file
            rc = createWarFile();
         }
      }
      catch (Exception e)
      {
         rc = ERROR_EXCEPTION;
      }
      finally
      {
         try
         {
            log(rc);
            //fw.flush();
            //fw.close();
         }
         catch (Exception e1)
         {
         }
      }
   }

   int processArgs(String[] argsOld)
   {
      File fileInstallDir = null;
      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 (args.length < 1)
      {
         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++)
      {
         log("arg[" + i + "] = " + args[i]);

         // is this the install dir param?
         if (args[i].startsWith(INSTALL_DIR_PARAM))
         {
            // Make sure it is more than 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;
            }
         }
      }

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

      return ERROR_NO_ERROR;
   }

   int createWarFile()
   {
      String            sWarTemplate   = sInstallDir + "ats\\etc\\svc\\templates\\CasaAuthTokenSvc.war";
      String            sWarNew        = sInstallDir + "ats\\catalinabase\\webapps\\CasaAuthTokenSvc.war";
      File              fileWarTemplate   = new File(sWarTemplate);;
      File              fileWarNew     = new File(sWarNew);
      FileOutputStream  fosWarNew      = null;
      ZipOutputStream   josWarNew      = null;
      ZipFile           jfTemplate      = null;
      int               rc          = ERROR_NO_ERROR;
      
      // Ensure that the war template exists
      log("looking for war template: " + sWarTemplate);
      if (!fileWarTemplate.exists())
      {
         rc = ERROR_WAR_TEMPLATE_FILE_MISSING;
      }

      if (rc == ERROR_NO_ERROR)
      {
         // Ensure that the new jar name does not exist
         if (fileWarNew.exists())
         {
            log("war file already exists: " + sWarNew);
            if (!fileWarNew.delete())
            {
               log("could not delete war file: " + sWarNew);
               rc = ERROR_NEW_JAR_CANNOT_BE_REPLACED;
            }
         }
      }
         
      if (rc == ERROR_NO_ERROR)
      {
         // Create/open the new jar
         try
         {
            log("create new war file output stream: " + sWarNew);
            fosWarNew = new FileOutputStream(fileWarNew);
            josWarNew = new ZipOutputStream(fosWarNew);
         }
         catch (IOException ioe0)
         {
            log(ioe0.toString());
            rc = ERROR_CREATE_WAR_FOS_FAILED;
         }
      }

      if (rc == ERROR_NO_ERROR)
      {
         // Open the old jar
         try
         {
            jfTemplate = new ZipFile(sWarTemplate);
         }
         catch (IOException ioe1)
         {
            rc = ERROR_OPEN_JAR_TEMPLATE_FAILED;
         }
      }
         
      if (rc == ERROR_NO_ERROR)
      {
         // Transfer the files
         rc = moveFilesFromJarToJar(josWarNew, jfTemplate);
      }
         
      // Add the files
      if (rc == ERROR_NO_ERROR)
      {
         int i;
         String [] rgsFilesToAdd = new String[1];
         rgsFilesToAdd[0] = sInstallDir + "ats\\etc\\svc\\templates\\casa_crypto.properties";
         String [] rgsNames = new String[1];
         rgsNames[0] = "WEB-INF/classes/casa_crypto.properties";
         for (i = 0; i < rgsFilesToAdd.length; i++)
         {
            log("Adding file: " + rgsFilesToAdd[i] + " with name " + rgsNames[i]);
            rc = addFileToJar(rgsFilesToAdd[i], rgsNames[i], josWarNew);
         }
      }
         
      // Close up
      if (null != josWarNew)
      {
         try
         {
            josWarNew.flush();
         }
         catch (IOException ioe2)
         {
            rc = ERROR_JOS_FLUSH_FAILED;
         }
         try
         {
            josWarNew.close();
         }
         catch (IOException ioe3)
         {
            rc = ERROR_JOS_CLOSE_FAILED;
         }
         try
         {
            fosWarNew.close();
         }
         catch (IOException ioe4)
         {
            rc = ERROR_FOS_CLOSE_FAILED;
         }
      }
      if (null != jfTemplate)
      {
         try
         {
            jfTemplate.close();
         }
         catch (IOException ioe5)
         {
            rc = ERROR_JFTEMPLATE_CLOSE_FAILED;
         }
      }

      return rc;
   }

   int moveFilesFromJarToJar(ZipOutputStream josDst, ZipFile jfSrc)
   {
      int rc = ERROR_NO_ERROR;
      try
      {
         Enumeration         entries = jfSrc.entries();
         ZipEntry            jeLoop;
         InputStream         isLoop;
         ZipEntry            zeIndex;
         int                 bRead;
         byte []             b = new byte[4096];
      
         while (entries.hasMoreElements())
         {
            jeLoop = (ZipEntry)entries.nextElement();

            // Skip WEB-INF/classes/cypto.properties
            if (jeLoop.getName().equalsIgnoreCase("WEB-INF/classes/casa_crypto.properties"))
            {
               log("skipping: " + "WEB-INF/classes/casa_crypto.properties");
               continue;
            }
            
            // Move the rest of the files over
            else
            {
               log("Transferring jar file: " + jeLoop.getName());

               // Create the input stream
               isLoop = jfSrc.getInputStream(jeLoop);
               
               // Set up the output stream
               zeIndex = new ZipEntry(jeLoop.getName());
               josDst.putNextEntry( zeIndex);
               
               // Transfer the file contents
               while (-1 != (bRead = isLoop.read(b)))
               {
                  josDst.write(b, 0, bRead);
               }
               
               // all done
               josDst.closeEntry();
               isLoop.close();
            }
         }
      }
      catch (Exception e)
      {
         rc = ERROR_JAR_COPY_FAILED;
      }
      return rc;
   }

   int addFileToJar(String sFilename, String sName, ZipOutputStream josJarNew)
   {
      FileInputStream fis;
      ZipEntry je;
      int bRead;
      byte [] b = new byte[4096];
      int rc = ERROR_NO_ERROR;
      
      try
      {
         // Create the input stream
         fis = new FileInputStream(sFilename);
         
         // Set up the output stream
         je = new ZipEntry(sName);
         josJarNew.putNextEntry(je);
         
         // Tansfer the contents of the file
         while (-1 != (bRead = fis.read(b)))
         {
            josJarNew.write(b, 0, bRead);
         }
         
         // All done
         fis.close();
         josJarNew.closeEntry();
      }
      catch (Exception e)
      {
         log(e.toString());
         rc = ERROR_ADD_FILE_TO_JAR_FAILED;
      }
      return rc;
   }

   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: 1make expected";
            break;
         case ERROR_EXCEPTION:
            sMessage = "Exception";
            break;
         default:
            sMessage = "Unknown error: " + err;
            break;
      }

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

   void log(String s)
   {
      /*
      try
      {
         fw.write(this.getClass().getName() + ": " + s + "\r\n");
      }
      catch (IOException ioe)
      {
      }
      */
   }
}