/*
===========================================================================

                       Copyright  2007 Allen Baker

---------------------------------------------------------------------------
Class:         EncryptString
Originator:    Allen Baker (2007.09.15 14:56)
---------------------------------------------------------------------------
$RCSfile$
$Revision$
$Date$
===========================================================================
*/



/*
===============================================
Package
----------------------------------------------- */
package cosmicabyss.com.app;



/*
===============================================
Imports
----------------------------------------------- */
import java.io.*;
import java.util.*;


import cosmicabyss.com.lib.*;



/*
=========================================================================== *//**
Description<PRE>
   This program encrypts strings passed to it on the command line and
   generates Java byte[] array definition statements for each encrypted
   string.
</PRE>

Usage<PRE>
   java cosmicabyss.com.app.EncryptString [-h -q] [-l [logFile]] strings+
      Arguments can be placed in any order on the command line.

   -h means HELP.
      It causes this usage message to be displayed, and terminates the
      program.

   -q means QUIET.
      It stops the program from sending log messages to stdout. The program
      sends log messages to stdout by default; this option is the only way
      to stop it from doing that.

   -l means LOGFILE.
      It takes an optional file name parameter, and causes the program to
      send log messages to the named file. If the file name is not present,
      the program generates a default file name. If the environment
      variable LOGDIRECTORY is defined, the program places the file in that
      directory. If not, the program places the file in the current
      directory. The program continues to send log messages to stdout too,
      unless the -q option is used.

   strings are the strings to encrypt.
      It is a required parameter and is one or more strings that the
      program will encrypt.

      As many strings may be put on the command line as desired.

      Enclosing the string in quotes is required for any string that
      contains embedded spaces.
</PRE>

<P>
<DL>
   <DT>
      <B>Example usage:</B>
      <DD>
         <PRE>
            *java cosmicabyss.com.app.EncryptString firstString "second String"
         </PRE>
      </DD>
   </DT>
   <DT>
      <B>View Source:</B>
      <DD>
         <A href="EncryptString.java.html">
            EncryptString.java
         </A>
      </DD>
   </DT>
   <DT>
      <B>Author:</B>
      <DD>
         <A href="mailto:sourcecode.v01@cosmicabyss.com">
            Allen Baker
         </A>
      </DD>
   </DT>
</DL>
*//*
=========================================================================== */
public class EncryptString
   {



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method creates a EncryptString class object and runs the
   application to completion.

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#000">View source</A>

   @param
      pArgs contains the command line arguments with which the class was
      invoked as an application.
   *//*
   -------------------------------------------------------------- */
   public <Type> EncryptString(Type[] pArgs) throws Exception
      {
      boolean  successCode = true;

      successCode = initialize(pArgs);
      if (successCode)
         {
         successCode = processAllStrings();
         }
      cOut.println
         (
         CLASS_NAME.string() +
         (successCode? " completed successfully." : " completed with problems.")
         );
      cOut.println();
      cOut.stopLog();
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method sets the ConsoleStream for this object.

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#001">View source</A>

   @return
      a reference to this object

   @param
      pConsole is a ConsoleStream through which this objects sends its
      output.
   *//*
   -------------------------------------------------------------- */
   public EncryptString setOut(ConsoleStream pConsole)
      {
      cOut = pConsole;
      return this;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This boilerplate method is used for testing an instantiated object of
   this class and may include any code the developer chooses.

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#002">View source</A>

   @return
      a reference to this object
   *//*
   -------------------------------------------------------------- */
   public EncryptString test() throws Exception
      {
      cOut.titledPrintf
         (
         "\"HELLO WORLD!\"",
         "%s  %s  %s",
         "I'm an object of the", CLASS_NAME, "class, and I approved this message."
         );
      return this;
      }



   /*
   ===================================================================
   ===================================================================
                --------------- Protected ---------------
   =================================================================== */



   /*
   ===================================================================
   ===================================================================
                 --------------- Private ---------------
   =================================================================== */



   /*
   ===============================================
   Class Constants
      CLASS_NAME  : the name of this class
      DESCRIPTION : the man page description of this application
      USAGE       : the man page usage information for this application
   ----------------------------------------------- */
   private static final XString  CLASS_NAME  = new XString(EncryptString.class.getName());
   private static final XString  DESCRIPTION = new XString
      (
      // <Description>  Preprocessor generated String definition, Don't mess with it.
      "This program encrypts strings passed to it on the command line and                                                   \n" +
      "generates Java byte[] array definition statements for each encrypted                                                 \n" +
      "string.                                                                                                              \n" +
      ""// </Description>
      );
   private static final XString  USAGE       = new XString
      (
      // <Usage>        Preprocessor generated String definition, Don't mess with it.
      "java cosmicabyss.com.app.EncryptString [-h -q] [-l [logFile]] strings+                                               \n" +
      "   Arguments can be placed in any order on the command line.                                                         \n" +
      "                                                                                                                     \n" +
      "-h means HELP.                                                                                                       \n" +
      "   It causes this usage message to be displayed, and terminates the                                                  \n" +
      "   program.                                                                                                          \n" +
      "                                                                                                                     \n" +
      "-q means QUIET.                                                                                                      \n" +
      "   It stops the program from sending log messages to stdout. The program                                             \n" +
      "   sends log messages to stdout by default; this option is the only way                                              \n" +
      "   to stop it from doing that.                                                                                       \n" +
      "                                                                                                                     \n" +
      "-l means LOGFILE.                                                                                                    \n" +
      "   It takes an optional file name parameter, and causes the program to                                               \n" +
      "   send log messages to the named file. If the file name is not present,                                             \n" +
      "   the program generates a default file name. If the environment                                                     \n" +
      "   variable LOGDIRECTORY is defined, the program places the file in that                                             \n" +
      "   directory. If not, the program places the file in the current                                                     \n" +
      "   directory. The program continues to send log messages to stdout too,                                              \n" +
      "   unless the -q option is used.                                                                                     \n" +
      "                                                                                                                     \n" +
      "strings are the strings to encrypt.                                                                                  \n" +
      "   It is a required parameter and is one or more strings that the                                                    \n" +
      "   program will encrypt.                                                                                             \n" +
      "                                                                                                                     \n" +
      "   As many strings may be put on the command line as desired.                                                        \n" +
      "                                                                                                                     \n" +
      "   Enclosing the string in quotes is required for any string that                                                    \n" +
      "   contains embedded spaces.                                                                                         \n" +
      ""// </Usage>
      );
   /*
   ===============================================
   Class variables
      cOut : console output.
   ----------------------------------------------- */
   private static ConsoleStream  cOut = ConsoleStream.getSingleton();
   /*
   ===============================================
   Instance variables
      iStringList       : the list of all strings to encrypt
      iGlobalProperties : a copy of all the environment variables.
   ----------------------------------------------- */
   private ArrayList<XString>  iStringList       = new ArrayList<XString>();
   private GlobalProperties    iGlobalProperties = null;



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method performs the core processing functions of this application.

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#003">View source</A>

   @return
      a success code of true if all goes well, false otherwise.
   *//*
   -------------------------------------------------------------- */
   private boolean processAllStrings() throws Exception
      {
      boolean  successCode = true;
      String   fmtStr;
      /*
      ===============================================
      tell 'em what we're gonna do
      ----------------------------------------------- */
      cOut.println("Plan","Will process " + iStringList.size() + " strings.");
      if      (iStringList.size() > 99999) fmtStr = "%06d";
      else if (iStringList.size() >  9999) fmtStr = "%05d";
      else if (iStringList.size() >   999) fmtStr = "%04d";
      else if (iStringList.size() >    99) fmtStr = "%03d";
      else if (iStringList.size() >     9) fmtStr = "%02d";
      else                                 fmtStr = "%d";
      /*
      ===============================================
      do it for each string in the StringList
      ----------------------------------------------- */
      int  stringsProcessed = 0;
      for (XString  theString : iStringList)
         {
         /*
         ===============================================
         tell 'em which string is being processed next
         ----------------------------------------------- */
         stringsProcessed++;
         cOut.printf("[" + fmtStr + "] Processing: %s\n",stringsProcessed,theString);
         /*
         ===============================================
         process the string
         ----------------------------------------------- */
         successCode &= processThisString(theString);
         }
      /*
      ===============================================
      tell 'em what we did
      ----------------------------------------------- */
      cOut.println("Result","Processed " + stringsProcessed + " of an expected " + iStringList.size() + " strings.");
      return successCode;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method performs the core processing functions of this application
   on one string.

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#004">View source</A>

   @return
      a success code of true if all goes well, false otherwise.

   @param
      pString is the name of the string to process.
   *//*
   -------------------------------------------------------------- */
   private boolean processThisString(XString pString) throws Exception
      {
      boolean   successCode = true;
      /*
      ===============================================
      create a RAMCipher
      ----------------------------------------------- */
      RAMCipher  cipher = new RAMCipher();
      byte[]     bytes;
      /*
      ===============================================
      encrypt the string
      ----------------------------------------------- */
      bytes = cipher.encrypt(pString);
      /*
      ===============================================
      print out the encrypted string in the form of a Java byte array
      definition.
      ----------------------------------------------- */
      printAsJavaByteArrayDefinition(pString,bytes);
      /*
      ===============================================
      tell 'em how it went
      ----------------------------------------------- */
      return successCode;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method converts a byte[] to a Java byte array definition

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#005">View source</A>

   @return
      nothing
   *//*
   -------------------------------------------------------------- */
   public static void printAsJavaByteArrayDefinition(XString pString, byte[] pBytes)
      {
      /*
      ===============================================
      display the string in its unencrypted form in a Java comment
      ----------------------------------------------- */
      cOut.pushWordWrap(false);
      cOut.println("   /*");
      cOut.println("   ===============================================");
      cOut.println("   RAMCipher.encrypt(\"" + pString + "\")");
      cOut.println("   ----------------------------------------------- */");
      /*
      ===============================================
      display the string in its encrypted form in a Java byte array
      definition
      ----------------------------------------------- */
      cOut.println("   byte[]  var1 =");
      cOut.print("      {");
      for (int j=0; j<pBytes.length; j++)
         {
         if ((j%8)==0)
            {
            cOut.println();
            cOut.print("      ");
            }
         cOut.print("(" + UString.alignRight(pBytes[j],4,' ') + ")");
         if (j<(pBytes.length-1)) cOut.print(", ");
         }
      cOut.println();
      cOut.println("      };");
      cOut.popWordWrap();
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method displays the command line arguments that this program was
   invoked with.

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#006">View source</A>

   @return
      nothing

   @param
      pArgs contains the command line arguments with which the class was
      invoked as an application.
   *//*
   -------------------------------------------------------------- */
   private <Type> void showArgs(Type[] pArgs) throws Exception
      {
      XString  str = new XString("");
      for (int i=0; i<pArgs.length; i++)
         {
         str = str.concat(UString.toString(pArgs[i]) + "   ");
         }
      cOut.println("Command Line Arguments",str);
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method processes the command line arguments and based on what it
   finds, sets the instance variables.

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#007">View source</A>

   @return
      a success code of true if all goes well, false otherwise.

   @param
      pArgs contains the command line arguments with which the class was
      invoked as an application.
   *//*
   -------------------------------------------------------------- */
   private <Type> boolean initialize(Type[] pArgs) throws Exception
      {
      boolean  successCode = true;
      /*
      ===============================================
      Greetings !
      ----------------------------------------------- */
      System.out.println();
      System.out.println();
      System.out.println();
      System.out.println();
      cOut.banner(CLASS_NAME);
      System.out.println();
      /*
      ===============================================
      tell the user what command line arges this program started with
      ----------------------------------------------- */
      showArgs(pArgs);
      /*
      ===============================================
      this cannot be done statically because it throws an exception.
      ----------------------------------------------- */
      iGlobalProperties = new GlobalProperties();
      /*
      ===============================================
      get ready to process the command line arguments
      ----------------------------------------------- */
      CommandLine  cmdLn = new CommandLine(CLASS_NAME,pArgs);
      /*
      ===============================================
      these are the valid command line controls
      ----------------------------------------------- */
      cmdLn.addControlsFromString(":hql::");
      /*
      ===============================================
      list the valid controls
      ----------------------------------------------- */
      cmdLn.listControls();
      cOut.println();
      /*
      ===============================================
      interpret the arguments on the command line
      ----------------------------------------------- */
      HashSet<XString>          controlsWithoutArgs = new HashSet<XString>();
      HashMap<XString,XString>  controlsWithArgs    = new HashMap<XString,XString>();
      ArrayList<XString>        excludedStrings     = new ArrayList<XString>();
      boolean                   result              = cmdLn.commandLineArgs
         (
         iGlobalProperties  ,
         controlsWithoutArgs,
         controlsWithArgs   ,
         excludedStrings    ,
         iStringList
         );
      /*
      ===============================================
      if the command line was messed up, abort the program
      ----------------------------------------------- */
      if (iStringList.isEmpty())
         {
         cOut.println("COMMAND LINE ERROR: MANDATORY control NOT on command line:  strings");
         }
      if ((result == false) || (iStringList.isEmpty()))
         {
         usage();
         cOut.titledSeverityPrintf
            (
            Const.HALT,
            CLASS_NAME,
            "Command line error."
            );
         cOut.stopLog();
         System.exit(-1);
         }
      /*
      ===============================================
      process commandline controls without arguments
      ----------------------------------------------- */
      for (XString  ctl : controlsWithoutArgs)
         {
         cOut.println(ctl.string() + " control is present.");
         if (ctl.equals("-h"))
            {
            usage();
            cOut.stopLog();
            System.exit(-1);
            }
         }
      if (controlsWithoutArgs.size() > 0) cOut.println();
      /*
      ===============================================
      process commandline controls with arguments
      ----------------------------------------------- */
      Set<XString>  set = controlsWithArgs.keySet();
      for (XString  ctl : set)
         {
         XString argStr = controlsWithArgs.get(ctl);
         cOut.println(ctl + " control is present with the argument: " + argStr);
         }
      if (controlsWithArgs.size() > 0) cOut.println();
      /*
      ===============================================
      get a list of all the strings that will be processed
      ----------------------------------------------- */
      for (XString  string : iStringList)
         {
         cOut.println("This string will be INcluded: " + string);
         }
      if (iStringList.size() > 0) cOut.println();
      /*
      ===============================================
      ----------------------------------------------- */
      return successCode;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method writes a usage message to the log

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#008">View source</A>

   @return
      nothing
   *//*
   -------------------------------------------------------------- */
   private void usage()
      {
      cOut.println("Program Description",DESCRIPTION);
      cOut.println("Usage",USAGE);
      }



   /*
   ===================================================================
   ===================================================================
              --------------- Inner Classes ---------------
   =================================================================== */



   /*
   ===================================================================
   ===================================================================
          --------------- Public Static Methods ---------------
   =================================================================== */



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method runs the EncryptString class as a standalone application.
   It's the method that's called when the class is invoked from the command
   line by using the java application launcher - "java".

   Usage<PRE>
   java cosmicabyss.com.app.EncryptString [-h -q] [-l [logFile]] strings+
      Arguments can be placed in any order on the command line.

   -h means HELP.
      It causes this usage message to be displayed, and terminates the
      program.

   -q means QUIET.
      It stops the program from sending log messages to stdout. The program
      sends log messages to stdout by default; this option is the only way
      to stop it from doing that.

   -l means LOGFILE.
      It takes an optional file name parameter, and causes the program to
      send log messages to the named file. If the file name is not present,
      the program generates a default file name. If the environment
      variable LOGDIRECTORY is defined, the program places the file in that
      directory. If not, the program places the file in the current
      directory. The program continues to send log messages to stdout too,
      unless the -q option is used.

   strings are the strings to encrypt.
      It is a required parameter and is one or more strings that the
      program will encrypt.

      As many strings may be put on the command line as desired.

      Enclosing the string in quotes is required for any string that
      contains embedded spaces.
   </PRE>

   <P><B>Implementation: </B><A HREF="EncryptString.java.html#009">View source</A>

   @return
      nothing

   @param
      pArgs contains the command line arguments with which the class was
      invoked as an application.
   *//*
   -------------------------------------------------------------- */
   public static void main(String[] pArgs) throws Exception
      {
      EncryptString  thisEncryptString = new EncryptString(pArgs);
      }



   }  // class EncryptString



   /*
   ===================================================================
   ===================================================================
              ------------------- Notes -------------------
   =================================================================== */