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

                                              Copyright  2014 Allen Baker

------------------------------------------------------------------------------------------------------------------------
File:        CosmicAbyssMakeFile
Originator:  Allen Baker (2014.04.26 02:24)
LayoutRev:   4
------------------------------------------------------------------------------------------------------------------------
$RCSfile$
$Revision$
$Date$
======================================================================================================================== */
package cosmicabyss.com.app;

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


import cosmicabyss.com.lib.*;



/*
======================================================================================================================== *//**
Description<PRE>
   This program creates an HTML file from the CosmicAbyss HTML template file.
</PRE>

Usage<PRE>
   java cosmicabyss.com.app.CosmicAbyssMakeFile [-h -q -r -s] [-l [logFile]] {-x fileSpec} {-ifile filename} {-xfile filename} fileSpecs+
      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.

   -r means RECURSE.
      It causes the program to recurse down through the trees of subdirectories that are rooted at the directories
      specified in the file specifiers that are on the command line.

   -s means SUBDIRECTORIES.
      It causes the program to match subdirectory names that match the file specifiers on the command line.

   -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.

   -x means EXCLUDE.
      It requires a fileSpec, and causes the program to not process any files that match the fileSpec. This control may
      be put on the command line as many times as needed to specify all the files that should be excluded from
      processing.

      Enclosing the fileSpec in quotes is REQUIRED for any fileSpec that contains embedded spaces or wildcard
      characters.

   -p means PRODUCTION.
      It causes the program to generate 'production' appropriate output instead of 'development' appropriate output.

   -xfile means EXCLUDE FILE.
      It takes a required file name parameter, and causes the program to read each non-empty line in the named file and
      treat it as the filespec argument to a -x control. This control may be put on the command line as many times as
      needed to specify all the files that contain filespecs for files that should be excluded from processing.

   -ifile means INCLUDE FILE.
      It takes a required file name parameter, and causes the program to read each non-empty line in the named file and
      treat it as a fileSpec that identifies files to include in processing. This control may be put on the command line
      as many times as needed to specify all the files that contain filespecs for files that should be included in the
      processing.

   fileSpecs identifies the files to process.
      It is a required parameter and is one or more file specifiers that identify the files that the program will
      process.

      Each fileSpec must match this format:
         fileSpec := [category].[type].[stem].[extension]
            category  := 'Page' | 'Include' | 'Template'
            type      := 'NAV' | 'DOC' | 'PKG' | 'PDF' | 'XLS' | 'XLSM' | 'JAR' | 'EXE' | 'C' | 'CPP' | 'CS' | 'JAVA' | 'VBA'
            stem      := pageName | extensionlessFilename
            extension := 'htm'

      As many fileSpecs may be put on the command line as needed to specify all the files that should be included in
      processing.

      Enclosing the fileSpec in quotes is required for any file specifier that contains embedded spaces.

      Enclosing the fileSpec in quotes prevents the command line interpreter from trying to replace wildcard characters
      itself instead of letting CosmicAbyssMakeFile do it.

      The quotes surrounding the fileSpec are not needed if it contains no wildcard characters or spaces.

</PRE>

<P>
<DL>
   <DT>
      <B>Example usage:</B>
      <DD>
         <PRE>
            *java cosmicabyss.com.app.CosmicAbyssMakeFile -r -x"*.bat" "..\*.*"
         </PRE>
      </DD>
   </DT>
   <DT>
      <B>View Source:</B>
      <DD>
         <A href="CosmicAbyssMakeFile.java.html">
            CosmicAbyssMakeFile.java
         </A>
      </DD>
   </DT>
   <DT>
      <B>Author:</B>
      <DD>
         <A href="mailto:sourcecode.v01@cosmicabyss.com">
            Allen Baker
         </A>
      </DD>
   </DT>
</DL>
*//*
======================================================================================================================== */
public class CosmicAbyssMakeFile
   {



   /*
   =====================================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Constructors  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Public Instance Constructors  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



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

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

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

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



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Protected Instance Constructors  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Private Instance Constructors  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Initialization  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Private Class Initialization  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*:                                          
   ===============================================================================================================
   ===============================================================================================================
   =============================================================================================================== *//**
   This method is the class static initialization block which is run the first time the JVM loads this class code
   and before anything else in this class is accessed

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

   *//*
   --------------------------------------------------------------------------------------------------------------- */
   static
      {
      /*
      ================================================================================================
      if required, make sure all the class constants and variables are initialized the first time the
      JVM loads this class code and before anything else in this class is accessed
      ------------------------------------------------------------------------------------------------ */
      initializeClassConstantsAndVariables();
      }



   /*
   =====================================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Methods  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ===================================================================================================================== */



   /*:                                          
   ===============================================================================================================
   ===============================================================================================================
   =============================================================================================================== *//**
   This method runs the CosmicAbyssMakeFile 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.CosmicAbyssMakeFile [-h -q -r -s] [-l [logFile]] {-x fileSpec} {-ifile filename} {-xfile filename} fileSpecs+
      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.

   -r means RECURSE.
      It causes the program to recurse down through the trees of subdirectories that are rooted at the directories
      specified in the file specifiers that are on the command line.

   -s means SUBDIRECTORIES.
      It causes the program to match subdirectory names that match the file specifiers on the command line.

   -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.

   -x means EXCLUDE.
      It requires a fileSpec, and causes the program to not process any files that match the fileSpec. This control may
      be put on the command line as many times as needed to specify all the files that should be excluded from
      processing.

      Enclosing the fileSpec in quotes is REQUIRED for any fileSpec that contains embedded spaces or wildcard
      characters.

   -p means PRODUCTION.
      It causes the program to generate 'production' appropriate output instead of 'development' appropriate output.

   -xfile means EXCLUDE FILE.
      It takes a required file name parameter, and causes the program to read each non-empty line in the named file and
      treat it as the filespec argument to a -x control. This control may be put on the command line as many times as
      needed to specify all the files that contain filespecs for files that should be excluded from processing.

   -ifile means INCLUDE FILE.
      It takes a required file name parameter, and causes the program to read each non-empty line in the named file and
      treat it as a fileSpec that identifies files to include in processing. This control may be put on the command line
      as many times as needed to specify all the files that contain filespecs for files that should be included in the
      processing.

   fileSpecs identifies the files to process.
      It is a required parameter and is one or more file specifiers that identify the files that the program will
      process.

      Each fileSpec must match this format:
         fileSpec := [category].[type].[stem].[extension]
            category  := 'Page' | 'Include' | 'Template'
            type      := 'NAV' | 'DOC' | 'PKG' | 'PDF' | 'XLS' | 'XLSM' | 'JAR' | 'EXE' | 'C' | 'CPP' | 'CS' | 'JAVA' | 'VBA'
            stem      := pageName | extensionlessFilename
            extension := 'htm'

      As many fileSpecs may be put on the command line as needed to specify all the files that should be included in
      processing.

      Enclosing the fileSpec in quotes is required for any file specifier that contains embedded spaces.

      Enclosing the fileSpec in quotes prevents the command line interpreter from trying to replace wildcard characters
      itself instead of letting CosmicAbyssMakeFile do it.

      The quotes surrounding the fileSpec are not needed if it contains no wildcard characters or spaces.

   </PRE>

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

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



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Public Class Methods  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Public Instance Methods  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



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

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

   @return
      a reference to this object

   @param
      pConsole is a ConsoleStream through which this objects sends its output.
   *//*
   --------------------------------------------------------------------------------------------------------------- */
   public CosmicAbyssMakeFile 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="CosmicAbyssMakeFile.java.html#004">View source</A>

   @return
      a reference to this object
   *//*
   --------------------------------------------------------------------------------------------------------------- */
   public CosmicAbyssMakeFile 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 Class Methods  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Protected Instance Methods  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Private Class Methods  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*:                                          
   ===============================================================================================================
   ===============================================================================================================
   =============================================================================================================== *//**
   This method is called from the class static initialization block to make sure all the class constants and
   variables are initialized the first time the JVM loads this class code and before anything else in this class
   is accessed

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

   *//*
   --------------------------------------------------------------------------------------------------------------- */
   private static void initializeClassConstantsAndVariables()
      {
      }



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Private Instance Methods  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*:                                          
   ===============================================================================================================
   ===============================================================================================================
   =============================================================================================================== *//**
   This method initializes all the instance constants and variables

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

   *//*
   --------------------------------------------------------------------------------------------------------------- */
   private <Type> boolean initializeInstanceConstantsAndVariables(Type[] pArgs) throws Exception
      {
      boolean  successCode = true;

      successCode = processCommandLine(pArgs);
      if (successCode)
         {
         }
      return successCode;
      }



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

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

   @return
      a success code of true if all goes well, false otherwise.
   *//*
   --------------------------------------------------------------------------------------------------------------- */
   private boolean processAllFiles() throws Exception
      {
      boolean  successCode = true;
      String   fmtStr;
      /*
      ================================================================================================
      tell 'em what we're gonna do
      ------------------------------------------------------------------------------------------------ */
      cOut.println("Plan","Will process " + iFileNameList.size() + " files.");
      if      (iFileNameList.size() > 99999) fmtStr = "%06d";
      else if (iFileNameList.size() >  9999) fmtStr = "%05d";
      else if (iFileNameList.size() >   999) fmtStr = "%04d";
      else if (iFileNameList.size() >    99) fmtStr = "%03d";
      else if (iFileNameList.size() >     9) fmtStr = "%02d";
      else                                   fmtStr = "%d";
      /*
      ================================================================================================
      do it for each file in the FileNameList
      ------------------------------------------------------------------------------------------------ */
      int  filesProcessed = 0;
      for (XString  filename : iFileNameList)
         {
         XFile    file             = new XFile(filename.trim());
         XString  canonicalPath    = new XString(file.getCanonicalPath());
         /*
         ================================================================================================
         tell 'em which file is being processed next
         ------------------------------------------------------------------------------------------------ */
         filesProcessed++;
         cOut.printf("[" + fmtStr + "] Processing:   %s\n",filesProcessed,canonicalPath);
         /*
         ================================================================================================
         process the file
         ------------------------------------------------------------------------------------------------ */
         successCode &= processThisFile(canonicalPath);
         if (! successCode)
            {
            break;
            }
         }
      /*
      ================================================================================================
      tell 'em what we did
      ------------------------------------------------------------------------------------------------ */
      cOut.println("Result","Processed " + filesProcessed + " of an expected " + iFileNameList.size() + " files.");
      return successCode;
      }



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

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

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

   @param
      pPathname is the name of the file to process.
   *//*
   --------------------------------------------------------------------------------------------------------------- */
   private boolean processThisFile(XString pPathname) throws Exception
      {
      boolean  successCode = true;
      /*
      ================================================================================================
      figure out the filenames we're going to use based on the original file name
      ------------------------------------------------------------------------------------------------ */
      TextFile  originalFile     = new TextFile(pPathname);
      XString   originalFilename = new XString(originalFile.getName());
      /*
      ================================================================================================
      pick the file name apart. It's expected to be in this format:
         fileSpec := [category].[type].[stem].[extension]
            category  := "Page" | "Include" | "Template"
            type      := "NAV" | "DOC" | "PDF" | "XLS" | "XLSM" | "JAR" | "EXE" | "C" | "CPP" | "CS" | "JAVA" | "VBA"
            stem      := pageName | extensionlessFilename
            extension := "htm"
      ------------------------------------------------------------------------------------------------ */
      ArrayList<XString>  filenameParts = originalFilename.tokenizedString(".");
      if (filenameParts.size() != 4)
         {
         cOut.println("ARGUMENT ERROR: Invalid file name:  %s", pPathname);
         usage();
         cOut.titledSeverityPrintf
            (
            Const.HALT,
            CLASS_NAME,
            "Argument error."
            );
         return false;
         }
      XString  filenameCategory  = filenameParts.get(0);
      XString  filenameType      = filenameParts.get(1);
      XString  filenameStem      = filenameParts.get(2);
      XString  filenameExtension = filenameParts.get(3);
      /*
      ================================================================================================
      branch to the logic for handeling files of this type
      ------------------------------------------------------------------------------------------------ */
      switch (filenameType.toString())
         {
         case "NAV" : successCode = processNavigationFile(pPathname, filenameParts); break;

         case "DOC" :
         case "PKG" :
         case "PDF" :
         case "XLS" :
         case "XLSM":
         case "JAR" :
         case "EXE" : successCode = processDownloadFile  (pPathname, filenameParts); break;

         case "C"   :
         case "CPP" :
         case "CS"  :
         case "JAVA":
         case "VBA" : successCode = processSourceCodeFile(pPathname, filenameParts); break;

         default    :
            {
            cOut.println("ARGUMENT ERROR: Invalid file name:  %s", pPathname);
            usage();
            cOut.titledSeverityPrintf
               (
               Const.HALT,
               CLASS_NAME,
               "Argument error."
               );
            return false;
            }
         }
      /*
      ================================================================================================
      ------------------------------------------------------------------------------------------------ */
      return successCode;
   }



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

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

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

   @param
      pPathname is the name of the file to process.
   *//*
   --------------------------------------------------------------------------------------------------------------- */
   private boolean processNavigationFile(XString pPathname, ArrayList<XString> pFilenameParts) throws Exception
      {
      boolean  successCode = true;
      /*
      ================================================================================================
      figure out the filenames we're going to use based on the original file name
      ------------------------------------------------------------------------------------------------ */
      TextFile originalFile     = new TextFile(pPathname);
      XString  originalPathname = new XString(originalFile.getCanonicalPath());
      XString  originalFilename = new XString(originalFile.getName());
      XString  inputPathname    = new XString(originalFile.getExtensionlessCanonicalPath());
      XString  outputPathname   = originalPathname;
      XString  includePathname  = new XString
         (
         originalFile.getCanonicalParent() +
         "/Include."                       +
         originalFilename.trimLeft("Page.").toString()
         );
      /*
      ================================================================================================
      now we're done with this file.
      ------------------------------------------------------------------------------------------------ */
      originalFile = null;
      /*
      ================================================================================================
      start building the input file by copying the template file into it.
      ------------------------------------------------------------------------------------------------ */
      TextFile templateFile = new TextFile("Template.CosmicAbyss.htm");
      TextFile inputFile    = new TextFile(inputPathname);
      inputFile.copyFrom(templateFile);
      /*
      ================================================================================================
      make string substitutions of the special strings that came into our input file from the template
      file.
      ------------------------------------------------------------------------------------------------ */
      XString[]    pageData  = pageInfo(originalFilename);
      if (iProduction)
         {
         XString[][]  strPairs1 =
            {
               {new XString("PAGE_TITLE"),                pageData[1]              },
               {new XString("CONTENT_TITLE"),             pageData[2]              },
               {new XString("#Include: DOWNLOAD_BUTTON"), new XString("<!-- -->")  },
               {new XString("INCLUDE_FILE"),              includePathname          }
            };
         inputFile.replace(strPairs1);
         }
      else
         {
         XString[][]  strPairs1 =
            {
               {new XString("PAGE_TITLE"),                             pageData[1]              },
               {new XString("CONTENT_TITLE"),                          pageData[2]              },
               {new XString("#Include: DOWNLOAD_BUTTON"),              new XString("<!-- -->")  },
               {new XString("INCLUDE_FILE"),                           includePathname          },
               {new XString("#Include: Template.Disqus.Comments.htm"), new XString("<!-- -->")  },
               {new XString("#Include: Template.Disqus.Close.htm"),    new XString("<!-- -->")  }
            };
         inputFile.replace(strPairs1);
         }
      /*
      ================================================================================================
      now create the output file and do include file processing on the input file to the output file.
      ------------------------------------------------------------------------------------------------ */
      TextWriter  outWriter = new TextWriter(outputPathname);
      processIncludes(inputFile, outWriter);
      outWriter.flush();
      outWriter.close();
      outWriter = null;
      /*
      ================================================================================================
      delete the temporary file we were using as input for the include processor
      ------------------------------------------------------------------------------------------------ */
      inputFile.delete();
      /*
      ================================================================================================
      special processing for the index file which doesn't conform to our filename format.
      ------------------------------------------------------------------------------------------------ */
      originalFile     = new TextFile(pPathname);
      originalFilename = new XString(originalFile.getName());
      if (originalFilename.equalsIgnoreCase("Page.NAV.Index.htm"))
         {
         TextFile indexFile = new TextFile("index.htm");
         indexFile.copyFrom(originalFile);
         indexFile = null;
         /*
         ================================================================================================
         optimize the resulting Html file.
         ------------------------------------------------------------------------------------------------ */
         HtmlFile hFile = new HtmlFile("index.htm");
         hFile.optimize();
         hFile = null;
         }
      originalFile  = null;
      /*
      ================================================================================================
      optimize the resulting Html file.
      ------------------------------------------------------------------------------------------------ */
      HtmlFile hFile = new HtmlFile(pPathname);
      hFile.optimize();
      hFile = null;
      /*
      ================================================================================================
      ------------------------------------------------------------------------------------------------ */
      return successCode;
      }



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

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

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

   @param
      pPathname is the name of the file to process.
   *//*
   --------------------------------------------------------------------------------------------------------------- */
   private boolean processDownloadFile(XString pPathname, ArrayList<XString> pFilenameParts) throws Exception
      {
      boolean  successCode = true;
      /*
      ================================================================================================
      figure out the filenames we're going to use based on the original file name
      ------------------------------------------------------------------------------------------------ */
      TextFile originalFile     = new TextFile(pPathname);
      XString  originalPathname = new XString(originalFile.getCanonicalPath());
      XString  originalFilename = new XString(originalFile.getName());
      XString  inputPathname    = new XString(originalFile.getExtensionlessCanonicalPath());
      XString  outputPathname   = originalPathname;
      XString  includePathname  = new XString
         (
         originalFile.getCanonicalParent() +
         "/Include."                       +
         originalFilename.trimLeft("Page.").toString()
         );
      /*
      ================================================================================================
      pick the file name apart. It's expected to be in this format:
         fileSpec := [category].[type].[stem].[extension]
            category  := "Page" | "Include" | "Template"
            type      := "NAV" | "DOC" | "PDF" | "XLS" | "XLSM" | "JAR" | "EXE" | "C" | "CPP" | "CS" | "JAVA" | "VBA"
            stem      := pageName | extensionlessFilename
            extension := "htm"
      ------------------------------------------------------------------------------------------------ */
      XString  filenameCategory  = pFilenameParts.get(0);
      XString  filenameType      = pFilenameParts.get(1);
      XString  filenameStem      = pFilenameParts.get(2);
      XString  filenameExtension = pFilenameParts.get(3);
      /*
      ================================================================================================
      now we're done with this file.
      ------------------------------------------------------------------------------------------------ */
      originalFile = null;
      /*
      ================================================================================================
      start building the input file by copying the template file into it.
      ------------------------------------------------------------------------------------------------ */
      TextFile templateFile = new TextFile("Template.CosmicAbyss.htm");
      TextFile inputFile    = new TextFile(inputPathname);
      inputFile.copyFrom(templateFile);
      /*
      ================================================================================================
      make string substitutions of the special strings that came into our input file from the template
      file.
      ------------------------------------------------------------------------------------------------ */
      XString[]    pageData  = pageInfo(originalFilename);
      if (iProduction)
         {
         XString[][]  strPairs1 =
            {
               {new XString("Script.ViewPort.js"),        new XString("Script.ViewPort.SourceCode.js")         },
               {new XString("PAGE_TITLE"),                pageData[1]                                          },
               {new XString("CONTENT_TITLE"),             pageData[2]                                          },
               {new XString("INCLUDE_FILE"),              includePathname                                      },
               {new XString("#Include: DOWNLOAD_BUTTON"), new XString("#Include: Template.DownloadButton.htm") }
            };
         inputFile.replace(strPairs1);
         }
      else
         {
         XString[][]  strPairs1 =
            {
               {new XString("Script.ViewPort.js"),                     new XString("Script.ViewPort.SourceCode.js")         },
               {new XString("PAGE_TITLE"),                             pageData[1]                                          },
               {new XString("CONTENT_TITLE"),                          pageData[2]                                          },
               {new XString("INCLUDE_FILE"),                           includePathname                                      },
               {new XString("#Include: DOWNLOAD_BUTTON"),              new XString("#Include: Template.DownloadButton.htm") },
               {new XString("#Include: Template.Disqus.Comments.htm"), new XString("<!-- -->")                              },
               {new XString("#Include: Template.Disqus.Close.htm"),    new XString("<!-- -->")                              }
            };
         inputFile.replace(strPairs1);
         }
      /*
      ================================================================================================
      this decides what the download button shoould say it will download
      ------------------------------------------------------------------------------------------------ */
      String downloadWhat;
      switch (filenameType.toString())
         {
         case "DOC" : downloadWhat = "This Document"         ; break;
         case "PKG" : downloadWhat = "This Document Package" ; break;
         case "PDF" : downloadWhat = "This Document"         ; break;
         case "XLS" : downloadWhat = "This File"             ; break;
         case "XLSM": downloadWhat = "This Application"      ; break;
         default    :
            {
            cOut.println("ARGUMENT ERROR: Invalid file name:  %s", pPathname);
            usage();
            cOut.titledSeverityPrintf
               (
               Const.HALT,
               CLASS_NAME,
               "Argument error."
               );
            return false;
            }
         }
      /*
      ================================================================================================
      figure out which directory the download file is in
      ------------------------------------------------------------------------------------------------ */
      String  downloadDirectory;
      switch (filenameType.toString())
         {
         case "DOC" : downloadDirectory = "Writings"; break;
         case "PKG" : downloadDirectory = "Writings"; break;
         case "PDF" : downloadDirectory = "Writings"; break;
         case "XLS" : downloadDirectory = "Writings"; break;
         case "XLSM": downloadDirectory = "XLSM"        ; break;
         default    :
            {
            cOut.println("ARGUMENT ERROR: Invalid file name:  %s", pPathname);
            usage();
            cOut.titledSeverityPrintf
               (
               Const.HALT,
               CLASS_NAME,
               "Argument error."
               );
            return false;
            }
         }
      /*
      ================================================================================================
      now create the output file and do include file processing on the input file to the output file.
      ------------------------------------------------------------------------------------------------ */
      TextWriter  outWriter = new TextWriter(outputPathname);
      processIncludes(inputFile, outWriter);
      outWriter.flush();
      outWriter.close();
      outWriter = null;
      /*
      ================================================================================================
      delete the temporary file we were using as input for the include processor
      ------------------------------------------------------------------------------------------------ */
      inputFile.delete();
      /*
      ================================================================================================
      build a file name and path name for the download file
      ------------------------------------------------------------------------------------------------ */
      XString  downloadExtension = filenameType.toLowerCase();
      XString  downloadFilename  = new XString(filenameStem.toString() + "." + downloadExtension.toString());
      XString  downloadPathname  = new XString("download/" + downloadDirectory + "/" + downloadFilename.toString());
      /*
      ================================================================================================
      make string substitutions of the special strings that came into our output file from the include
      file processing.
      ------------------------------------------------------------------------------------------------ */
      TextFile     outputFile = new TextFile(outputPathname);
      XString[][]  strPairs2  =
         {
            {new XString("DOWNLOAD_FILE_FULLPATH"), downloadPathname.trimRight(downloadExtension).concat("zip") },
            {new XString("DOWNLOAD_FILE_NAMEONLY"), downloadFilename.trimRight(downloadExtension).concat("zip") },
            {new XString("Download This"),          new XString("Download " + downloadWhat)                     }
         };
      outputFile.replace(strPairs2);
      outputFile.touch();
      /*
      ================================================================================================
      optimize the resulting Html file.
      ------------------------------------------------------------------------------------------------ */
      HtmlFile hFile = new HtmlFile(pPathname);
      hFile.optimize();
      hFile = null;
      /*
      ================================================================================================
      ------------------------------------------------------------------------------------------------ */
      return successCode;
      }



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

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

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

   @param
      pPathname is the name of the file to process.
   *//*
   --------------------------------------------------------------------------------------------------------------- */
   private boolean processSourceCodeFile(XString pPathname, ArrayList<XString> pFilenameParts) throws Exception
      {
      boolean  successCode = true;
      /*
      ================================================================================================
      figure out the filenames we're going to use based on the original file name
      ------------------------------------------------------------------------------------------------ */
      TextFile  templateFile     = null;
      TextFile  originalFile     = new TextFile(pPathname);
      XString   originalPathname = new XString(originalFile.getCanonicalPath());
      XString   originalFilename = new XString(originalFile.getName());
      XString   inputPathname    = new XString(originalFile.getExtensionlessCanonicalPath());
      XString   outputPathname   = originalPathname;
      /*
      ================================================================================================
      pick the file name apart. It's expected to be in this format:
         fileSpec := [category].[type].[stem].[extension]
            category  := "Page" | "Include" | "Template"
            type      := "NAV" | "DOC" | "PDF" | "XLS" | "XLSM" | "JAR" | "EXE" | "C" | "CPP" | "CS" | "JAVA" | "VBA"
            stem      := pageName | extensionlessFilename
            extension := "htm"
      ------------------------------------------------------------------------------------------------ */
      XString  filenameCategory  = pFilenameParts.get(0);
      XString  filenameType      = pFilenameParts.get(1);
      XString  filenameStem      = pFilenameParts.get(2);
      XString  filenameExtension = pFilenameParts.get(3);
      /*
      ================================================================================================
      figure out the source code file's extension
      ------------------------------------------------------------------------------------------------ */
      XString  sourceCodeExtension = null;
      switch (filenameType.toString())
         {
         case "C":    sourceCodeExtension = new XString("c");    break;
         case "CPP":  sourceCodeExtension = new XString("cpp");  break;
         case "CS":   sourceCodeExtension = new XString("cs");   break;
         case "JAVA": sourceCodeExtension = new XString("java"); break;
         case "VBA":  sourceCodeExtension = new XString("bas");  break;
         default:     sourceCodeExtension = new XString("");     break;
         }
      /*
      ================================================================================================
      figure out what syntaxhighlighter brush to use
      ------------------------------------------------------------------------------------------------ */
      XString  syntaxHighlighterBrush = null;
      switch (filenameType.toString())
         {
         case "C":    syntaxHighlighterBrush = new XString("brush: cpp;");    break;
         case "CPP":  syntaxHighlighterBrush = new XString("brush: cpp;");    break;
         case "CS":   syntaxHighlighterBrush = new XString("brush: csharp;"); break;
         case "JAVA": syntaxHighlighterBrush = new XString("brush: java;");   break;
         case "VBA":  syntaxHighlighterBrush = new XString("brush: vb;");     break;
         default:     syntaxHighlighterBrush = new XString("brush: java;");   break;
         }
      /*
      ================================================================================================
      build a file name and path name for the source code file
      ------------------------------------------------------------------------------------------------ */
      XString  sourceCodeFilename = new XString(filenameStem.toString() + "." + sourceCodeExtension.toString());
      XString  sourceCodePathname = new XString("src/" + filenameType.toString() + "/" + sourceCodeFilename.toString());
      /*
      ================================================================================================
      build a file name and path name for the TEMPORARY source code file
      ------------------------------------------------------------------------------------------------ */
      XString  tempSourceCodeFilename = new XString(filenameStem.toString() + "." + sourceCodeExtension.toString() + ".temp");
      XString  tempSourceCodePathname = new XString("src/" + filenameType.toString() + "/" + tempSourceCodeFilename.toString());
      /*
      ================================================================================================
      now create the TEMPORARY source code file with encoded HTML characters; be sure to delete it
      when done with it.
         Whenever you need to paste your source code to HTML, you have to encode at least the
         characters below:
            <PRE>
               +------+--------+-------------------+
               +------+--------+-------------------+
               | From |   To   |    Description    |
               +------+--------+-------------------+
               |  &   | &amp;  | AMPERSAND         |
               |  "   | &quot; | QUOTATION MARK    |
               |  <   | &lt;   | LESS-THAN SIGN    |
               |  >   | &gt;   | GREATER-THAN SIGN |
               +------+--------+-------------------+
            </PRE>
         This section of code does just that.
      ------------------------------------------------------------------------------------------------ */
      TextFile tempSourceCodeFile = new TextFile(tempSourceCodePathname);
      TextFile sourceCodeFile     = new TextFile(sourceCodePathname);
      tempSourceCodeFile.copyFrom(sourceCodeFile);
      XString[][]  strPairs0 =
         {
            {new XString("&" ), new XString("&amp;" ) }, // this one must go first or it will corrupt the others containing '&'
            {new XString("\""), new XString("&quot;") },
            {new XString("<" ), new XString("&lt;"  ) },
            {new XString(">" ), new XString("&gt;"  ) },
         };
      tempSourceCodeFile.replace(strPairs0);
      /*
      ================================================================================================
      now create a TEMPORARY include file for this source code page; be sure to delete it when done
      with it.
      ------------------------------------------------------------------------------------------------ */
      XString  includePathname = new XString(originalFile.getCanonicalParent() + "/Include." + originalFilename.trimLeft("Page.").toString());
      TextFile includeFile     = new TextFile(includePathname);
      templateFile             = new TextFile("Template.SourceCode.htm");
      includeFile.copyFrom(templateFile);
      /*
      ================================================================================================
      now we're done with this file.
      ------------------------------------------------------------------------------------------------ */
      originalFile = null;
      /*
      ================================================================================================
      make the string substitution[s] required to tailor the include file for this source code page
      ------------------------------------------------------------------------------------------------ */
      includeFile.replace(new XString("INCLUDE_FILE"), tempSourceCodePathname);
      includeFile.replace(new XString("brush: vb;"  ), syntaxHighlighterBrush);
      /*
      ================================================================================================
      start building the input file by copying the template file into it.
      ------------------------------------------------------------------------------------------------ */
      TextFile  inputFile = new TextFile(inputPathname);
      templateFile        = new TextFile("Template.CosmicAbyss.htm");
      inputFile.copyFrom(templateFile);
      /*
      ================================================================================================
      make string substitutions of the special strings that came into our input file from the template
      file.
      ------------------------------------------------------------------------------------------------ */
      if (iProduction)
         {
         XString[][]  strPairs1 =
            {
               {new XString("Script.ViewPort.js"), new XString("Script.ViewPort.SourceCode.js")                },
               {new XString("PAGE_TITLE"),         new XString("CosmicAbyss " + sourceCodeFilename.toString()) },
               {new XString("CONTENT_TITLE"),      sourceCodeFilename                                          },
               {new XString("DOWNLOAD_BUTTON"),    new XString("Template.DownloadButton.htm")                  },
               {new XString("INCLUDE_FILE"),       includePathname                                             }
            };
         inputFile.replace(strPairs1);
         }
      else
         {
         XString[][]  strPairs1 =
            {
               {new XString("Script.ViewPort.js"), new XString("Script.ViewPort.SourceCode.js")                },
               {new XString("PAGE_TITLE"),         new XString("CosmicAbyss " + sourceCodeFilename.toString()) },
               {new XString("CONTENT_TITLE"),      sourceCodeFilename                                          },
               {new XString("DOWNLOAD_BUTTON"),    new XString("Template.DownloadButton.htm")                  },
               {new XString("INCLUDE_FILE"),       includePathname                                             },
               {new XString("#Include: Template.Disqus.Comments.htm"), new XString("<!-- -->")                 },
               {new XString("#Include: Template.Disqus.Close.htm"),    new XString("<!-- -->")                 }
            };
         inputFile.replace(strPairs1);
         }
      /*
      ================================================================================================
      now create the output file and do include file processing on the input file to the output file.
      ------------------------------------------------------------------------------------------------ */
      TextWriter  outWriter = new TextWriter(outputPathname);
      processIncludes(inputFile, outWriter);
      outWriter.flush();
      outWriter.close();
      outWriter = null;
      /*
      ================================================================================================
      delete the temporary source code file
      ------------------------------------------------------------------------------------------------ */
      tempSourceCodeFile.delete();
      /*
      ================================================================================================
      delete the temporary file we were using as input for the include processor
      ------------------------------------------------------------------------------------------------ */
      inputFile.delete();
      /*
      ================================================================================================
      make string substitutions of the special strings that came into our output file from the include
      file processing.
      ------------------------------------------------------------------------------------------------ */
      TextFile     outputFile = new TextFile(outputPathname);
      XString[][]  strPairs2  =
         {
            {new XString("DOWNLOAD_FILE_FULLPATH"), sourceCodePathname.trimRight(sourceCodeExtension).concat("zip") },
            {new XString("DOWNLOAD_FILE_NAMEONLY"), sourceCodeFilename.trimRight(sourceCodeExtension).concat("zip") },
            {new XString("Download This"),          new XString("Download This Source Code") }
         };
      outputFile.replace(strPairs2);
      outputFile.touch();
      /*
      ================================================================================================
      get rid of the temporary include file
      ------------------------------------------------------------------------------------------------ */
      includeFile.delete();
      /*
      ================================================================================================
      optimize the resulting Html file.
      ------------------------------------------------------------------------------------------------ */
      HtmlFile hFile = new HtmlFile(pPathname);
      hFile.optimize();
      hFile = null;
      /*
      ================================================================================================
      ------------------------------------------------------------------------------------------------ */
      return successCode;
      }



   /*:                                          
   ===============================================================================================================
   ===============================================================================================================
   =============================================================================================================== *//**
   This function returns a 1-dimnsional array containing the file name, page title, and content title for the
   file identified by pFileName.

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

   @return
      This function returns a 1-dimnsional array containing the file name, page title, and content title for the
      file identified by pFileName.

   @param
      pFileName is the name of the file for which information is returned.
   --------------------------------------------------------------------------------------------------------------- */
   private XString[] pageInfo(XString pFileName)
      {
      XString[] defaultResult = {XString.EMPTY, XString.EMPTY, XString.EMPTY};

      for (XString[] titles : iTitles)
         {
         if (titles[0].equalsIgnoreCase(pFileName))
            {
            return titles;
            }
         }
      return defaultResult;
      }



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

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

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

   @param
      pFilename is the name of the file to process.
   *//*
   --------------------------------------------------------------------------------------------------------------- */
   private boolean processIncludes(TextFile pInputFile, TextWriter pOutWriter) throws Exception
      {
      boolean  successCode = true;
      /*
      ================================================================================================
      this method makes no sense on directory files; it must be a normal file
      ------------------------------------------------------------------------------------------------ */
      if (pInputFile.isDirectory()) return false;
      /*
      ================================================================================================
      this is our input file
      ------------------------------------------------------------------------------------------------ */
      TextReaderIterator  inIter = pInputFile.iterator();
      /*
      ================================================================================================
      read each line and process it separately.
      ------------------------------------------------------------------------------------------------ */
      while (inIter.hasNext())
         {
         XString  line        = inIter.next();
         XString  trimmedLine = line.trim();
         /*
         ================================================================================================
         if the line IS NOT an "include" line, we just echo it to the output
         ------------------------------------------------------------------------------------------------ */
         if (! trimmedLine.startsWithIgnoreCase("#Include: "))
            {
            pOutWriter.println(line);
            }
         /*
         ================================================================================================
         else if the line IS an "include" line, ...
         ------------------------------------------------------------------------------------------------ */
         else
            {
            /*
            ================================================================================================
            trim away the "#Include: " keyword string
            ------------------------------------------------------------------------------------------------ */
            trimmedLine = trimmedLine.trimLeftIgnoreCase("#Include: ").trim();
            /*
            ================================================================================================
            if what is left contains a string treat is as the name of a file to include inline and send its
            contents to the output.  Note, this part of the code will recurses to do the actual inclusion.
            Furthermore, the original line with the "#Include: " keyword is thrown away - not echoed to the
            output.
            ------------------------------------------------------------------------------------------------ */
            if (! trimmedLine.isEmpty())
               {
               TextFile  includeFile   = new TextFile(trimmedLine);
               XString   canonicalPath = new XString(includeFile.getCanonicalPath());

               cOut.printf("Including: %s\n",canonicalPath);
               successCode = processIncludes(includeFile, pOutWriter);
               /*
               ================================================================================================
               if something goes wrong, this code will exit the loop and cause the unwinding of any recursion
               that happened.
               ------------------------------------------------------------------------------------------------ */
               if (! successCode) break;
               }
            /*
            ================================================================================================
            else if the line had no file name on it, just throw the line away
            ------------------------------------------------------------------------------------------------ */
            }
         }
      /*
      ================================================================================================
      tell 'em how it went
      ------------------------------------------------------------------------------------------------ */
      return successCode;
      }



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

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

   @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="CosmicAbyssMakeFile.java.html#015">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 processCommandLine(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(":hqrspl::x:");
      cmdLn.addControl("-xfile", "required");
      cmdLn.addControl("-ifile", "required");
      /*
      ================================================================================================
      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>        excludedFileSpecs   = new ArrayList<XString>();
      ArrayList<XString>        includedFileSpecs   = new ArrayList<XString>();
      boolean                   result              = cmdLn.commandLineArgs
         (
         iGlobalProperties  ,
         controlsWithoutArgs,
         controlsWithArgs   ,
         excludedFileSpecs  ,
         includedFileSpecs
         );
      /*
      ================================================================================================
      if the command line was messed up, abort the program
      ------------------------------------------------------------------------------------------------ */
      if (includedFileSpecs.isEmpty())
         {
         cOut.println("COMMAND LINE ERROR: MANDATORY control NOT on command line:  fileSpecs");
         }
      if ((result == false) || (includedFileSpecs.isEmpty()))
         {
         usage();
         cOut.titledSeverityPrintf
            (
            Const.HALT,
            CLASS_NAME,
            "Command line error."
            );
         cOut.stopLog();
         System.exit(-1);
         }
      /*
      ================================================================================================
      arguments for the FileNameList with their default values.  Some of these arguments may be
      modified by commandline controls.
      ------------------------------------------------------------------------------------------------ */
      boolean  recurse             = false;
      boolean  fullyQualifiedNames = true;
      boolean  matchSubdirs        = false;
      boolean  sort                = true;
      boolean  collapse            = false;
      /*
      ================================================================================================
      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);
            }
         recurse      |= ctl.equals("-r");
         matchSubdirs |= ctl.equals("-s");
         iProduction  |= ctl.equals("-p");
         }
      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 files names that will be processed
      ------------------------------------------------------------------------------------------------ */
      for (XString  fileSpec : includedFileSpecs)
         {
         cOut.println("Files matching this fileSpec will be INcluded: " + fileSpec);
         }
      if (includedFileSpecs.size() > 0) cOut.println();
      for (XString  fileSpec : excludedFileSpecs)
         {
         cOut.println("Files matching this fileSpec will be EXcluded: " + fileSpec);
         }
      if (excludedFileSpecs.size() > 0) cOut.println();
      iFileNameList = new FileNameList
         (
         includedFileSpecs,excludedFileSpecs,recurse,fullyQualifiedNames,matchSubdirs,sort,collapse
         );
      /*
      ================================================================================================
      ------------------------------------------------------------------------------------------------ */
      return successCode;
      }



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

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

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



   /*
   =====================================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Nested Types  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Public Class Nested Types  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Public Instance Nested Types  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Protected Class Nested Types  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Protected Instance Nested Types  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Private Class Nested Types  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Private Instance Nested Types  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Constants  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Public Class Constants  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Protected Class Constants  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  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(CosmicAbyssMakeFile.class.getName());
   private static final XString  DESCRIPTION = new XString
      (
      // <Description>  Preprocessor generated String definition, Don't mess with it.
      "This program creates an HTML file from the CosmicAbyss HTML template file.                                           \n" +
      ""// </Description>
      );
   private static final XString  USAGE       = new XString
      (
      // <Usage>        Preprocessor generated String definition, Don't mess with it.
      "java cosmicabyss.com.app.CosmicAbyssMakeFile [-h -q -r -s] [-l [logFile]] {-x fileSpec} {-ifile filename} {-xfile filename} fileSpecs+\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 program.                                         \n" +
      "                                                                                                                     \n" +
      "-q means QUIET.                                                                                                      \n" +
      "   It stops the program from sending log messages to stdout. The program sends log messages to stdout by default;    \n" +
      "   this option is the only way to stop it from doing that.                                                           \n" +
      "                                                                                                                     \n" +
      "-r means RECURSE.                                                                                                    \n" +
      "   It causes the program to recurse down through the trees of subdirectories that are rooted at the directories      \n" +
      "   specified in the file specifiers that are on the command line.                                                    \n" +
      "                                                                                                                     \n" +
      "-s means SUBDIRECTORIES.                                                                                             \n" +
      "   It causes the program to match subdirectory names that match the file specifiers on the command line.             \n" +
      "                                                                                                                     \n" +
      "-l means LOGFILE.                                                                                                    \n" +
      "   It takes an optional file name parameter, and causes the program to send log messages to the named file. If the   \n" +
      "   file name is not present, the program generates a default file name. If the environment variable LOGDIRECTORY is  \n" +
      "   defined, the program places the file in that directory. If not, the program places the file in the current        \n" +
      "   directory. The program continues to send log messages to stdout too, unless the -q option is used.                \n" +
      "                                                                                                                     \n" +
      "-x means EXCLUDE.                                                                                                    \n" +
      "   It requires a fileSpec, and causes the program to not process any files that match the fileSpec. This control may \n" +
      "   be put on the command line as many times as needed to specify all the files that should be excluded from          \n" +
      "   processing.                                                                                                       \n" +
      "                                                                                                                     \n" +
      "   Enclosing the fileSpec in quotes is REQUIRED for any fileSpec that contains embedded spaces or wildcard           \n" +
      "   characters.                                                                                                       \n" +
      "                                                                                                                     \n" +
      "-p means PRODUCTION.                                                                                                 \n" +
      "   It causes the program to generate 'production' appropriate output instead of 'development' appropriate output.    \n" +
      "                                                                                                                     \n" +
      "-xfile means EXCLUDE FILE.                                                                                           \n" +
      "   It takes a required file name parameter, and causes the program to read each non-empty line in the named file and \n" +
      "   treat it as the filespec argument to a -x control. This control may be put on the command line as many times as   \n" +
      "   needed to specify all the files that contain filespecs for files that should be excluded from processing.         \n" +
      "                                                                                                                     \n" +
      "-ifile means INCLUDE FILE.                                                                                           \n" +
      "   It takes a required file name parameter, and causes the program to read each non-empty line in the named file and \n" +
      "   treat it as a fileSpec that identifies files to include in processing. This control may be put on the command line\n" +
      "   as many times as needed to specify all the files that contain filespecs for files that should be included in the  \n" +
      "   processing.                                                                                                       \n" +
      "                                                                                                                     \n" +
      "fileSpecs identifies the files to process.                                                                           \n" +
      "   It is a required parameter and is one or more file specifiers that identify the files that the program will       \n" +
      "   process.                                                                                                          \n" +
      "                                                                                                                     \n" +
      "   Each fileSpec must match this format:                                                                             \n" +
      "      fileSpec := [category].[type].[stem].[extension]                                                               \n" +
      "         category  := 'Page' | 'Include' | 'Template'                                                                \n" +
      "         type      := 'NAV' | 'DOC' | 'PKG' | 'PDF' | 'XLS' | 'XLSM' | 'JAR' | 'EXE' | 'C' | 'CPP' | 'CS' | 'JAVA' | 'VBA'\n" +
      "         stem      := pageName | extensionlessFilename                                                               \n" +
      "         extension := 'htm'                                                                                          \n" +
      "                                                                                                                     \n" +
      "   As many fileSpecs may be put on the command line as needed to specify all the files that should be included in    \n" +
      "   processing.                                                                                                       \n" +
      "                                                                                                                     \n" +
      "   Enclosing the fileSpec in quotes is required for any file specifier that contains embedded spaces.                \n" +
      "                                                                                                                     \n" +
      "   Enclosing the fileSpec in quotes prevents the command line interpreter from trying to replace wildcard characters \n" +
      "   itself instead of letting CosmicAbyssMakeFile do it.                                                              \n" +
      "                                                                                                                     \n" +
      "   The quotes surrounding the fileSpec are not needed if it contains no wildcard characters or spaces.               \n" +
      "                                                                                                                     \n" +
      ""// </Usage>
      );




   /*
   =====================================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Variables  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Public Class Variables  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Public Instance Variables  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Protected Class Variables  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Protected Instance Variables  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Private Class Variables  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   ================================================================================================
   cOut : formatted and time-stamped console output.
   ------------------------------------------------------------------------------------------------ */
   private static ConsoleStream  cOut = ConsoleStream.getSingleton();



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Private Instance Variables  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   ================================================================================================
   iFileNameList     : the list of all file names that match the filespecs given on the command
                       line.
   iGlobalProperties : a copy of all the environment variables.
   ------------------------------------------------------------------------------------------------ */
   private FileNameList      iFileNameList     = null;
   private GlobalProperties  iGlobalProperties = null;
   private boolean           iProduction       = false;
   /*
   ================================================================================================
   ------------------------------------------------------------------------------------------------ */
   private XString[][] iTitles =
      {
      //   File Name                               Page Title                                  Content Title
      //   --------------------------------------+-------------------------------------------+------------------------------
         { new XString("index.htm"),                                 new XString("CosmicAbyss Home"),                              new XString("Allen Baker's Website")                        },
         { new XString("Page.NAV.Index.htm"),                        new XString("CosmicAbyss Home"),                              new XString("Allen Baker's Website")                        },
         { new XString("Page.NAV.AppsAndTools.htm"),                 new XString("CosmicAbyss Apps and Tools"),                    new XString("Apps and Tools")                               },
         { new XString("Page.NAV.ExcelConfig.htm"),                  new XString("CosmicAbyss Excel Configuration"),               new XString("Excel Configuration")                          },
         { new XString("Page.NAV.SourceCodeAll.htm"),                new XString("CosmicAbyss Source Code"),                       new XString("Source Code")                                  },
         { new XString("Page.NAV.SourceCodeC.htm"),                  new XString("CosmicAbyss C and C++ Source Code"),             new XString("C and C++ Source Code")                        },
         { new XString("Page.NAV.SourceCodeCSharp.htm"),             new XString("CosmicAbyss C# Source Code"),                    new XString("C# Source Code")                               },
         { new XString("Page.NAV.SourceCodeJava.htm"),               new XString("CosmicAbyss Java Source Code"),                  new XString("Java Source Code")                             },
         { new XString("Page.NAV.SourceCodeVba.htm"),                new XString("CosmicAbyss VBA Source Code"),                   new XString("VBA Source Code")                              },
         { new XString("Page.NAV.ExcelBasedApps.htm"),               new XString("CosmicAbyss Excel-Based Apps"),                  new XString("Excel-Based Apps")                             },
         { new XString("Page.NAV.WindowsApps.htm"),                  new XString("CosmicAbyss Windows Apps"),                      new XString("Windows Apps")                                 },
         { new XString("Page.NAV.Writings.htm"),                     new XString("CosmicAbyss Writings"),                          new XString("Writings")                                     },
         { new XString("Page.NAV.SiteMap.htm"),                      new XString("CosmicAbyss Site Map"),                          new XString("Site Map")                                     },
         { new XString("Page.NAV.About.htm"),                        new XString("CosmicAbyss About"),                             new XString("About")                                        },
         { new XString("Page.NAV.AboutPic1.htm"),                    new XString("CosmicAbyss About Pic"),                         new XString("About the Picture")                            },
         { new XString("Page.NAV.Universities.htm"),                 new XString("CosmicAbyss Universities"),                      new XString("Universities Attended")                        },
         { new XString("Page.XLSM.PersonalityTypeIdentifier.htm"),   new XString("CosmicAbyss Personality Type Indentifier"),      new XString("Personality Type Indentifier")                 },
         { new XString("Page.XLSM.ColorTool.htm"),                   new XString("CosmicAbyss Color Tool"),                        new XString("Color Tool")                                   },
         { new XString("Page.DOC.RoleArchitecture.htm"),             new XString("CosmicAbyss Role Architecture"),                 new XString("An Architecture For IT Architectural Roles")   },
         { new XString("Page.DOC.PairChoiceDecisionMatrix.htm"),     new XString("CosmicAbyss Pair Choice Decision Matrix"),       new XString("Using A Pair Choice Decision Matrix")          },
         { new XString("Page.DOC.Endianness.htm"),                   new XString("CosmicAbyss Endianness"),                        new XString("Endianness")                                   },
         { new XString("Page.DOC.ArchitectureDevelopmentGuide.htm"), new XString("CosmicAbyss Architecture Development Guide"),    new XString("Architecture Development Guide")               },
         { new XString("Page.DOC.Patent.htm"),                       new XString("CosmicAbyss Patent"),                            new XString("US Patent 7035921_B1")                         },
         { new XString("Page.PKG.JetSend.htm"),                      new XString("CosmicAbyss HP JetSend"),                        new XString("HP JetSend")                                   },
         { new XString("Page.DOC.JetSendNetworkArchitecture.htm"),   new XString("CosmicAbyss HP JetSend Network Architecture"),   new XString("HP JetSend Network Architecture")              },
         { new XString("Page.DOC.JetSendOSP.htm"),                   new XString("CosmicAbyss HP JetSend OSP"),                    new XString("HP JetSend Session Protocol (OSP)")            },
         { new XString("Page.DOC.JetSendTIAPI.htm"),                 new XString("CosmicAbyss HP JetSend TIAPI"),                  new XString("HP JetSend Transport Independent API (TIAPI)") },
         { new XString("Page.DOC.JetSendRMTPAPI.htm"),               new XString("CosmicAbyss HP JetSend RMTPAPI"),                new XString("HP JetSend Transport Protocol API (RMTPAPI)")  },
         { new XString("Page.DOC.JetSendRMTP.htm"),                  new XString("CosmicAbyss HP JetSend RMTP"),                   new XString("HP JetSend Transport Protocol (RMTP)")         },
         { new XString("Page.DOC.JetSendPacketMarshalling.htm"),     new XString("CosmicAbyss HP JetSend Packet Marshalling"),     new XString("HP JetSend Packet Marshalling")                },
         { new XString("Page.DOC.SignedAndSecureCommunications.htm"),new XString("CosmicAbyss Signed and Secure Communications"),  new XString("Signed and Secure Communications")             },
         { new XString("Page.DOC.Availability.htm"),                 new XString("CosmicAbyss Availability"),                      new XString("Calculating End-to-End Availability")          },
      };


   }  // class CosmicAbyssMakeFile



   /*
   =====================================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Notes  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ===================================================================================================================== */



   /*:                                          
   ===============================================================================================================
   ===============================================================================================================
   =============================================================================================================== *//**
   This

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

   @return
      This function returns

   @param
      pX is the
   @param
      pY is the
   --------------------------------------------------------------------------------------------------------------- */
      /*
      ================================================================================================
      ------------------------------------------------------------------------------------------------ */



   /*
   =====================================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  Section Level 1 Banner  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   ::::::::::::::::::::::::::::::::::::::::::::[  Section Level 2 Banner  ]:::::::::::::::::::::::::::::::::::::::::::::
   ===================================================================================================================== */



   /*
   =====================================================================================================================
   --------------------------------------------[  Section Level 3 Banner  ]---------------------------------------------
   ===================================================================================================================== */



   /*
   =====================================================================================================================
                                               [  Section Level 4 Banner  ]
   ===================================================================================================================== */