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

                       Copyright  2008 Allen Baker

---------------------------------------------------------------------------
Class:         CountTickets
Originator:    Allen Baker (2008.02.20 13:21)
---------------------------------------------------------------------------
$RCSfile$
$Revision$
$Date$
===========================================================================
*/



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



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


import cosmicabyss.com.lib.*;



/*
=========================================================================== *//**
Description<PRE>
   This program counts the number of tickets in a Radix extract file based
   upon several criteria.
</PRE>

Usage<PRE>
   java cosmicabyss.com.app.CountTickets [-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.

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

      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 CountTickets 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.CountTickets -r -x"*.bat" "..\*.*"
         </PRE>
      </DD>
   </DT>
   <DT>
      <B>View Source:</B>
      <DD>
         <A href="CountTickets.java.html">
            CountTickets.java
         </A>
      </DD>
   </DT>
   <DT>
      <B>Author:</B>
      <DD>
         <A href="mailto:sourcecode.v01@cosmicabyss.com">
            Allen Baker
         </A>
      </DD>
   </DT>
</DL>
*//*
=========================================================================== */
public class CountTickets
   {



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

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

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

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



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

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

   @return
      a reference to this object

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

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



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



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



   /*
   ===============================================
   Class Constants
      CLASS_NAME  : the name of this class
      DESCRIPTION : the man page description of this application
      USAGE       : the man page usage information for this application
   ----------------------------------------------- */
   private static final char     QUOTE_CHAR  = '\"';
   private static final XString  QUOTE_XSTR  = new XString(QUOTE_CHAR);
   private static final char     DELIM_CHAR  = ',';
   private static final XString  DELIM_XSTR  = new XString(DELIM_CHAR);

   private static final int  COL_ID                      = 0;
   private static final int  COL_STATUS                  = 1;
   private static final int  COL_PRIORITY                = 2;
   private static final int  COL_DESCRIPTION             = 3;
   private static final int  COL_CREATED                 = 4;
   private static final int  COL_DEADLINE                = 5;
   private static final int  COL_ACTUAL_START            = 6;
   private static final int  COL_ACTUAL_FINISH           = 7;
   private static final int  COL_ACTUAL_DURATION         = 8;
   private static final int  COL_ORGANIZATION            = 9;
   private static final int  COL_CALLER                  = 10;
   private static final int  COL_TO_WORKGROUP            = 11;
   private static final int  COL_TO_PERSON               = 12;
   private static final int  COL_CLASSIFICATION          = 13;
   private static final int  COL_CLASSIFICATION_PARENT   = 14;
   private static final int  COL_CONFIGURATION_ITEM_NAME = 15;

   private static final int  NUM_COLS = 16;

   private static final XString  CLASS_NAME  = new XString(CountTickets.class.getName());
   private static final XString  DESCRIPTION = new XString
      (
      // <Description>  Preprocessor generated String definition, Don't mess with it.
      "This program counts the number of tickets in a Radix extract file based                                              \n" +
      "upon several criteria.                                                                                               \n" +
      ""// </Description>
      );
   private static final XString  USAGE       = new XString
      (
      // <Usage>        Preprocessor generated String definition, Don't mess with it.
      "java cosmicabyss.com.app.CountTickets [-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                                                  \n" +
      "   program.                                                                                                          \n" +
      "                                                                                                                     \n" +
      "-q means QUIET.                                                                                                      \n" +
      "   It stops the program from sending log messages to stdout. The program                                             \n" +
      "   sends log messages to stdout by default; this option is the only way                                              \n" +
      "   to stop it from doing that.                                                                                       \n" +
      "                                                                                                                     \n" +
      "-r means RECURSE.                                                                                                    \n" +
      "   It causes the program to recurse down through the trees of                                                        \n" +
      "   subdirectories that are rooted at the directories specified in the                                                \n" +
      "   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                                             \n" +
      "   specifiers on the command line.                                                                                   \n" +
      "                                                                                                                     \n" +
      "-l means LOGFILE.                                                                                                    \n" +
      "   It takes an optional file name parameter, and causes the program to                                               \n" +
      "   send log messages to the named file. If the file name is not present,                                             \n" +
      "   the program generates a default file name. If the environment                                                     \n" +
      "   variable LOGDIRECTORY is defined, the program places the file in that                                             \n" +
      "   directory. If not, the program places the file in the current                                                     \n" +
      "   directory. The program continues to send log messages to stdout too,                                              \n" +
      "   unless the -q option is used.                                                                                     \n" +
      "                                                                                                                     \n" +
      "-x means EXCLUDE.                                                                                                    \n" +
      "   It requires a fileSpec, and causes the program to not process any                                                 \n" +
      "   files that match the fileSpec. This control may be put on the command                                             \n" +
      "   line as many times as needed to specify all the files that should be                                              \n" +
      "   excluded from processing.                                                                                         \n" +
      "                                                                                                                     \n" +
      "   Enclosing the fileSpec in quotes is REQUIRED for any fileSpec that                                                \n" +
      "   contains embedded spaces or wildcard characters.                                                                  \n" +
      "                                                                                                                     \n" +
      "-xfile means EXCLUDE FILE.                                                                                           \n" +
      "   It takes a required file name parameter, and causes the program to                                                \n" +
      "   read each non-empty line in the named file and treat it as the                                                    \n" +
      "   filespec argument to a -x control. This control may be put on the                                                 \n" +
      "   command line as many times as needed to specify all the files that                                                \n" +
      "   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                                                \n" +
      "   read each non-empty line in the named file and treat it as a fileSpec                                             \n" +
      "   that identifies files to include in processing. This control may be                                               \n" +
      "   put on the command line as many times as needed to specify all the                                                \n" +
      "   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                                                \n" +
      "   identify the files that the program will process.                                                                 \n" +
      "                                                                                                                     \n" +
      "   As many fileSpecs may be put on the command line as needed to specify                                             \n" +
      "   all the files that should be included in processing.                                                              \n" +
      "                                                                                                                     \n" +
      "   Enclosing the fileSpec in quotes is required for any file specifier                                               \n" +
      "   that contains embedded spaces.                                                                                    \n" +
      "                                                                                                                     \n" +
      "   Enclosing the fileSpec in quotes prevents the command line                                                        \n" +
      "   interpreter from trying to replace wildcard characters itself instead                                             \n" +
      "   of letting CountTickets do it.                                                                                    \n" +
      "                                                                                                                     \n" +
      "   The quotes surrounding the fileSpec are not needed if it contains no                                              \n" +
      "   wildcard characters or spaces.                                                                                    \n" +
      ""// </Usage>
      );
   /*
   ===============================================
   Class variables
      cOut : console output.
   ----------------------------------------------- */
   private static ConsoleStream  cOut = ConsoleStream.getSingleton();
   /*
   ===============================================
   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;



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

   <P><B>Implementation: </B><A HREF="CountTickets.java.html#003">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);
         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);
         }
      /*
      ===============================================
      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.  This function creates an output csv file from an input csv
   file.  The output csv file contains daily sums and averages of the data
   in the input csv file.

   <P><B>Implementation: </B><A HREF="CountTickets.java.html#004">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 processThisFile(XString pFileName) throws Exception
      {
      boolean             successCode = true;
      TextWriter          outFile     = new TextWriter(pFileName.concat(".csv"));
      DelimitedFile       inFile      = new DelimitedFile(pFileName).setDelimiter(DELIM_CHAR).setQuote(QUOTE_CHAR).setSkipWhiteSpaceLines(true);
//      /*
//      ===============================================
//      get list of dates for the last six months
//      ----------------------------------------------- */
//      long                nowTime          = System.currentTimeMillis();
//      long                sixMonthsAgoTime = nowTime - (long)((long)182 * (long)24 * (long)60 * (long)60 * (long)1000);  // 6mo ago in ms
//      java.util.Date      sixMonthsAgoDate = new java.util.Date(sixMonthsAgoTime);
//      XString             firstDate        = Util.timeStamp("yyyy.MM.dd",sixMonthsAgoDate);
//      ArrayList<XString>  dates            = Util.dateList(firstDate, Util.timeStamp("yyyy.MM.dd"));
      /*
      ===============================================
      get list of dates for the last twelve months
      ----------------------------------------------- */
      long                nowTime           = System.currentTimeMillis();
      long                twlvMonthsAgoTime = nowTime - (long)((long)365 * (long)24 * (long)60 * (long)60 * (long)1000);  // 12mo ago in ms
      java.util.Date      twlvMonthsAgoDate = new java.util.Date(twlvMonthsAgoTime);
      XString             firstDate         = Util.timeStamp("yyyy.MM.dd",twlvMonthsAgoDate);
      ArrayList<XString>  dates             = Util.dateList(firstDate, Util.timeStamp("yyyy.MM.dd"));
//      /*
//      ===============================================
//      get list of dates since the beginning of 2007
//      ----------------------------------------------- */
//      ArrayList<XString>  dates = Util.dateList(new XString("2007.01.01"), Util.timeStamp("yyyy.MM.dd"));
      /*
      ===============================================
      this method makes no sense on directory files, this must be a normal
      file
      ----------------------------------------------- */
      if (inFile.isDirectory()) return successCode;
      /*
      ===============================================

      each line of the input file represents 1 radix ticket that has
      existed at some time in Radix

      along with other ticket information, each line of the file includes
      two strings, the radix ticket's create date and the ticket's actual
      finish date.  Tickets that are still not finished have a finish date
      of "".  For those, we change the actual finish date to "2999.12.31
      23:59".

      This section of code loads all the create and actual finish dates
      into memory.
      ----------------------------------------------- */
      ArrayList<XString>  created = new ArrayList<XString>();
      ArrayList<XString>  closed  = new ArrayList<XString>();
      ArrayList<XString>  config  = new ArrayList<XString>();
      int                 lineNo  = 0;
      while (inFile.hasNext())
         {
         ArrayList<XString>  tokens = inFile.parsedLine();

         lineNo++;
//         if (lineNo == 1) continue;

         if (tokens.size() < NUM_COLS)
            {
            cOut.println("Line " + lineNo + " only has " + tokens.size() + " columns");
            }

         XString  status      = tokens.get(COL_STATUS                 ).trimLeft(QUOTE_XSTR).trimRight(QUOTE_XSTR);
         XString  createdDate = tokens.get(COL_CREATED                ).trimLeft(QUOTE_XSTR).trimRight(QUOTE_XSTR);
         XString  closedDate  = tokens.get(COL_ACTUAL_FINISH          ).trimLeft(QUOTE_XSTR).trimRight(QUOTE_XSTR);
         XString  configItem  = tokens.get(COL_CONFIGURATION_ITEM_NAME).trimLeft(QUOTE_XSTR).trimRight(QUOTE_XSTR);

         if (status.equals("Void")) closedDate = createdDate;
         if (closedDate.equals("")) closedDate = new XString("2999.12.31 23:59");

         created.add(createdDate);
         closed.add(closedDate);
         config.add(configItem);
         }
      /*
      ===============================================
      compute the desired sums and averages for each of these assets:

           Abbrv (See Comment)       Asset Name
      --   -----------------------   ----------------------------------------------------------
      00   W-IIA                     IIA (Issue Identification Analysis)
      01   TQTI                      Inkjet QTIP (Quality Tracking Information Program)
      02   N-AO                      IPG Americas Consumer Support ODS (NAODS)
      03   W-ASTRO2-B W-SAP-BW-      IPG IT SAP BW (ASTRO2)
      04   N-IPGP                    IPG Prophet
      05   N-ISSU                    Issue Tracking (TeamTrack)
      06   N-PLAN                    PLANCAT
      07   MRED                      Telecom Redirection Analysis
      08   APCD                      AP CDI (Consumer Data Information)
      09   N-EDS                     EDS
      10   N-ICM                     ICM Operational Reporting, Analytics (Telephony Analytics)

      W-IIA TQTI N-AO W-ASTRO2-B W-SAP-BW- N-IPGP N-ISSU N-PLAN MRED APCD N-EDS N-ICM
      ----------------------------------------------- */
      XString  targetConfig = new XString("W-IIA");
      ArrayList<Double>  B0openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B0createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B0createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("TQTI");
      ArrayList<Double>  B1openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B1createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B1createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("N-AO");
      ArrayList<Double>  B2openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B2createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B2createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("W-ASTRO2-B,W-SAP-BW-");
      ArrayList<Double>  B3openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B3createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B3createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("N-IPGP");
      ArrayList<Double>  B4openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B4createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B4createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("N-ISSU");
      ArrayList<Double>  B5openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B5createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B5createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("N-PLAN");
      ArrayList<Double>  B6openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B6createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B6createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("MRED");
      ArrayList<Double>  B7openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B7createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B7createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("APCD");
      ArrayList<Double>  B8openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B8createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B8createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("N-EDS");
      ArrayList<Double>  B9openTickets            = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B9createdTickets         = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B9createdTicketsMoveAvg  = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);

      targetConfig = new XString("N-ICM");
      ArrayList<Double>  B10openTickets           = openTicketsByDate(dates,created,closed,config,targetConfig);
      ArrayList<Double>  B10createdTickets        = createdTicketsByDate(dates,created,config,targetConfig);
      ArrayList<Double>  B10createdTicketsMoveAvg = movingAverageOfCreatedTicketsByDate(dates,created,config,targetConfig,7);
      /*
      ===============================================
      compute trend lines for each data series
      ----------------------------------------------- */
      ArrayList<Double>  x = new ArrayList<Double>();

      for (int i=0; i<dates.size(); i++) x.add((double)i);

      int  order = 24;

      ArrayList<Double>  B0openTicketsTrend            = (new PolynomialFit(order, x, B0openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B0createdTicketsTrend         = (new PolynomialFit(order, x, B0createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B0createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B0createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B1openTicketsTrend            = (new PolynomialFit(order, x, B1openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B1createdTicketsTrend         = (new PolynomialFit(order, x, B1createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B1createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B1createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B2openTicketsTrend            = (new PolynomialFit(order, x, B2openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B2createdTicketsTrend         = (new PolynomialFit(order, x, B2createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B2createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B2createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B3openTicketsTrend            = (new PolynomialFit(order, x, B3openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B3createdTicketsTrend         = (new PolynomialFit(order, x, B3createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B3createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B3createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B4openTicketsTrend            = (new PolynomialFit(order, x, B4openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B4createdTicketsTrend         = (new PolynomialFit(order, x, B4createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B4createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B4createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B5openTicketsTrend            = (new PolynomialFit(order, x, B5openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B5createdTicketsTrend         = (new PolynomialFit(order, x, B5createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B5createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B5createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B6openTicketsTrend            = (new PolynomialFit(order, x, B6openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B6createdTicketsTrend         = (new PolynomialFit(order, x, B6createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B6createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B6createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B7openTicketsTrend            = (new PolynomialFit(order, x, B7openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B7createdTicketsTrend         = (new PolynomialFit(order, x, B7createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B7createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B7createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B8openTicketsTrend            = (new PolynomialFit(order, x, B8openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B8createdTicketsTrend         = (new PolynomialFit(order, x, B8createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B8createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B8createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B9openTicketsTrend            = (new PolynomialFit(order, x, B9openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B9createdTicketsTrend         = (new PolynomialFit(order, x, B9createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B9createdTicketsMoveAvgTrend  = (new PolynomialFit(order, x, B9createdTicketsMoveAvg)).polynomialValuesAsList();

      ArrayList<Double>  B10openTicketsTrend           = (new PolynomialFit(order, x, B10openTickets)).polynomialValuesAsList();
      ArrayList<Double>  B10createdTicketsTrend        = (new PolynomialFit(order, x, B10createdTickets)).polynomialValuesAsList();
      ArrayList<Double>  B10createdTicketsMoveAvgTrend = (new PolynomialFit(order, x, B10createdTicketsMoveAvg)).polynomialValuesAsList();
      /*
      ===============================================
      write some column headers to the output csv file
      ----------------------------------------------- */
      outFile.print("Date,");
      for (int i=0; i<=10; i++)
         {
         XString  hdr1 = new XString("OpenTickets("                            + i +  "),");
         XString  hdr2 = new XString("OpenTicketsTrend("                       + i +  "),");

         XString  hdr3 = new XString("CreatedTickets("                         + i +  "),");
         XString  hdr4 = new XString("CreatedTicketsTrend("                    + i +  "),");

         XString  hdr5 = new XString("CreatedTickets7DayRollingAverage("       + i +  "),");
         XString  hdr6 = new XString("CreatedTickets7DayRollingAverageTrend("  + i +  "),");

         outFile.print(hdr1.string() + hdr2.string() + hdr3.string() + hdr4.string() + hdr5.string() + hdr6.string());
         }
      outFile.println();
      /*
      ===============================================
      write the daily sums and averages to the output the csv file
      ----------------------------------------------- */
      int  numDates   = dates.size();
      for (int dateIdx=0; dateIdx<numDates; dateIdx++)
         {
         outFile.println
            (
            dates.get(dateIdx)                          + "," +

            B0openTickets.get(dateIdx)                  + "," +
            B0openTicketsTrend.get(dateIdx)             + "," +
            B0createdTickets.get(dateIdx)               + "," +
            B0createdTicketsTrend.get(dateIdx)          + "," +
            B0createdTicketsMoveAvg.get(dateIdx)        + "," +
            B0createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B1openTickets.get(dateIdx)                  + "," +
            B1openTicketsTrend.get(dateIdx)             + "," +
            B1createdTickets.get(dateIdx)               + "," +
            B1createdTicketsTrend.get(dateIdx)          + "," +
            B1createdTicketsMoveAvg.get(dateIdx)        + "," +
            B1createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B2openTickets.get(dateIdx)                  + "," +
            B2openTicketsTrend.get(dateIdx)             + "," +
            B2createdTickets.get(dateIdx)               + "," +
            B2createdTicketsTrend.get(dateIdx)          + "," +
            B2createdTicketsMoveAvg.get(dateIdx)        + "," +
            B2createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B3openTickets.get(dateIdx)                  + "," +
            B3openTicketsTrend.get(dateIdx)             + "," +
            B3createdTickets.get(dateIdx)               + "," +
            B3createdTicketsTrend.get(dateIdx)          + "," +
            B3createdTicketsMoveAvg.get(dateIdx)        + "," +
            B3createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B4openTickets.get(dateIdx)                  + "," +
            B4openTicketsTrend.get(dateIdx)             + "," +
            B4createdTickets.get(dateIdx)               + "," +
            B4createdTicketsTrend.get(dateIdx)          + "," +
            B4createdTicketsMoveAvg.get(dateIdx)        + "," +
            B4createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B5openTickets.get(dateIdx)                  + "," +
            B5openTicketsTrend.get(dateIdx)             + "," +
            B5createdTickets.get(dateIdx)               + "," +
            B5createdTicketsTrend.get(dateIdx)          + "," +
            B5createdTicketsMoveAvg.get(dateIdx)        + "," +
            B5createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B6openTickets.get(dateIdx)                  + "," +
            B6openTicketsTrend.get(dateIdx)             + "," +
            B6createdTickets.get(dateIdx)               + "," +
            B6createdTicketsTrend.get(dateIdx)          + "," +
            B6createdTicketsMoveAvg.get(dateIdx)        + "," +
            B6createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B7openTickets.get(dateIdx)                  + "," +
            B7openTicketsTrend.get(dateIdx)             + "," +
            B7createdTickets.get(dateIdx)               + "," +
            B7createdTicketsTrend.get(dateIdx)          + "," +
            B7createdTicketsMoveAvg.get(dateIdx)        + "," +
            B7createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B8openTickets.get(dateIdx)                  + "," +
            B8openTicketsTrend.get(dateIdx)             + "," +
            B8createdTickets.get(dateIdx)               + "," +
            B8createdTicketsTrend.get(dateIdx)          + "," +
            B8createdTicketsMoveAvg.get(dateIdx)        + "," +
            B8createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B9openTickets.get(dateIdx)                  + "," +
            B9openTicketsTrend.get(dateIdx)             + "," +
            B9createdTickets.get(dateIdx)               + "," +
            B9createdTicketsTrend.get(dateIdx)          + "," +
            B9createdTicketsMoveAvg.get(dateIdx)        + "," +
            B9createdTicketsMoveAvgTrend.get(dateIdx)   + "," +

            B10openTickets.get(dateIdx)                 + "," +
            B10openTicketsTrend.get(dateIdx)            + "," +
            B10createdTickets.get(dateIdx)              + "," +
            B10createdTicketsTrend.get(dateIdx)         + "," +
            B10createdTicketsMoveAvg.get(dateIdx)       + "," +
            B10createdTicketsMoveAvgTrend.get(dateIdx)
            );
         }
      /*
      ===============================================
      flush nd close the output csv file
      ----------------------------------------------- */
      outFile.flush();
      outFile.close();
      return successCode;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method counts the number of tickets that were open during any part
   of each day in a list of dates and returns the counts for each day.

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

   @return
      an ArrayList<XString> of the XString representation of the number of
      tickets open for each day

   @param
      pDateList contains a list of all the dates for which a ticket count
      is requested.
   @param
      pTicketCreatedDates contains a list of the created dates for all the
      tickets
   @param
      pTicketClosedDates contains a list of the closed dates for all the
      same tickets
   *//*
   -------------------------------------------------------------- */
   private ArrayList<Double> openTicketsByDate
      (
      ArrayList<XString>  pDateList,
      ArrayList<XString>  pTicketCreatedDates,
      ArrayList<XString>  pTcketClosedDates,
      ArrayList<XString>  pTicketConfigItems,
      XString             pTargetConfigItem
      )
      {
      /*
      ===============================================
      an array to keep the results in
      ----------------------------------------------- */
      ArrayList<Double>  results = new ArrayList<Double>();
      /*
      ===============================================
      multiple target configuration item can be passed in by separating
      each of them with a comma within the string.
      ----------------------------------------------- */
      ArrayList<XString>  targetConfigItems = pTargetConfigItem.tokenizedString(",");
      /*
      ===============================================
      for each date for which a ticket count is requested, sum up the
      number of tickets that were open anytime on that day and print out
      the resulting sum.  A ticket was open sometime during a particular
      day if:
         1) it was created anytime before the end of the particular day AND
         2) it was closed anytime after the start of the particular day
           |-----------------------|   the particular day
         <-------------------------|   created anytime at or before end
           |-------------------------> closed anytime at or after start
      This method catches any tickets that were both opened and closed
      within a particular day.
      ----------------------------------------------- */
      int  numDates   = pDateList.size();
      int  numTickets = pTicketCreatedDates.size();
      for (int dateIdx=0; dateIdx<numDates; dateIdx++)
         {
         int sum = 0;
         /*
         ===============================================
         for each ticket ...
         ----------------------------------------------- */
         for (int ticketIdx=0; ticketIdx<numTickets; ticketIdx++)
            {
            /*
            ===============================================
            only count this ticket if is for the target config item
            ----------------------------------------------- */
            XString  ticketConfigItem = new NCString(pTicketConfigItems.get(ticketIdx));
            boolean  countThisTicket = false;
            for (int tIdx=0; tIdx<targetConfigItems.size(); tIdx++)
               {
               countThisTicket |= ticketConfigItem.contains(targetConfigItems.get(tIdx));
               }
            if (countThisTicket)
               {
               XString  ticketCreatedDate = pTicketCreatedDates.get(ticketIdx);
               XString  ticketClosedDate  = pTcketClosedDates.get(ticketIdx);

               XString  startOfThisDay = pDateList.get(dateIdx).concat(" 00:00");
               XString  endOfThisDay   = pDateList.get(dateIdx).concat(" 23:59");

               boolean  openOnThisDay =
                  (
                  (ticketCreatedDate.compareTo(endOfThisDay)  <= 0) &&  // created at or before the end of this day
                  (ticketClosedDate.compareTo(startOfThisDay) >= 0)     // closed at or after the start of this day
                  );
               if (openOnThisDay) sum++;
               }
            }
         /*
         ===============================================
         add this date's sum to the results list
         ----------------------------------------------- */
         results.add((double)sum);
         }
      /*
      ===============================================
      return the ArrayList of results
      ----------------------------------------------- */
      return results;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method counts the number of tickets that were created during any
   part of each day in a list of dates and returns the counts for each
   day.

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

   @return
      an ArrayList<XString> of the XString representation of the number of
      tickets created on each day

   @param
      pDateList contains a list of all the dates for which a ticket count
      is requested.
   @param
      pTicketCreatedDates contains a list of the created dates for all the
      tickets
   *//*
   -------------------------------------------------------------- */
   private ArrayList<Double> createdTicketsByDate
      (
      ArrayList<XString>  pDateList,
      ArrayList<XString>  pTicketCreatedDates,
      ArrayList<XString>  pTicketConfigItems,
      XString             pTargetConfigItem
      )
      {
      /*
      ===============================================
      an array to keep the results in
      ----------------------------------------------- */
      ArrayList<Double>  results = new ArrayList<Double>();
      /*
      ===============================================
      multiple target configuration item can be passed in by separating
      each of them with a comma within the string.
      ----------------------------------------------- */
      ArrayList<XString>  targetConfigItems = pTargetConfigItem.tokenizedString(",");
      /*
      ===============================================
      for each date for which a ticket count is requested, sum up the
      number of tickets that were created anytime on that day and print out
      the resulting sum.
      ----------------------------------------------- */
      int  numDates   = pDateList.size();
      int  numTickets = pTicketCreatedDates.size();
      for (int dateIdx=0; dateIdx<numDates; dateIdx++)
         {
         int sum = 0;
         /*
         ===============================================
         for each ticket ...
         ----------------------------------------------- */
         for (int ticketIdx=0; ticketIdx<numTickets; ticketIdx++)
            {
            /*
            ===============================================
            only count this ticket if is for the target config item
            ----------------------------------------------- */
            XString  ticketConfigItem = new NCString(pTicketConfigItems.get(ticketIdx));
            boolean  countThisTicket = false;
            for (int tIdx=0; tIdx<targetConfigItems.size(); tIdx++)
               {
               countThisTicket |= ticketConfigItem.contains(targetConfigItems.get(tIdx));
               }
            if (countThisTicket)
               {
               XString  ticketCreatedDate = pTicketCreatedDates.get(ticketIdx);

               XString  startOfThisDay = pDateList.get(dateIdx).concat(" 00:00");
               XString  endOfThisDay   = pDateList.get(dateIdx).concat(" 23:59");

               boolean  openOnThisDay =
                  (
                  (ticketCreatedDate.compareTo(endOfThisDay)   <= 0) &&  // created at or before the end of this day
                  (ticketCreatedDate.compareTo(startOfThisDay) >= 0)     // created at or after the start of this day
                  );
               if (openOnThisDay) sum++;
               }
            }
            /*
            ===============================================
            add this date's sum to the results list
            ----------------------------------------------- */
            results.add((double)sum);
         }
      /*
      ===============================================
      return the ArrayList of results
      ----------------------------------------------- */
      return results;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method counts the number of tickets that were created during any
   part of each day in a list of dates and computes a moving average for
   each day.  It also maintains a count of the total number of tickets
   created during the entire time span represented by the list of dates and
   prints out that count at the end.

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

   @return
      an ArrayList<XString> of the XString representation of the moving
      average of tickets created on each day

   @param
      pDateList contains a list of all the dates for which a ticket count
      is requested.
   @param
      pTicketCreatedDates contains a list of the created dates for all the
      tickets
   @param
      pPeriod is the period of time for which the moving average is computed
   *//*
   -------------------------------------------------------------- */
   private ArrayList<Double> movingAverageOfCreatedTicketsByDate
      (
      ArrayList<XString>  pDateList,
      ArrayList<XString>  pTicketCreatedDates,
      ArrayList<XString>  pTicketConfigItems,
      XString             pTargetConfigItem,
      int                 pPeriod
      )
      {
      /*
      ===============================================
      an array to keep the results in
      ----------------------------------------------- */
      ArrayList<Double>  results = new ArrayList<Double>();
      /*
      ===============================================
      multiple target configuration item can be passed in by separating
      each of them with a comma within the string.
      ----------------------------------------------- */
      ArrayList<XString>  targetConfigItems = pTargetConfigItem.tokenizedString(",");
      /*
      ===============================================
      for each date for which a ticket count is requested, sum up the
      number of tickets that were created anytime on that day and print out
      the resulting sum.
      ----------------------------------------------- */
      int[]  periodArray = new int[pPeriod];
      int    periodIdx   = 0;
      int    numDates    = pDateList.size();
      int    numTickets  = pTicketCreatedDates.size();
      for (int dateIdx=0; dateIdx<numDates; dateIdx++)
         {
         int sum = 0;
         /*
         ===============================================
         for each ticket ...
         ----------------------------------------------- */
         for (int ticketIdx=0; ticketIdx<numTickets; ticketIdx++)
            {
            /*
            ===============================================
            only count this ticket if is for the target config item
            ----------------------------------------------- */
            XString  ticketConfigItem = new NCString(pTicketConfigItems.get(ticketIdx));
            boolean  countThisTicket = false;
            for (int tIdx=0; tIdx<targetConfigItems.size(); tIdx++)
               {
               countThisTicket |= ticketConfigItem.contains(targetConfigItems.get(tIdx));
               }
            if (countThisTicket)
               {
               XString  ticketCreatedDate = pTicketCreatedDates.get(ticketIdx);

               XString  startOfThisDay = pDateList.get(dateIdx).concat(" 00:00");
               XString  endOfThisDay   = pDateList.get(dateIdx).concat(" 23:59");

               boolean  openOnThisDay =
                  (
                  (ticketCreatedDate.compareTo(endOfThisDay)   <= 0) &&  // created at or before the end of this day
                  (ticketCreatedDate.compareTo(startOfThisDay) >= 0)     // created at or after the start of this day
                  );
               if (openOnThisDay) sum++;
               }
            }
         /*
         ===============================================
         ----------------------------------------------- */
         periodArray[periodIdx] = sum;
         periodIdx = UMath.inc(periodIdx,pPeriod);
         /*
         ===============================================
         add this date's sum to the results list
         ----------------------------------------------- */
         results.add(UMath.average(periodArray));
         }
      /*
      ===============================================
      return the ArrayList of results
      ----------------------------------------------- */
      return results;
      }



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

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

   @return
      nothing

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



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

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

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

   @param
      pArgs contains the command line arguments with which the class was
      invoked as an application.
   *//*
   -------------------------------------------------------------- */
   private <Type> boolean initialize(Type[] pArgs) throws Exception
      {
      boolean  successCode = true;
      /*
      ===============================================
      Greetings !
      ----------------------------------------------- */
      System.out.println();
      System.out.println();
      System.out.println();
      System.out.println();
      cOut.banner(CLASS_NAME);
      System.out.println();
      /*
      ===============================================
      tell the user what command line arges this program started with
      ----------------------------------------------- */
      showArgs(pArgs);
      /*
      ===============================================
      this cannot be done statically because it throws an exception.
      ----------------------------------------------- */
      iGlobalProperties = new GlobalProperties();
      /*
      ===============================================
      get ready to process the command line arguments
      ----------------------------------------------- */
      CommandLine  cmdLn = new CommandLine(CLASS_NAME,pArgs);
      /*
      ===============================================
      these are the valid command line controls
      ----------------------------------------------- */
      cmdLn.addControlsFromString(":hqrsl::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");
         }
      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="CountTickets.java.html#010">View source</A>

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



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



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



   /*:                 
   ==============================================================
   ============================================================== *//**
   This method runs the CountTickets 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.CountTickets [-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.

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

      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 CountTickets 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="CountTickets.java.html#011">View source</A>

   @return
      nothing

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



   }  // class CountTickets



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