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

                       Copyright  2002 Allen Baker

---------------------------------------------------------------------------
Class:         DirectoryPruner
Originator:    Allen Baker (2002.06.19)
---------------------------------------------------------------------------
$RCSfile$
$Revision$
$Date$
===========================================================================
*/



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



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


import cosmicabyss.com.lib.*;



/*
=========================================================================== *//**
Description<PRE>
   This program prunes files and subdirectories from a directory if those
   files and subdirectories are not present in a master directory.
</PRE>

Usage<PRE>
   java cosmicabyss.com.app.DirectoryPruner [-h -q] [-l [logFile]] -m masterDirectoryName -t targetDirectoryName
      Arguments can be placed in any order on the command line.

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

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

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

   -m means MASTER DIRECTORY.
      It is a required control.  It takes a required directory name
      parameter, and identifies the directory that the target directory
      will be pruned to match.  The program will delete any files or
      sub-directories that it finds in the target directory but not in the
      master directory.

      Enclosing the masterDirectoryName in quotes is required if the name
      contains embedded spaces.

      The masterDirectoryName must be the name of one and only one
      directory.  Therefor, no wildcard characters are allowed in the name.

   -t means TARGET DIRECTORY.
      It is a required control.  It takes a required directory name
      parameter, and causes the program to prune the named directory to
      match the master directory.  The program will delete any files or
      sub-directories that it finds in the target directory but not in the
      master directory.

      Enclosing the targetDirectoryName in quotes is required if the name
      contains embedded spaces.

      The targetDirectoryName must be the name of one and only one
      directory.  Therefor, no wildcard characters are allowed in the name.

</PRE>

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



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

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

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

      successCode = initialize(pArgs);
      if (successCode)
         {
         successCode = prune();
         }
      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="DirectoryPruner.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 DirectoryPruner 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="DirectoryPruner.java.html#002">View source</A>

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



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



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



   /*
   ===============================================
   Class Constants
      CLASS_NAME  : the name of this class
      DESCRIPTION : the man page description of this application
      USAGE       : the man page usage information for this application
   ----------------------------------------------- */
   private static final XString  CLASS_NAME  = new XString(DirectoryPruner.class.getName());
   private static final XString  DESCRIPTION = new XString
      (
      // <Description>  Preprocessor generated String definition, Don't mess with it.
      "This program prunes files and subdirectories from a directory if those                                               \n" +
      "files and subdirectories are not present in a master directory.                                                      \n" +
      ""// </Description>
      );
   private static final XString  USAGE       = new XString
      (
      // <Usage>        Preprocessor generated String definition, Don't mess with it.
      "java cosmicabyss.com.app.DirectoryPruner [-h -q] [-l [logFile]] -m masterDirectoryName -t targetDirectoryName        \n" +
      "   Arguments can be placed in any order on the command line.                                                         \n" +
      "                                                                                                                     \n" +
      "-h means HELP.                                                                                                       \n" +
      "   It causes this usage message to be displayed, and terminates the                                                  \n" +
      "   program.                                                                                                          \n" +
      "                                                                                                                     \n" +
      "-q means QUIET.                                                                                                      \n" +
      "   It stops the program from sending log messages to stdout. The program                                             \n" +
      "   sends log messages to stdout by default; this option is the only way                                              \n" +
      "   to stop it from doing that.                                                                                       \n" +
      "                                                                                                                     \n" +
      "-l means LOGFILE.                                                                                                    \n" +
      "   It takes an optional file name parameter, and causes the program to                                               \n" +
      "   send log messages to the named file. If the file name is not present,                                             \n" +
      "   the program generates a default file name. If the environment                                                     \n" +
      "   variable LOGDIRECTORY is defined, the program places the file in that                                             \n" +
      "   directory. If not, the program places the file in the current                                                     \n" +
      "   directory. The program continues to send log messages to stdout too,                                              \n" +
      "   unless the -q option is used.                                                                                     \n" +
      "                                                                                                                     \n" +
      "-m means MASTER DIRECTORY.                                                                                           \n" +
      "   It is a required control.  It takes a required directory name                                                     \n" +
      "   parameter, and identifies the directory that the target directory                                                 \n" +
      "   will be pruned to match.  The program will delete any files or                                                    \n" +
      "   sub-directories that it finds in the target directory but not in the                                              \n" +
      "   master directory.                                                                                                 \n" +
      "                                                                                                                     \n" +
      "   Enclosing the masterDirectoryName in quotes is required if the name                                               \n" +
      "   contains embedded spaces.                                                                                         \n" +
      "                                                                                                                     \n" +
      "   The masterDirectoryName must be the name of one and only one                                                      \n" +
      "   directory.  Therefor, no wildcard characters are allowed in the name.                                             \n" +
      "                                                                                                                     \n" +
      "-t means TARGET DIRECTORY.                                                                                           \n" +
      "   It is a required control.  It takes a required directory name                                                     \n" +
      "   parameter, and causes the program to prune the named directory to                                                 \n" +
      "   match the master directory.  The program will delete any files or                                                 \n" +
      "   sub-directories that it finds in the target directory but not in the                                              \n" +
      "   master directory.                                                                                                 \n" +
      "                                                                                                                     \n" +
      "   Enclosing the targetDirectoryName in quotes is required if the name                                               \n" +
      "   contains embedded spaces.                                                                                         \n" +
      "                                                                                                                     \n" +
      "   The targetDirectoryName must be the name of one and only one                                                      \n" +
      "   directory.  Therefor, no wildcard characters are allowed in the name.                                             \n" +
      "                                                                                                                     \n" +
      ""// </Usage>
      );
   /*
   ===============================================
   Class variables
      cOut                       : console output.
      cFileNamesAreCaseSensitive : remembers whether file names and paths
                                   are case sensitive on this OS.
   ----------------------------------------------- */
   private static ConsoleStream  cOut                       = ConsoleStream.getSingleton();
   private static boolean        cFileNamesAreCaseSensitive = Util.fileNamesAreCaseSensitive();
   /*
   ===============================================
   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 XString           iMasterDirName    = null;
   private XString           iTargetDirName    = null;



   /*:                 
   ==============================================================
   ============================================================== *//**
   Prune the target-directory of every file and subdirectory that is not in
   the master-directory.

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

   *//*
   -------------------------------------------------------------- */
   private boolean prune() throws Exception
      {
      /*
      ===============================================
      give the user a chance to bail out.
      ----------------------------------------------- */
      if ( ! userReallyWantsToGoAhead(iMasterDirName,iTargetDirName))
         {
         println();
         println("DirectoryPruner aborted.");
         return true;
         }
      println();
      println("DirectoryPruner proceeding.");
      println();
      /*
      ===============================================
      get a list of all the files in the master directory and all its
      subdirectories.
         The name of the master directory is removed from the front of the
         files so that they are relative file names - relative to the
         master directory
      ----------------------------------------------- */
      println("   Getting    list of files and subdirectories in " + iMasterDirName);
      ArrayList<XString>  masterList = buildFileList(new XFile(iMasterDirName));
      println("   Trimming   list of files and subdirectories in " + iMasterDirName);
      masterList = trimLeftList(masterList,iMasterDirName);
      /*
      ===============================================
      get a list of all the files in the target directory and all its
      subdirectories
         The name of the target directory is removed from the front of the
         files so that they are relative file names - relative to the
         target directory
      ----------------------------------------------- */
      println("   Getting    list of files and subdirectories in " + iTargetDirName);
      ArrayList<XString>  pruneList = buildFileList(new XFile(iTargetDirName));
      println("   Trimming   list of files and subdirectories in " + iTargetDirName);
      pruneList = trimLeftList(pruneList,iTargetDirName);
      /*
      ===============================================
      convert masterList to a set for faster searching.
      ----------------------------------------------- */
      println("   Converting list of files and subdirectories in " + iMasterDirName + " to a set.");
      HashSet<XString>  masterSet = new HashSet<XString>(masterList);
      /*
      ===============================================
      get a list of all the files that are in the target directory but not
      in the master directory
      ----------------------------------------------- */
      println
         (
         "   Getting    list of files and subdirectories in " +
         iTargetDirName                                       +
         " but not in "                                       +
         iMasterDirName
         );
      ArrayList<XString>  deleteList = new ArrayList<XString>();
      Iterator<XString>   iter       = pruneList.iterator();
      while (iter.hasNext())
         {
         XString  name = iter.next();
         if ( ! masterSet.contains(name))
            {
            deleteList.add(name);
            }
         }
      /*
      ===============================================
      Add the name of the target directory to the front of all the files so
      that they are absolute file names.
      ----------------------------------------------- */
      println
         (
         "   Prepending list of files and subdirectories in " +
         iTargetDirName                                       +
         " but not in "                                       +
         iMasterDirName
         );
      deleteList = prependList(deleteList,iTargetDirName);
      /*
      ===============================================
      delete the files in the list
      ----------------------------------------------- */
      println
         (
         "   Deleting   list of files and subdirectories in " +
         iTargetDirName                                       +
         " but not in "                                       +
         iMasterDirName
         );
      deleteList(deleteList);
      return true;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   Make sure the parameter names a valid directory.

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

   *//*
   -------------------------------------------------------------- */
   private File getDirectory(XString pDirName) throws Exception
      {
      File  directory = new File(pDirName.toString());
      if ( ! directory.isDirectory())
         {
         Exception exception = new Exception(pDirName + " is not a directory.");
         throw exception;
         }
      return directory;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   Build a list of all the files and subdirectories in a directory and
   recursively descend the subdirectories to add their files and
   subdirectories to the list.

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

   *//*
   -------------------------------------------------------------- */
   private ArrayList<XString> buildFileList(File pDirectory) throws Exception
      {
      ArrayList<XString>  resultList = new ArrayList<XString>();
      /*
      ===============================================
      Create list of the files that reside within the directory
      ----------------------------------------------- */
      String  fileList[] = pDirectory.list();
      for (int i=0; i<fileList.length; i++)
         {
         File  currentFile = new File(pDirectory, fileList[i]);
         if (currentFile.isDirectory())
            {
            /*
            ===============================================
            Sub-directory is found in the directory tree
            ----------------------------------------------- */
            resultList.addAll(buildFileList(currentFile));
            resultList.add(toXString(currentFile.getCanonicalPath()));
            }
         else
            {
            /*
            ===============================================
            Display file names with their pathnames in a
            directory tree
            ----------------------------------------------- */
            resultList.add(toXString(currentFile.getCanonicalPath()));
            }
         }
      return resultList;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   Remove a prefix string from all the file and directory names in a list.

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

   *//*
   -------------------------------------------------------------- */
   private ArrayList<XString> trimLeftList(ArrayList<XString> pList, XString pPrefix) throws Exception
      {
      ArrayList<XString>  resultList = new ArrayList<XString>();
      Iterator<XString>   iter       = pList.iterator();
      while (iter.hasNext())
         {
         XString  original = iter.next();
         XString  trimmed  = original.trimLeft(pPrefix);
         resultList.add(trimmed);
         }
      return resultList;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   Add a prefix string to all the file and directory names in a list.

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

   *//*
   -------------------------------------------------------------- */
   private ArrayList<XString> prependList(ArrayList<XString> pList, XString pPrefix) throws Exception
      {
      ArrayList<XString>  resultList = new ArrayList<XString>();
      Iterator<XString>   iter       = pList.iterator();
      while (iter.hasNext())
         {
         XString  original  = iter.next();
         XString  prepended = toXString(pPrefix.toString() + original.toString());
         resultList.add(prepended);
         }
      return resultList;
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   Display the name of all the files and directories named in a list.

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

   *//*
   -------------------------------------------------------------- */
   private void displayList(List<XString> pList)
      {
      Iterator  iter = pList.iterator();
      while (iter.hasNext())
         {
         println(iter.next());
         }
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   Delete all the files and directories named in a list.

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

   *//*
   -------------------------------------------------------------- */
   private void deleteList(List<XString> pList)
      {
      Iterator<XString>  iter = pList.iterator();
      while (iter.hasNext())
         {
         XString  fileName = iter.next();
         File     file     = new File(fileName.toString());
         if (file.isDirectory())
            {
            println("Deleting DIRECTORY: " + fileName);
            }
         else
            {
            println("Deleting FILE: " + fileName);
            }
         file.delete();
         }
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   Ask the user if they really want to go ahead with the directory prunning.
      Tell me what you want, what you really really want.
      I'll tell you what I want, what I really really want.
      So tell me what you want, what you really really want.

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

   *//*
   -------------------------------------------------------------- */
   private boolean userReallyWantsToGoAhead
      (
      XString  pMasterDirName,
      XString  pTargetDirName
      )
      throws Exception
      {
      BufferedReader  bufferedReader = new BufferedReader
         (
         new InputStreamReader(System.in)
         );
      while (true)
         {
         System.out.println();
         System.out.print
            (
            "Are you sure you want to prune [" +
            pTargetDirName                     +
            "] to match ["                     +
            pMasterDirName                     +
            "], YES or NO ? "
            );
         String  answer = bufferedReader.readLine().toUpperCase();
         if (answer.equals("YES")) return true;
         if (answer.equals("NO"))  return false;
         if (answer.equals("N"))   return false;
         System.out.println();
         System.out.println
            (
            "  \"" +
            answer +
            "\" is not a valid answer. Try again."
            );
         }
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This class's println writes messages to a message log.

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

   *//*
   -------------------------------------------------------------- */
   private void println()
      {
      cOut.println();
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This class's println writes messages to a message log.

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

   *//*
   -------------------------------------------------------------- */
   private <Type> void println(Type pMsg)
      {
      cOut.println(pMsg);
      }



   /*:                 
   ==============================================================
   ============================================================== *//**
   This class's println writes messages to a message log.

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

   *//*
   -------------------------------------------------------------- */
   private <Type> XString toXString(Type pStr)
      {
      return (cFileNamesAreCaseSensitive)? XString.toXString(pStr) : NCString.toNCString(pStr);
      }



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

   <P><B>Implementation: </B><A HREF="DirectoryPruner.java.html#014">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="DirectoryPruner.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 initialize(Type[] pArgs) throws Exception
      {
      boolean  successCode = true;
      /*
      ===============================================
      Greetings !
      ----------------------------------------------- */
      System.out.println();
      System.out.println();
      System.out.println();
      System.out.println();
      cOut.banner(CLASS_NAME);
      System.out.println();
      /*
      ===============================================
      tell the user what command line arges this program started with
      ----------------------------------------------- */
      showArgs(pArgs);
      /*
      ===============================================
      this cannot be done statically because it throws an exception.
      ----------------------------------------------- */
      iGlobalProperties = new GlobalProperties();
      /*
      ===============================================
      get ready to process the command line arguments
      ----------------------------------------------- */
      CommandLine  cmdLn = new CommandLine(CLASS_NAME,pArgs);
      /*
      ===============================================
      these are the valid command line controls
      ----------------------------------------------- */
      cmdLn.addControlsFromString(":hql::m:t:");
      cmdLn.makeControlMandatory("-m");
      cmdLn.makeControlMandatory("-t");
      cmdLn.makeControlNonMandatory("+");
      /*
      ===============================================
      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 (result == false)
         {
         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 (ctl.equals("-m"))
            {
            File dir       = getDirectory(argStr);
            iMasterDirName = toXString(dir.getCanonicalPath());
            }
         if (ctl.equals("-t"))
            {
            File dir       = getDirectory(argStr);
            iTargetDirName = toXString(dir.getCanonicalPath());
            }
         }
      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="DirectoryPruner.java.html#016">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 DirectoryPruner 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.DirectoryPruner [-h -q] [-l [logFile]] -m masterDirectoryName -t targetDirectoryName
      Arguments can be placed in any order on the command line.

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

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

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

   -m means MASTER DIRECTORY.
      It is a required control.  It takes a required directory name
      parameter, and identifies the directory that the target directory
      will be pruned to match.  The program will delete any files or
      sub-directories that it finds in the target directory but not in the
      master directory.

      Enclosing the masterDirectoryName in quotes is required if the name
      contains embedded spaces.

      The masterDirectoryName must be the name of one and only one
      directory.  Therefor, no wildcard characters are allowed in the name.

   -t means TARGET DIRECTORY.
      It is a required control.  It takes a required directory name
      parameter, and causes the program to prune the named directory to
      match the master directory.  The program will delete any files or
      sub-directories that it finds in the target directory but not in the
      master directory.

      Enclosing the targetDirectoryName in quotes is required if the name
      contains embedded spaces.

      The targetDirectoryName must be the name of one and only one
      directory.  Therefor, no wildcard characters are allowed in the name.

   </PRE>

   <P><B>Implementation: </B><A HREF="DirectoryPruner.java.html#017">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
      {
      System.out.println("System.out");
      cOut.println("cOut");
      DirectoryPruner  thisDirectoryPruner = new DirectoryPruner(pArgs);
      }



   }  // class DirectoryPruner



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