/*::.
==================================================================================================================================
=================================================¦ Copyright © 2007 Allen Baker ¦=================================================
                                                 +------------------------------+
File:       JavaFile.java
Originator: Allen Baker (2007.09.07 18:48)
LayoutRev:  5
================================================================================================================================== */



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



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



/*::
======================================================================================================================== *//**
Instances of this class are TextFiles containing Java source code.

<P>
   <DL>
      <DT>
         <B>
            Example usage:
         </B>
         <DD>
            <BLOCKQUOTE>
               <PRE id="unindent">
                  no example provided
               </PRE>
            </BLOCKQUOTE>
         </DD>
      </DT>
      <DT>
         <B>
            View Source:
         </B>
         <DD>
            <A href="JavaFile.java.html">
               JavaFile.java
            </A>
         </DD>
      </DT>
      <DT>
         <B>
            Author:
         </B>
         <DD>
            <A href="mailto:sourcecode.v01@cosmicabyss.com">
               Allen Baker
            </A>
         </DD>
      </DT>
   </DL>
*//*
======================================================================================================================== */
public class JavaFile extends TextFile
   {
   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates an instance of the JavaFile class.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public JavaFile(XFile xfile) throws Exception
      {
      super(xfile.getCanonicalPath());
      this.layoutVersion();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates an instance of the JavaFile class.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public JavaFile(TextFile tfile) throws Exception
      {
      super(tfile.getCanonicalPath());
      this.layoutVersion();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates an instance of the JavaFile class.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public JavaFile(JavaFile tfile) throws Exception
      {
      super(tfile.getCanonicalPath());
      this.layoutVersion();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates an instance of the JavaFile class.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public JavaFile(URI uri) throws Exception
      {
      super(uri);
      this.layoutVersion();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates an instance of the JavaFile class.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public JavaFile(File file) throws Exception
      {
      super(file.getCanonicalPath());
      this.layoutVersion();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates an instance of the JavaFile class.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public <Type> JavaFile(File parent, Type child) throws Exception
      {
      super(parent,child);
      this.layoutVersion();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates an instance of the JavaFile class.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public <Type> JavaFile(Type pathname) throws Exception
      {
      super(pathname);
      this.layoutVersion();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates an instance of the JavaFile class.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public <Type1,Type2> JavaFile(Type1 parent, Type2 child) throws Exception
      {
      super(parent,child);
      this.layoutVersion();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method preprocesss a java file.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void preprocess() throws Exception
      {
      if (iJavaFile != null)
         {
         iJavaFile.preprocess();
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method removes the comments from this source code file. It strips out standard comments and
   double slash comments and nested comments

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void stripComments() throws Exception
      {
      this.stripDelimitedSubstrings("/*", "*/");
      this.stripDelimitedSubstrings("//", "\n", false, false);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method counts the uncommented lines of code in a java, c, or c++ source code file.

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

   @return
      The number of uncommented lines of code
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public int linesOfCode() throws Exception
      {
      return JavaFile.linesOfCode(this.getCanonicalPath());
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to cOut all the unmodified method declarations in this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnUnmodifiedMethodDeclarations() throws Exception
      {
      for (XString value : this.listUnmodifiedMethodDeclarations())
         {
         cOut.println(value);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to cOut all the method declarations in this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnMethodDeclarations() throws Exception
      {
      for (XString value : this.listMethodDeclarations())
         {
         cOut.println(value);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to cOut all the method signatures in this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnMethodSignatures() throws Exception
      {
      for (XString value : this.listMethodSignatures())
         {
         cOut.println(value);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to cOut all the method names in this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnMethodNames() throws Exception
      {
      for (XString value : this.listMethodNames())
         {
         cOut.println(value);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to cOut all the method parameter lists in this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnMethodParameterLists() throws Exception
      {
      for (XString value : this.listMethodParameterLists())
         {
         cOut.println(value);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to cOut all the method scopes (class or instance) in this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnMethodClassOrInstance() throws Exception
      {
      for (XString value : this.listMethodClassOrInstance())
         {
         cOut.println(value);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to cOut all the method parameter counts in this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnMethodParameterCounts() throws Exception
      {
      for (XString value : this.listMethodParameterCounts())
         {
         cOut.println(value);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to Sysout an ArrayList of the groups from every match of a regular expression for
   finding method declarations against this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnMethodDeclarationSubstrings() throws Exception
      {
      for (ArrayList<XString> method : this.listMethodDeclarationSubstrings())
         {
         boolean  first = true;
         for (XString value : method)
            {
            if (first)
               {
               first = false;
               System.out.println();
               System.out.println();
               System.out.println();
               System.out.println
                  (
                  "/*\n"                                                                                                              +
                  "==============================================================================================================\n"  +
                  "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"  +
                  "=============================================================================================================="
                  );
               System.out.println(value);
               System.out.println
                  (
                  "-------------------------------------------------------------------------------------------------------------- */"
                  );
               }
            else
               {
               System.out.println(value);
               }
            }
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the unmodified method declarations in this JavaFile.

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

   @return
      This method returns an ArrayList of all the unmodified method declarations in this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listUnmodifiedMethodDeclarations() throws Exception
      {
      return this.listSpecifiedSubstringForEachMethodDeclaration(0);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the method declarations in this JavaFile.

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

   @return
      This method returns an ArrayList of all the method declarations in this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listMethodDeclarations() throws Exception
      {
      return this.listSpecifiedSubstringForEachMethodDeclaration(1);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the method signatures in this JavaFile.

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

   @return
      This method returns an ArrayList of all the method signatures in this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listMethodSignatures() throws Exception
      {
      return this.listSpecifiedSubstringForEachMethodDeclaration(2);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the method names in this JavaFile.

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

   @return
      This method returns an ArrayList of all the method names in this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listMethodNames() throws Exception
      {
      return this.listSpecifiedSubstringForEachMethodDeclaration(3);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the method parameter lists in this JavaFile.

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

   @return
      This method returns an ArrayList of all the method parameter lists in this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listMethodParameterLists() throws Exception
      {
      return this.listSpecifiedSubstringForEachMethodDeclaration(4);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the method scopes (class or instance) in this JavaFile.

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

   @return
      This method returns an ArrayList of all the method scopes (class or instance) in this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listMethodClassOrInstance() throws Exception
      {
      return this.listSpecifiedSubstringForEachMethodDeclaration(6);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the method parameter counts in this JavaFile.

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

   @return
      This method returns an ArrayList of all the method parameter counts in this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listMethodParameterCounts() throws Exception
      {
      return this.listSpecifiedSubstringForEachMethodDeclaration(7);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the specified method substrings in this JavaFile. For each
   method declaration in this file, there should be one substring in the returned ArrayList.

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

   @return
      This method returns an ArrayList of all the specified method substrings in this JavaFile.

   @param
      pGroupNumber specifies which method substring to return.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listSpecifiedSubstringForEachMethodDeclaration(int pSubstringNumber) throws Exception
      {
      ArrayList<XString>      results                     = new ArrayList<XString>();
      ListOfLists<XString>    methodDeclarationSubstrings = listMethodDeclarationSubstrings();
      for (ArrayList<XString> methodDeclarationSubstring : methodDeclarationSubstrings)
         {
         if (pSubstringNumber < methodDeclarationSubstring.size())
            {
            results.add(methodDeclarationSubstring.get(pSubstringNumber));
            }
         }
      return results;
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of the groups from every match of a regular expression for finding
   method declarations against this JavaFile.

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

   @return
      This method returns an ArrayList of the groups from every match of a regular expression against
      this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ListOfLists<XString> listMethodDeclarationSubstrings() throws Exception
      {
      XStringsIterator iter = new XStringsIterator(this);
      StringBuffer     strB = new StringBuffer();
      while (iter.hasNext())
         {
         XString  line = iter.next().concat("\n");
         strB.append(line.toString());
         }
      iter = null;
      return JavaFile.listMethodDeclarationSubstrings(strB.toString());
      }



   public void listMethodDeclarationNamedSubstrings() throws Exception
      {
      XStringsIterator iter = new XStringsIterator(this);
      StringBuffer     strB = new StringBuffer();
      while (iter.hasNext())
         {
         XString  line = iter.next().concat("\n");
         strB.append(line.toString());
         }
      iter = null;



      XString              str               = new XString(strB);
      ArrayList<XString> groupNames = new ArrayList<XString>();


      groupNames.add(new XString("ACCESS"));
      groupNames.add(new XString("MODIFIERS"));
      groupNames.add(new XString("TYPEPARAMETERS"));
      groupNames.add(new XString("RETURNTYPE"));
      groupNames.add(new XString("METHODNAME"));
      groupNames.add(new XString("THROWER"));
      groupNames.add(new XString("PARAMETERLIST"));
      ListOfMaps<XString, XString> substringMapList = str.matchNamedGroupResults(JavaFile.REGEX_FIND_METHODS, groupNames);
      for (HashMap<XString, XString> map : substringMapList)
         {
         System.out.println();
         System.out.println();
         namedSubstringPrintln("ACCESS", map);
         namedSubstringPrintln("MODIFIERS", map);
         namedSubstringPrintln("TYPEPARAMETERS", map);
         namedSubstringPrintln("RETURNTYPE", map);
         namedSubstringPrintln("METHODNAME", map);
         namedSubstringPrintln("THROWER", map);
         namedSubstringPrintln("PARAMETERLIST", map);
         }
      }

private static <Type1> void namedSubstringPrintln(Type1 pGroupName, HashMap<XString, XString> pMap)
   {
   XString  groupName  = new XString(pGroupName);
   XString  label      = groupName;
   XString  groupValue = pMap.get(groupName);
   if (groupValue == null) groupValue = XString.EMPTY;
   label = label.alignLeft(label.length() + 1, ' ');
   label = label.alignLeft(20, '-').concat(" ");
   System.out.println(label.concat(groupValue));
   }


   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of the substrings from every match of a regular expression for
   finding method declarations against a specified String-compatible object such as an XString or
   String.

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

   @return
      This method returns an ArrayList of the substrings from every match of a regular expression
      against a specified String-compatible object such as an XString or String.

   @param
      pStr is the Object whose String representation is matched against a regular expression for
      finding method declarations.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static <Type1> ListOfLists<XString> listMethodDeclarationSubstrings(Type1 pStr)
      {
      /*.
      ==========================================================================================
      Convert the Object to search into an XString and find all the method declarations in it
      using the regular expression. This is going to return an ArrayList of substrings for each
      method declaration located. Each list of substrings contains various substrings of the
      method declaration.
      ------------------------------------------------------------------------------------------ */
      XString              str               = new XString(pStr);
      ListOfLists<String>  substringListList = UString.matchResultsGroups(str, JavaFile.REGEX_FIND_METHODS);
      /*.
      ==========================================================================================
      For each method declaration found, get its substring list.
      ------------------------------------------------------------------------------------------ */
      for (ArrayList<String> substringList : substringListList)
         {
//         /*.
//         ==========================================================================================
//         We're going to add a couple of things to this substring list. The first thing we will add
//         is a string indicating if this found method declaration is for a class (static) method or
//         an instance method.
//         ------------------------------------------------------------------------------------------ */
//         XString declarationSubstring = substringList.get(0);
//         XString classOrInstance      = new XString(declarationSubstring.containsIgnoreCase("static")? "class" : "instance");
//         substringList.add(classOrInstance);
//         /*.
//         ==========================================================================================
//         The second thing we will add is the string representation of a count of the number of
//         paramaters in this method declaration.
//         ------------------------------------------------------------------------------------------ */
//         XString parametersSubstring  = substringList.get(3);
//         int     parameterCount       = 0;
//         if (parametersSubstring.toString() != null) parameterCount = parametersSubstring.substringCount(",") + 1;
//         substringList.add(new XString(String.valueOf(parameterCount)));
//         /*.
//         ==========================================================================================
//         Now we're going to modify some of the substrings in this method declaration substring list
//         to get rid of newlines and extra spaces.
//         ------------------------------------------------------------------------------------------ */
//         for (int idx = 0; idx < substringList.size(); idx++)
//            {
//            /*.
//            ==========================================================================================
//            Get the idx'th substring of this method declaration substring list
//            ------------------------------------------------------------------------------------------ */
//            XString substring = substringList.get(idx);
//            /*.
//            ==========================================================================================
//            Modify the idx'th substring and replace it in the method declaration substring list
//            ------------------------------------------------------------------------------------------ */
//            if (substring.toString() != null)
//               {
//               substring = substring.iteratingReplace("\n", "");
//               substring = substring.iteratingReplace("  ", " ");
//               substring = substring.iteratingReplace(" ( ", "(");
//               substring = substring.iteratingReplace("( ",  "(");
//               substring = substring.iteratingReplace(" (",  "(");
//               substring = substring.iteratingReplace(" ) ", ")");
//               substring = substring.iteratingReplace(") ",  ")");
//               substring = substring.iteratingReplace(" )",  ")");
//               substringList.set(idx, substring);
//               }
//            }
//         /*.
//         ==========================================================================================
//         Add the unmodified full declaration back as the first element in the list
//         ------------------------------------------------------------------------------------------ */
//         substringList.add(0, declarationSubstring);
         }
      return XString.toListOfXStringLists(substringListList);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of MatchResults. The MatchResults come from finding all the matches
   in a string to a regular expression. In particular, the regular expression used for finding matches
   is designed to match method declarations.

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

   @return
      This method returns an ArrayList of MatchResults. The MatchResults come from finding all the
      matches in a string to a regular expression. In particular, the regular expression used for
      finding matches is designed to match method declarations.

   @param
      pStr is the Object whose XString representation is searched for matches to the regular
      expression.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static <Type1> ArrayList<MatchResult> methodDeclarationsMatchResults(Type1 pStr)
      {
      XString str = new XString(pStr);
      return str.matchResults(JavaFile.REGEX_FIND_METHODS);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints to cOut all the method calls in this JavaFile.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void printlnMethodCalls() throws Exception
      {
      for (XString value : this.listMethodCalls())
         {
         cOut.println(value);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the method calls in this JavaFile.

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

   @return
      This method returns an ArrayList of all the method parameter counts in this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listMethodCalls() throws Exception
      {
      return this.listSpecifiedSubstringForEachMethodCall(0);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of all the specified method call substrings in this JavaFile.
   Currently, there is only one substring, the method being called.

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

   @return
      This method returns an ArrayList of all the specified method call substrings in this JavaFile.

   @param
      pGroupNumber specifies which method substring to return.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ArrayList<XString> listSpecifiedSubstringForEachMethodCall(int pSubstringNumber) throws Exception
      {
      ArrayList<XString>      results              = new ArrayList<XString>();
      ListOfLists<XString>    methodCallSubstrings = listMethodCallSubstrings();
      for (ArrayList<XString> methodCallSubstring : methodCallSubstrings)
         {
         if (pSubstringNumber < methodCallSubstring.size())
            {
            results.add(methodCallSubstring.get(pSubstringNumber));
            }
         }
      return results;
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of the substrings from every match of a regular expression for
   finding method declarations against this file. Currently, there is only one substring, the method
   being called.

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

   @return
      This method returns an ArrayList of the substrings from every match of a regular expression
      against this JavaFile.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public ListOfLists<XString> listMethodCallSubstrings() throws Exception
      {
      XStringsIterator  iter = new XStringsIterator(this);
      StringBuffer      strB = new StringBuffer();
      while (iter.hasNext())
         {
         XString  line = iter.next().concat("\n");
         strB.append(line.toString());
         }
      iter = null;
      return JavaFile.listMethodCallSubstrings(strB.toString());
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of the substrings from every match of a regular expression for
   finding method declarations against a specified String-compatible object such as an XString or
   String.

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

   @return
      This method returns an ArrayList of the substrings from every match of a regular expression
      against a specified String-compatible object such as an XString or String.

   @param
      pStr is the Object whose String representation is matched against a regular expression for
      finding method declarations.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static <Type1> ListOfLists<XString> listMethodCallSubstrings(Type1 pStr)
      {
      /*.
      ==========================================================================================
      Convert the Object to search into an XString and find all the method calls in it using the
      regular expression. This is going to return an ArrayList of substrings for each method
      call located. Each list of substrings contains various substrings of the method call.
      ------------------------------------------------------------------------------------------ */
      XString               str               = new XString(pStr);
      ListOfLists<XString>  substringListList = str.matchResultsGroups(JavaFile.REGEX_FIND_METHOD_CALLS);
      return substringListList;
      }



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

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

   @return
      A reference to this object

   @param
      pConsole is a ConsoleStream through which this objects sends its output.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static <Type1> ArrayList<MatchResult> methodCallsMatchResults(Type1 pStr)
      {
      XString str = new XString(pStr);
      return str.matchResults(JavaFile.REGEX_FIND_METHOD_CALLS);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns an ArrayList of MatchResults. The MatchResults come from finding all the matches
   in a string to a regular expression. In particular, the regular expression used for finding matches
   is designed to match method calls.

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

   @return
      This method returns an ArrayList of MatchResults. The MatchResults come from finding all the
      matches in a string to a regular expression. In particular, the regular expression used for
      finding matches is designed to match method calls.

   @param
      pStr is the Object whose XString representation is searched for matches to the regular
      expression.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static <Type1, Type2> ArrayList<MatchResult> namedMethodCallsMatchResults(Type1 pStr, Type2 pMethodName)
      {
      XString  str        = new XString(pStr);
      XString  methodName = new XString(pMethodName);
      XString  regex      = new XString(JavaFile.REGEX_FIND_NAMED_METHOD_CALL);
      regex = regex.replace("%METHOD_NAME%", methodName);
      return str.matchResults(regex);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method finds instances of unqualified method calls within this file. A qualified method call is
   of the form:
      <BLOCKQUOTE>
         [instanceName|className].methodName(..)
      </BLOCKQUOTE>

   An unqualified method call is of the form:
      <BLOCKQUOTE>
         MethodName(..)
      </BLOCKQUOTE>

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void findUnqualifiedMethodCalls() throws Exception
      {
      /*.
      ==========================================================================================
      Build a StringBuffer consisting of this entire file.
      ------------------------------------------------------------------------------------------ */
      XStringsIterator  iter = new XStringsIterator(this);
      StringBuffer      strB = new StringBuffer();
      while (iter.hasNext())
         {
         XString  line = iter.next().concat("\n");
         strB.append(line.toString());
         }
      iter = null;
      /*.
      ==========================================================================================
      Get a list of method names, eliminate duplicates, and sort it.
      ------------------------------------------------------------------------------------------ */
      ArrayList<XString>  methodNamesList = listMethodNames();
      HashSet<XString>    methodNamesSet  = new HashSet<XString>(methodNamesList);
      methodNamesList = new ArrayList<XString>(methodNamesSet);
      methodNamesList = Util.sortedArrayList(methodNamesList);
      /*.
      ==========================================================================================
      Find all the unqualified call for each method name
      ------------------------------------------------------------------------------------------ */
      ArrayList<MatchResult>  unqualifiedMethodCalls = new ArrayList<MatchResult>();
      for (XString methodName: methodNamesList)
         {
         unqualifiedMethodCalls.addAll(namedMethodCallsMatchResults(strB, methodName));
         }
      /*.
      ==========================================================================================
      Print out each one
      ------------------------------------------------------------------------------------------ */
      for (MatchResult mr : unqualifiedMethodCalls)
         {
         /*.
         ==========================================================================================
         Find the start of line that this match is on
         ------------------------------------------------------------------------------------------ */
         int  start = mr.start();
         while (strB.charAt(start) != '\n') start--;
         start++;
         /*.
         ==========================================================================================
         Find the end of line that this match is on
         ------------------------------------------------------------------------------------------ */
         int  end = mr.end();
         while (strB.charAt(end) != '\n') end++;
         /*.
         ==========================================================================================
         Print out the line
         ------------------------------------------------------------------------------------------ */
         XString  printString = new XString(strB.substring(start, end));
         if ( ! (printString.contains("public") || printString.contains("protected") || printString.contains("private")))
            {
            System.out.println(printString);
            /*.
            ==========================================================================================
            Print out the unqualified methodName
            ------------------------------------------------------------------------------------------ */
            XString  methodName = new XString(strB.substring(mr.start(), mr.end()));
            methodName = methodName.trim().trimLeft("(");
            System.out.println(methodName);
            }
         }
      }



//   public XString getMethodCalls(Type1 pStr, Type2 pDeclaration) throws Exception



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints th stdout the code portion of all the methods in this file. The code portion is
   that part of the source code for a method that does not include the header comment or anything
   between the header comment and the method declaration such as a supresswarnings annotation.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void listMethodsCode() throws Exception
      {
      /*.
      ==========================================================================================
      Build a StringBuffer consisting of this entire file.
      ------------------------------------------------------------------------------------------ */
      XStringsIterator  iter = new XStringsIterator(this);
      StringBuffer      strB = new StringBuffer();
      while (iter.hasNext())
         {
         XString  line = iter.next().concat("\n");
         strB.append(line.toString());
         }
      iter = null;
      /*.
      ==========================================================================================
      ------------------------------------------------------------------------------------------ */
      ArrayList<XString> methods = this.listUnmodifiedMethodDeclarations();
      for (XString decl : methods)
         {
         XString  code = this.getMethodCode(strB, decl);
         System.out.println();
         System.out.println();
         System.out.println();
//         System.out.println
//            (
//            "/*\n"                                                                                                              +
//            "==============================================================================================================\n"  +
//            "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"  +
//            "=============================================================================================================="
//            );
//         System.out.println
//            (
//            "-------------------------------------------------------------------------------------------------------------- */"
//            );
         System.out.println(code);
         }
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method gets the code portion of a specified method. The code portion is that part of the source
   code for a method that does not include the header comment or anything between the header comment
   and the method declaration such as a supresswarnings annotation.

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

   @return
      This method gets the code portion of a specified method.

   @param
      pStr is the Object whose XString representation will be searched for the specified method's code
   @param
      pDeclaration is the declaration statement for the method tyo get the code for.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public <Type1, Type2> XString getMethodCode(Type1 pStr, Type2 pDeclaration) throws Exception
      {
      XString  str  = new XString(pStr);
      XString  decl = new XString(pDeclaration);
      int      methodStart = str.indexOf(decl);
      int      openBrace   = str.indexOf("{", methodStart);
      int      endBrace    = (int)str.indexAfterDelimitedSpan("{", "}", openBrace + 1);
      XString  code        = str.substring(methodStart, endBrace);
      return code;
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method wordwraps text blocks within line comments (comments delineated by "//"). It only wraps
   those that are within full line comments, i.e., lines that only contain a comment and do not contain
   any code. So end-of-line or trailing line comments are not wrapped.

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

   @param
      pLineLength is the line length at which the comments are word wrapped.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void wordWrapLineComments(int pLineLength) throws Exception
      {
      this.modify("wordWrapLineComments", pLineLength);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method reads Strings from an iterator over this TextFile (pIter), modifies them, and writes
   them out to an output (pOutput).<P>

   The modification this method performs is wordwrapping of text blocks within line comments (comments
   delineated by "//"). It only wraps those that are within full line comments, i.e., lines that only
   contain a comment and do not contain any code. So end-of-line or trailing line comments are not
   wrapped.

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

   @param
      pIter is an XStringsIterator for reading this TextFile
   @param
      pOutput is a TextWriter for writing the modified content of this TextFile to the output file.
   @param
      pArguments is a variable sized list of arguments and this method expects it to contain:
         <BLOCKQUOTE>
            pArguments[0]: int lineLength
               <BLOCKQUOTE>
                  Is the line length at which the comments are word wrapped.
               </BLOCKQUOTE>
         </BLOCKQUOTE>
   *//*
   ---------------------------------------------------------------------------------------------------- */
   @SuppressWarnings("unchecked")
   public <Type1> void wordWrapLineComments(XStringsIterator pIter, TextWriter pOutput, Object... pArguments) throws Exception
      {
      /*.
      ==========================================================================================
      Get the arguments
      ------------------------------------------------------------------------------------------ */
      int  lineLength = (int)pArguments[0];
      /*.
      ==========================================================================================
      create and launch a state machine to wrap the comments
      ------------------------------------------------------------------------------------------ */
      StateMachine  sm = new StateMachine(pIter, pOutput, lineLength);
      sm.run();
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method applies the Allman style of indent. C++ preprocessor logic IS indented by default.

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

   @param
      pIndentSize is the number of spaces to indent for each code block level.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void allmanStyle(int pIndentSize) throws Exception
      {
      this.modify("allmanStyle", pIndentSize, false);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method applies the Allman style of indent. C++ preprocessor logic IS or IS NOT indented
   according to the argument value that is passed in through the pNopp parameter.

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

   @param
      pIndentSize is the number of spaces to indent for each code block level.
   @param
      pNopp is a control that if true: turns OFF C++ preprocessor logic indenting; otherwise, if false:
      it leaves C++ preprocessor indenting in its default state in which C++ preprocessor logic IS
      indented.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void allmanStyle(int pIndentSize, boolean pNopp) throws Exception
      {
      this.modify("allmanStyle", pIndentSize, pNopp);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method reads Strings from an iterator over this TextFile (pIter), modifies them, and writes
   them out to an output (pOutput).<P>

   The modification this method performs is applying the Allman style indent.

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

   @param
      pIter is an XStringsIterator for reading this TextFile
   @param
      pOutput is a TextWriter for writing the modified content of this TextFile to the output file.
   @param
      pArguments is a variable sized list of arguments and this method expects it to contain:
         <BLOCKQUOTE>
            pArguments[0]: int indentSize
               <BLOCKQUOTE>
                  Is the number of spaces to indent for each code block level.
               </BLOCKQUOTE>
            pArguments[0]: boolean nopp
               <BLOCKQUOTE>
                  Is a control that if set to true, turns OFF C++ preprocessor logic indenting. If
                  false, C++ logic is turned ON.
               </BLOCKQUOTE>
         </BLOCKQUOTE>
   *//*
   ---------------------------------------------------------------------------------------------------- */
   @SuppressWarnings("unchecked")
   public <Type1> void allmanStyle(XStringsIterator pIter, TextWriter pOutput, Object... pArguments) throws Exception
      {
      /*.
      ==========================================================================================
      Get the arguments
      ------------------------------------------------------------------------------------------ */
      int      indentSize = (int)pArguments[0];
      boolean  nopp       = (boolean)pArguments[1];
      /*.
      ==========================================================================================
      turn the C++ preprocessor logic indenting logic around to make it easier to understand
      ------------------------------------------------------------------------------------------ */
      boolean  indentpp = !nopp;
      /*.
      ==========================================================================================
      => indent      is a string containing one indent
      => level       is the current indentation level
      => isIniting   is a property of the line just read that is true if the line is part of a
                     constructor initialization
      => line        is the unmodified line just read
      => trimmed     is the line just read minus its leading and trailing whitespace
      => noWs        is the line just read minus all its whitespace
      => lopped      is the line just read minus all its whitespace minus any "//"  delimited
                     comment minus any trailing ";"
      => countOpenP  is the count of the number of open parens in the line just read
      => countCloseP is the count of the number of close parens in the line just read
      => countOpenB  is the count of the number of open braces in the line just read
      => countcloseB is the count of the number of close braces in the line just read
      => isBalancedP is a property of the line just read that is true if the line has the same
                     number of open parens and close parens
      => isBalancedB is a property of the line just read that is true if the line has the same
                     number of open braces and close braces
      => isAccess    is a property of the line just read that is true if the line contains is an
                     access specifier
      ------------------------------------------------------------------------------------------ */
      XString  indent    = XString.fill(indentSize, ' ');
      int      level     = 0;
      boolean  isIniting = false;
      boolean  isTernary = false;
      XString  line;
      XString  trimmed;
      XString  noWs;
      XString  lopped;
      int      countOpenP;
      int      countCloseP;
      int      countOpenB;
      int      countCloseB;
      boolean  isBalancedP;
      boolean  isBalancedB;
      boolean  isAccess;
      /*.
      ==========================================================================================
      process each line in turn until the EOF is reached
      ------------------------------------------------------------------------------------------ */
      while (pIter.hasNext())
         {
         line        = pIter.next();
         trimmed     = line.trim();
         noWs        = trimmed.replace(" ", "");
         lopped      = lopOffComment(noWs);
         lopped      = lopped.trimRightCharset(";");
         countOpenP  = lopped.containsCount("(");
         countCloseP = lopped.containsCount(")");
         countOpenB  = lopped.containsCount("{");
         countCloseB = lopped.containsCount("}");
         isBalancedP = countOpenP == countCloseP;
         isBalancedB = countOpenB == countCloseB;
         isTernary   = isTernary && lopped.startsWith(":");
         isTernary   = isTernary || lopped.startsWith("?");
         isIniting   = (!isTernary) && (isIniting || lopped.startsWith(":")) && (!lopped.startsWith("{"));
         isAccess    = (lopped.equals("public:") || lopped.equals("protected:") || lopped.equals("private:"));
         /*.
         ==========================================================================================
         format braced null blocks ...
         ------------------------------------------------------------------------------------------ */
         if (lopped.startsWith("{}") || lopped.endsWith("{}"))
            {
            trimmed = trimmed.iteratingReplace("{  ", "{ ");
            trimmed = trimmed.replace("{}", "{ }");
            }
         /*.
         ==========================================================================================
         --- now start block indenting ---
         ------------------------------------------------------------------------------------------ */
         /*.
         ==========================================================================================
         preprocessor directives: "#ifndef"  "#ifdef"  "#if"  "#endif"  "#else"  "#elif"
         ------------------------------------------------------------------------------------------ */
         if (indentpp)
            {
            if (trimmed.startsWith("#if"))
               {
               indentAndPrint(pOutput, level, indent, trimmed);
               level++;
               }
            else if (trimmed.startsWith("#el"))
               {
               level--;
               indentAndPrint(pOutput, level, indent, trimmed);
               level++;
               }
            else if (trimmed.startsWith("#end"))
               {
               level--;
               indentAndPrint(pOutput, level, indent, trimmed);
               }
            }
         /*.
         ==========================================================================================
         if its an access specifier line
         ------------------------------------------------------------------------------------------ */
         if (isAccess)
            {
            indentAndPrint(pOutput, level - 1, indent, trimmed);
            }
         /*.
         ==========================================================================================
         if this line is part of a constructor initialization ...
         ------------------------------------------------------------------------------------------ */
         else if (isIniting)
            {
            indentAndPrint(pOutput, level + 1, indent, trimmed);
            }
         /*.
         ==========================================================================================
         if this line is part of a ternary conditional statement ...
         ------------------------------------------------------------------------------------------ */
         else if (isTernary)
            {
            indentAndPrint(pOutput, level + 1, indent, trimmed);
            }
         /*.
         ==========================================================================================
         ugly hack
         ------------------------------------------------------------------------------------------ */
         else if (lopped.startsWith("<<"))
            {
            indentAndPrint(pOutput, level + 1, indent, trimmed);
            }
         /*.
         ==========================================================================================
         if this entire line does nothing except end a level ...
         ------------------------------------------------------------------------------------------ */
         else if (lopped.equals(")") || lopped.equals("}"))
            {
            level--;
            indentAndPrint(pOutput, level, indent, trimmed);
            }
         /*.
         ==========================================================================================
         if this entire line does nothing except start a level ...
         ------------------------------------------------------------------------------------------ */
         else if (lopped.equals("(") || lopped.equals("{"))
            {
            indentAndPrint(pOutput, level, indent, trimmed);
            level++;
            }
         /*.
         ==========================================================================================
         if the end of this line ends a paren block (it can end multiple if it ends in several
         consecutive close parens), adjust the level count accordingly.
         ------------------------------------------------------------------------------------------ */
         else if (!isBalancedP || !isBalancedB)
            {
            int  diffP = countOpenP - countCloseP;
            int  diffB = countOpenB - countCloseB;
            int  diffT = diffP + diffB;
            indentAndPrint(pOutput, level, indent, trimmed);
            level += diffT;
            }
         else
            {
            indentAndPrint(pOutput, level, indent, trimmed);
            }
         }
      }

   private void generateIndents(TextWriter pOutput, int pHowMany, XString pIndent)
      {
      for (int indentCount = 0; indentCount < pHowMany; indentCount++)
         {
         pOutput.print(pIndent);
         }
      }

   private void indentAndPrint(TextWriter pOutput, int pHowMany, XString pIndent, XString pLine)
      {
      generateIndents(pOutput, pHowMany, pIndent);
      pOutput.println(pLine);
      }

   private XString lopOffComment(XString pLine)
      {
      XString  lopped = pLine;

      int idx = lopped.indexOf("//");
      if (idx < 0)
         {
         return lopped;
         }
      else if (idx == 0)
         {
         return XString.EMPTY;
         }
      else
         {
         lopped = lopped.substring(0, idx);
         return lopped;
         }
      }


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

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

   @return
      A reference to this object

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

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



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Protected  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Private  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   /*.
   ==========================================================================================
   Class Constants
      CLASS_NAME:
         The name of this class
      DFLT_LINE_LEN:
         The default line length for word wrapping
   ------------------------------------------------------------------------------------------ */
   private static final XString  CLASS_NAME    = new XString(JavaFile.class.getName());
   private static final int      DFLT_LINE_LEN = ConsoleMessage.defaultLineLength();
   /*.
   ==========================================================================================
   Regular expressions for parsing Java files.
   ------------------------------------------------------------------------------------------ */
   public static final String  REGEX_FIND_METHOD_CALLS =
      (
      "("                                                                           +
         "("                                                                        +
            "(?<Qualifier>"                                                           +
               "(\\w)+"                                                             +
            ")"                                                                     +
            "[\\s\\n\\r]*(\\.)[\\s\\n\\r]*"                                         +
         ")*"                                                                       +
         ""                                                                         +
         "(?<Name>"                                                                   +
            "(?!"                                                                   +
               "\\bif\\b|\\bfor\\b|\\bwhile\\b|\\bswitch\\b|\\btry\\b|\\bcatch\\b"  +
            ")"                                                                     +
            "(\\w)+"                                                                +
         ")"                                                                        +
         ""                                                                         +
         "[\\s\\n\\r]*"                                                             +
         ""                                                                         +
         "(?<Arguments>"                                                              +
            "(\\(.*\\))"                                                            +
         ")"                                                                        +
      ")"
      );

   public static final String  REGEX_FIND_NAMED_METHOD_CALL =
      (
      "("                                                                           +
         "("                                                                        +
            "(?<Qualifier>"                                                           +
               "(\\w)+"                                                             +
            ")"                                                                     +
            "[\\s\\n\\r]*(\\.)[\\s\\n\\r]*"                                         +
         ")*"                                                                       +
         ""                                                                         +
         "(?<Name>"                                                                   +
            "(?!"                                                                   +
               "\\bif\\b|\\bfor\\b|\\bwhile\\b|\\bswitch\\b|\\btry\\b|\\bcatch\\b"  +
            ")"                                                                     +
            "%METHOD_NAME%"                                                         +
         ")"                                                                        +
         ""                                                                         +
         "[\\s\\n\\r]*"                                                             +
         ""                                                                         +
         "(?<Arguments>"                                                              +
            "(\\(.*\\))"                                                            +
         ")"                                                                        +
      ")"
      );
   /*.
   ==========================================================================================
   Regular expression for matching Java method declarations.
      <BLOCKQUOTE>
         These are the characters that must be escaped in a Java regular expression literal
            <BLOCKQUOTE>
               <PRE id="unindent">
                  mustEscape=.^$*+?()[{\|
               </PRE>
            </BLOCKQUOTE>
      </BLOCKQUOTE>
      <BLOCKQUOTE>
         These are a couple of complex sample method declarations that the regular expression
         must be able to match.
            <BLOCKQUOTE>
               <PRE id="unindent">
                  public static synchronized final transient <TypeReturn, Type2, Type3, Type4> TypeReturn methodName ( Type1 param1, Type2 param2, Type3 param3, Type4 param4, String param6, double param7 ) throws iOException, NumberFormatException , DEStitute
                  public static synchronized final transient <TypeReturn, Type1 extends Comparable, Type2, Type3, Type4> TypeReturn<TypeParameter> methodName ( List<? extends T> list, Type1 param1, Type2 param2, Type3 param3, Type4 param4, String param6, double param7 ) throws iOException, NumberFormatException , DEStitute
               </PRE>
            </BLOCKQUOTE>
      </BLOCKQUOTE>
      <BLOCKQUOTE>
         These are the group tokens used to build this regular expression..
            <BLOCKQUOTE>
               <PRE id="unindent">
                  {accessGroup}
                  {modifiersGroup}
                  {typeParametersGroup}
                  {returnTypeGroup}
                  {methodNameGroup}
                  {parameterGroup}
                  {throwGroup}
               </PRE>
            </BLOCKQUOTE>
      </BLOCKQUOTE>
      <BLOCKQUOTE>
         This is the content of a string substitution file for expanding the group tokens
         listed above.
            <BLOCKQUOTE>
               <PRE id="unindent">
                  =
                  {accessGroup}=(?:{access})
                  {access}=(?<ACCESS>((public|protected|private){rqdWs})?)

                  {modifiersGroup}=(?:{modifiers})
                  {modifiers}=(?<MODIFIERS>((abstract|final|native|transient|static|synchronized){rqdWs})*)

                  {typeParametersGroup}=(?:{typeParametersOption})
                  {typeParametersOption}=({typeParametersSet}{rqdWs})?
                  {typeParametersSet}=(?<TYPEPARAMETERS>{typeParameters})?
                  {typeParameters}=(<{optWs}{typeSpec}({commaSeperator}{typeSpec})*{optWs}>)

                  {returnTypeGroup}=(?:{returnType}{rqdWs})
                  {returnType}=(?<RETURNTYPE>{typeSpec})

                  {methodNameGroup}=(?:{methodName})
                  {methodName}=(?<METHODNAME>{identifier})

                  {parameterGroup}=(?:{optWs}{parameterList})
                  {parameterList}=(?<PARAMETERLIST>\({optWs}({oneParameter}*|{multipleParameters}){optWs}\))
                  {multipleParameters}=({normalParameter}({commaSeperator}{normalParameter})*)*({commaSeperator}{varArgsParameter})?
                  {oneParameter}=({normalParameter}|{varArgsParameter})
                  {varArgsParameter}=({varArgsType}{rqdWs}{identifier})
                  {normalParameter}=({typeSpec}{rqdWs}{identifier})
                  {varArgsType}={typeSpec}{elipsis}

                  {throwGroup}=(?:{throwerOption})
                  {throwerOption}=({rqdWs}{thrower})?
                  {thrower}=(?<THROWER>throws{rqdWs}{thrownList})
                  {thrownList}={typeName}({commaSeperator}{typeName})*

                  {typeSpec}=({regularType}|{parameterizedType})
                  {parameterizedType}=({regularType}{optWs}<{optWs}{regularType}{optWs}>)
                  {regularType}={baseType}{typeExtension}?
                  {typeExtension}=({rqdWs}extends{rqdWs}{concreteType})
                  {baseType}=({concreteType}|{unknownType})
                  {unknownType}=\?
                  {concreteType}={typeName}({indexer})?
                  {typeName}={identifier}

                  {commaSeperator}={optWs},{optWs}

                  {rqdWs}=\s+
                  {optWs}=\s*
                  {identifier}=[A-Za-z]\w*
                  {string}="([^"]|\\")*"
                  {elipsis}=\.\.\.
                  {indexer}=\[]

                  \=\\
               </PRE>
            </BLOCKQUOTE>
      </BLOCKQUOTE>
      <BLOCKQUOTE>
         To generate the regular expressions:
            => paste the group tokens into a text file, say - groupTokens.txt<BR>
            => paste the content of a string substitution file into a text file, say -
               subs.txt<BR>
            => run the string substitution tool to expand the group tokens like this:
               -> Substitute -fsubs.txt groupTokens.txt
      </BLOCKQUOTE>
   ------------------------------------------------------------------------------------------ */
   public static final String  REGEX_FIND_METHODS =
      (
      "(?:(?<ACCESS>((public|protected|private)\\s+)?))" +
      "(?:(?<MODIFIERS>((abstract|final|native|transient|static|synchronized)\\s+)*))" +
      "(?:((?<TYPEPARAMETERS>(<\\s*(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?|(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*<\\s*([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*>))(\\s*,\\s*(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?|(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*<\\s*([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*>)))*\\s*>))?\\s+)?)" +
      "(?:(?<RETURNTYPE>(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?|(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*<\\s*([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*>)))\\s+)" +
      "(?:(?<METHODNAME>[A-Za-z]\\w*))" +
      "(?:\\s*(?<PARAMETERLIST>\\(\\s*((((([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?|(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*<\\s*([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*>))\\s+[A-Za-z]\\w*)|((([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?|(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*<\\s*([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*>))\\.\\.\\.\\s+[A-Za-z]\\w*))*|(((([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?|(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*<\\s*([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*>))\\s+[A-Za-z]\\w*)(\\s*,\\s*((([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?|(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*<\\s*([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*>))\\s+[A-Za-z]\\w*))*)*(\\s*,\\s*((([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?|(([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*<\\s*([A-Za-z]\\w*(\\[])?|\\?)(\\s+extends\\s+[A-Za-z]\\w*(\\[])?)?\\s*>))\\.\\.\\.\\s+[A-Za-z]\\w*))?)\\s*\\)))" +
      "(?:(\\s+(?<THROWER>throws\\s+[A-Za-z]\\w*(\\s*,\\s*[A-Za-z]\\w*)*))?)"
      );
   /*.
   ==========================================================================================
   Class variables
      cOut : console output.
   ------------------------------------------------------------------------------------------ */
   private static ConsoleStream  cOut = ConsoleStream.getSingleton();
   /*.
   ==========================================================================================
   Instance variables
      iVarName : something or other
   ------------------------------------------------------------------------------------------ */
   private State         iCurrState = null;
   private JavaFileBase  iJavaFile  = null;



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method figures out which source code layout version the file uses. The default is 0.

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

   *//*
   ---------------------------------------------------------------------------------------------------- */
   private void layoutVersion() throws Exception
      {
      int  result = 0;
      XStringsIterator  iter = new XStringsIterator(this.getCanonicalPath());
      while (iter.hasNext())
         {
         XString  line = iter.next().trim();
         if (line.startsWith("LayoutRev:"))
            {
            ArrayList<XString>  tokens = line.tokenizedString(" ");
            if (tokens.size() > 1)
               {
               XString  revStr = tokens.get(1);
               if (revStr.isAllDigits())
                  {
                  result = UMath.decodeDecimalInt(revStr);
                  /*.
                  ==========================================================================================
                  If the iterator for a TextFile isn't allowed to cycle through the entire file then a call
                  to rename() shortly afterwards fails.
                  ------------------------------------------------------------------------------------------ */
                  // break;
                  }
               }
            }
         }
      switch (result)
         {
         default:
            iJavaFile = new JavaFileV0(this.getCanonicalPath());
            break;
         case 4:
            iJavaFile = new JavaFileV4(this.getCanonicalPath());
            break;
         case 5:
            iJavaFile = new JavaFileV5(this.getCanonicalPath());
            break;
         }
      }



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Inner Classes  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   ////////////////////////////////////////////////////////////////////////////////////////////////////
   public class StateMachine
      {
      public XString  iCurrLine     = null;
      public State    iState        = null;

      public State    iStartState   = null;
      public State    iCodeState    = null;
      public State    iCommentState = null;
      public State    iItemState    = null;
      public State    iTextState    = null;

      public XStringsIterator  iIter       = null;
      public TextWriter        iOutput     = null;
      public int               iLineLength = 0;

      public XString  iPrefix;
      public XString  iSuffix;
      public XString  iTrimmed;
      public XString  iItemIndent;
      public boolean  iIsComment;
      public boolean  iIsCommentBorder;
      public boolean  iIsBlank;
      public boolean  iIsBlankComment;
      public boolean  iIsNewPrefix;
      public boolean  iIsCopyright;
      public boolean  iIsItem;
      public boolean  iIsNewParagraph;
      public boolean  iIsText;

      public int signal = 0;

      public ArrayList<XString>   iParagraphLines = new ArrayList<XString>();
      public XString              iPreviousPrefix = XString.EMPTY;
      public boolean              iWasCopyright   = false;

      // ====================================================================================
      public StateMachine(XStringsIterator pIter, TextWriter pOutput, int pLineLength)
         {
         iIter       = pIter;
         iOutput     = pOutput;
         iLineLength = pLineLength;

         iStartState   = new StartState  (this);
         iCodeState    = new CodeState   (this);
         iCommentState = new CommentState(this);
         iItemState    = new ItemState   (this);
         iTextState    = new TextState   (this);
         iState        = iStartState;
         }

      // ====================================================================================
      public void characterizeLine()
         {
         iPrefix          = commentPrefix(iCurrLine);
         iSuffix          = iCurrLine.trimLeft(iPrefix);
         iTrimmed         = iCurrLine.trim();
         iIsComment       = iTrimmed.startsWith("//");
         iIsCommentBorder = ((iTrimmed.length() > 5) && iTrimmed.containsOnlyCharsInString("/"));
         iIsBlank         = iTrimmed.equals("");
         iIsBlankComment  = (iIsComment && iSuffix.isEmpty());
         iIsNewPrefix     = (!iPrefix.equals(iPreviousPrefix));
         iIsCopyright     = iSuffix.startsWithIgnoreCase("Copyright");
         iIsItem          =
            (  // These are only considered items if they are the first text in a full line comment
               // Note: The upstile '|' is for things we want treated as an item but not treated by
               //       Doxygen as a list item.
               // Note: Don't use period '.' as a bullet because all the spaces following it except
               //       one are deleted below. It's only recognized as a sentence ending.
               // Note: The (eol after) variants make it possible to have otherwise empty lines be
               //       valid items.
               iSuffix.startsWith("@")    // Doxygen tag         (no space after)
            || iSuffix.startsWith("* ")   // Doxygen list bullet (space after)
            || iSuffix.startsWith("- ")   // Doxygen list bullet (space after)
            || iSuffix.startsWith("+ ")   // Doxygen list bullet (space after)
            || iSuffix.startsWith("| ")   // bullet or ascii art (space after)
            || iSuffix.trim().equals("*") // Doxygen list bullet (eol after)
            || iSuffix.trim().equals("-") // Doxygen list bullet (eol after)
            || iSuffix.trim().equals("+") // Doxygen list bullet (eol after)
            || iSuffix.trim().equals("|") // bullet or ascii art (eol after)
            );
         // Items have a special leading character on their first line. All subsequent lines after the first are
         // indented from the first line. An iIsText line signals that the item ended with the previous line.
         if (iIsItem)
            {
            if      (iSuffix.startsWith("@")) iItemIndent = new XString("     ");
            else if (iSuffix.startsWith("*")) iItemIndent = iSuffix.trimLeft("*").whitespacePrefix().concat(" ");
            else if (iSuffix.startsWith("-")) iItemIndent = iSuffix.trimLeft("-").whitespacePrefix().concat(" ");
            else if (iSuffix.startsWith("+")) iItemIndent = iSuffix.trimLeft("+").whitespacePrefix().concat(" ");
            else if (iSuffix.startsWith("|")) iItemIndent = iSuffix.trimLeft(".").whitespacePrefix().concat(" ");
            }
         iIsNewParagraph =
            (
               !iIsComment
            || iIsBlank
            || iIsCommentBorder
            || iIsBlankComment
            || iIsNewPrefix
            || iIsItem
            || iWasCopyright
            );
         iIsText =
            (
               iIsComment
            && !iIsBlank
            && !iIsCommentBorder
            && !iIsBlankComment
            && !iIsItem
            && !iWasCopyright
            );
/*
if (iTrimmed.equals("/// @code"))
   {
   signal = 15;
   System.out.println();
   System.out.println("            |          1         2         3         4         5         6         7         8         9" );
   System.out.println("            |01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
   System.out.println("      line: |" + iCurrLine.toString() + "|");
   System.out.println("    prefix: |" + iPrefix.toString() + "|");
   System.out.println("prevPrefix: |" + iPreviousPrefix.toString() + "|");
   System.out.println("   newPara: |" + iIsNewParagraph + "|");
   System.out.println();
   }
else if (signal > 0)
   {
   --signal;
   System.out.println();
   System.out.println("            |          1         2         3         4         5         6         7         8         9" );
   System.out.println("            |01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
   System.out.println("      line: |" + iCurrLine.toString() + "|");
   System.out.println("    prefix: |" + iPrefix.toString() + "|");
   System.out.println("prevPrefix: |" + iPreviousPrefix.toString() + "|");
   System.out.println("   newPara: |" + iIsNewParagraph + "|");
   System.out.println();
   }
*/
         iWasCopyright   = iIsCopyright;
         iPreviousPrefix = iPrefix;
         }

      // ====================================================================================
      public XString commentPrefix(XString pLine)
         {
         XString  prefix = XString.EMPTY;
         if (pLine.trim().startsWith("//"))
            {
            int idx = 0;
            while ((idx < pLine.length()) && Character.isWhitespace(pLine.charAt(idx)))
               {
               ++idx;
               }
            while ((idx < pLine.length()) && (pLine.charAt(idx) == '/'))
               {
               ++idx;
               }
            while ((idx < pLine.length()) && Character.isWhitespace(pLine.charAt(idx)))
               {
               ++idx;
               }
            prefix = pLine.substring(0, idx);
            }
         return prefix;
         }

      // ====================================================================================
      public void  run() throws Exception
         {
         while (iState != null)
            {
            iState.run();
            }
         }

      }   // class StateMachine



   ////////////////////////////////////////////////////////////////////////////////////////////////////
   private abstract class State
      {
      public StateMachine  mcn = null;

      // ====================================================================================
      public abstract void run() throws Exception;


      // ====================================================================================
      public State(StateMachine pMachine)
         {
         mcn = pMachine;
         }

      // ====================================================================================
      public void setState(State pState)
         {
         mcn.iState = pState;
         }

      // ====================================================================================
      public void setCurrLine(XString pCurrLine)
         {
         mcn.iCurrLine = pCurrLine;
         if (mcn.iCurrLine != null)
            {
            mcn.characterizeLine();
            }
         }

      // ====================================================================================
      public void nextLine() throws Exception
         {
         if (mcn.iIter.hasNext())
            {
            XString pLine = mcn.iIter.next();
            byte[] bytes = pLine.getBytes("UTF-8");
            XString value = new XString(new String(bytes, "UTF-8"));
            setCurrLine(value);
 //           setCurrLine(mcn.iIter.next());
            }
         else
            {
            setCurrLine(null);
            setState(null);
            }
         }

      // ====================================================================================
      public void wrapParagraphLines(int pFieldWidth)
         {
         if (!mcn.iParagraphLines.isEmpty())
            {
            XString  oneBigString = XString.EMPTY;
            while (!mcn.iParagraphLines.isEmpty())
               {
               XString  line = mcn.iParagraphLines.remove(0);
               oneBigString = oneBigString.concat(line);
               oneBigString = oneBigString.concat("\n");
               }
            oneBigString = oneBigString.iteratingReplace(".  ", ". ");
            mcn.iParagraphLines = oneBigString.wordWrap(pFieldWidth);
            }
         }

      // ====================================================================================
      public void print(TextWriter pOutput, XString pLine)
         {
         pOutput.print(pLine);
         }

      // ====================================================================================
      public void println(TextWriter pOutput, XString pLine)
         {
         pOutput.println(pLine);
         }

      }   // class State



   ////////////////////////////////////////////////////////////////////////////////////////////////////
   public class StartState extends State
      {

      // ====================================================================================
      public StartState(StateMachine pMachine)
         {
         super(pMachine);
         }

      // ====================================================================================
      public void run() throws Exception
         {
         nextLine();
         if (mcn.iCurrLine != null)
            {
            if (mcn.iIsComment) { setState(mcn.iCommentState); } else { setState(mcn.iCodeState); }
            }
         }

      }   // class StartState



   ////////////////////////////////////////////////////////////////////////////////////////////////////
   public class CodeState extends State
      {
      // ====================================================================================
      public CodeState(StateMachine pMachine)
         {
         super(pMachine);
         }

      // ====================================================================================
      public void run() throws Exception
         {
         if ((mcn.iCurrLine == null) || (mcn.iIsComment))
            {
            Exception  e = new Exception("JvaFile.CodeState.run(): line=<" + mcn.iCurrLine + ">  isCode?=<" + !mcn.iIsComment + ">");
            throw e;
            }

         // --------------------------------------------------------------------------
         while (mcn.iCurrLine != null)
            {
            if (mcn.iIsComment)
               {
               setState(mcn.iCommentState);
               return;
               }
            println(mcn.iOutput, mcn.iCurrLine);
            nextLine();
            }
         }

      }   // class CodeState



   ////////////////////////////////////////////////////////////////////////////////////////////////////
   public class CommentState extends State
      {
      // ====================================================================================
      public CommentState(StateMachine pMachine)
         {
         super(pMachine);
         }

      // ====================================================================================
      public void run() throws Exception
         {
         if ((mcn.iCurrLine == null) || (!mcn.iIsComment))
            {
            Exception  e = new Exception("JvaFile.CommentState.run(): line=<" + mcn.iCurrLine + ">  isComment?=<" + mcn.iIsComment + ">");
            throw e;
            }

         // --------------------------------------------------------------------------
         while (mcn.iCurrLine != null)
            {
            if (!mcn.iIsComment)
               {
               setState(mcn.iCodeState);
               return;
               }
            if (mcn.iIsItem)
               {
               setState(mcn.iItemState);
               return;
               }
            if (mcn.iIsText)
               {
               setState(mcn.iTextState);
               return;
               }
            if (mcn.iIsCommentBorder)
               {
               int  fieldWidth;
               if (mcn.iSuffix.length() == 0)
                  {
                  // a border starting in col 0 is all prefix with no suffix
                  XString  newPrefix = mcn.iPrefix.whitespacePrefix();
                  fieldWidth = mcn.iLineLength - newPrefix.length();
                  XString  newBorder = XString.fill(fieldWidth, '/');
                  println(mcn.iOutput, newPrefix.concat(newBorder));
                  }
               else
                  {
                  fieldWidth = mcn.iLineLength - mcn.iPrefix.length();
                  XString  newBorder = XString.fill(fieldWidth, '/');
                  println(mcn.iOutput, mcn.iPrefix.concat(newBorder));
                  }
               }
            else
               {
               println(mcn.iOutput, mcn.iCurrLine);
               }
            nextLine();
            }
         }

      }   // class CommentState



   ////////////////////////////////////////////////////////////////////////////////////////////////////
   public class ItemState extends State
      {
      // ====================================================================================
      public ItemState(StateMachine pMachine)
         {
         super(pMachine);
         }

      // ====================================================================================
      public void run() throws Exception
         {
         if ((mcn.iCurrLine == null) || (!mcn.iIsItem))
            {
            Exception  e = new Exception("JvaFile.ItemState.run(): line=<" + mcn.iCurrLine + ">  isItem?=<" + mcn.iIsItem + ">");
            throw e;
            }

         // --------------------------------------------------------------------------
         XString  itemPrefix         = mcn.iPrefix;
         XString  indentedPrefix     = itemPrefix.concat(mcn.iItemIndent);
         int      itemFieldWidth     = mcn.iLineLength - itemPrefix.length();
         int      indentedFieldWidth = mcn.iLineLength - indentedPrefix.length();
         boolean  firstLine          = true;
         while (mcn.iCurrLine != null)
            {
            if (firstLine && mcn.iIsItem)   // cause Item is never text but want to wrap w following text
               {
               firstLine = false;
               // this bit is all about hiding the vertical bar bullet from wrapParagraphLines(). That method
               // handles vertical bars in a way that we don't want for full line comments. So, we
               // temporarily replace the vertical bar here with a character that wrapParagraphLines()
               // ignores. When it comes time to print the bulleted line, this temporary character is changed
               // back to the vertical bar.
               if (mcn.iSuffix.startsWith("|"))
                  {
                  mcn.iParagraphLines.add(mcn.iSuffix.trimLeft("|").appendPrefix(":"));
                  }
               // if it's not a vertical bar
               else
                  {
                  mcn.iParagraphLines.add(mcn.iSuffix);
                  }
               nextLine();
               }
            else if (mcn.iIsText)
               {
               mcn.iParagraphLines.add(mcn.iSuffix);
               nextLine();
               }
            else if (mcn.iIsNewParagraph)
               {
               wrapParagraphLines(itemFieldWidth);
               if (!mcn.iParagraphLines.isEmpty())
                  {
                  XString  line = mcn.iParagraphLines.remove(0);
                  // this is where we replace the temporary character we substituted for the vertical bar
                  if (line.startsWith(":"))
                     {
                     line = line.trimLeft(":").appendPrefix("|");
                     }
                  println(mcn.iOutput, itemPrefix.concat(line));
                  }

               wrapParagraphLines(indentedFieldWidth);
               while (!mcn.iParagraphLines.isEmpty())
                  {
                  println(mcn.iOutput, indentedPrefix.concat(mcn.iParagraphLines.remove(0)));
                  }
               if (mcn.iIsComment) { setState(mcn.iCommentState); } else { setState(mcn.iCodeState); }
               return;
               }
            else
               {
               if (mcn.iIsComment) { setState(mcn.iCommentState); } else { setState(mcn.iCodeState); }
               break;
               }
            }

         // Wrap leftovers
         wrapParagraphLines(itemFieldWidth);
         if (!mcn.iParagraphLines.isEmpty())
            {
            XString  line = mcn.iParagraphLines.remove(0);
            // this is where we replace the temporary character we substituted for the vertical bar
            if (line.startsWith(":"))
               {
               line = line.trimLeft(":").appendPrefix("|");
               }
            println(mcn.iOutput, itemPrefix.concat(line));
            }

         wrapParagraphLines(indentedFieldWidth);
         while (!mcn.iParagraphLines.isEmpty())
            {
            println(mcn.iOutput, indentedPrefix.concat(mcn.iParagraphLines.remove(0)));
            }
         }

      }   // class ItemState



   ////////////////////////////////////////////////////////////////////////////////////////////////////
   public class TextState extends State
      {
      // ====================================================================================
      public TextState(StateMachine pMachine)
         {
         super(pMachine);
         }

      // ====================================================================================
      public void run() throws Exception
         {
         if ((mcn.iCurrLine == null) || (!mcn.iIsText))
            {
            Exception  e = new Exception("JvaFile.TextState.run(): line=<" + mcn.iCurrLine + ">  isText?=<" + mcn.iIsText + ">");
            throw e;
            }

         // --------------------------------------------------------------------------
         XString  textPrefix = mcn.iPrefix;
         int      fieldWidth = mcn.iLineLength - textPrefix.length();
         while (mcn.iCurrLine != null)
            {
            if (mcn.iIsNewParagraph)
               {
               wrapParagraphLines(fieldWidth);
               while (!mcn.iParagraphLines.isEmpty())
                  {
                  println(mcn.iOutput, textPrefix.concat(mcn.iParagraphLines.remove(0)));
                  }
               }
            if (mcn.iIsText)
               {
               if (mcn.iIsNewPrefix)
                  {
                  textPrefix = mcn.iPrefix;
                  fieldWidth = mcn.iLineLength - textPrefix.length();
                  }
               mcn.iParagraphLines.add(mcn.iSuffix);
               nextLine();
               }
            else
               {
               if (mcn.iIsComment) { setState(mcn.iCommentState); } else { setState(mcn.iCodeState); }
               break;
               }
            }

         // Wrap leftovers
         wrapParagraphLines(fieldWidth);
         while (!mcn.iParagraphLines.isEmpty())
            {
            println(mcn.iOutput, textPrefix.concat(mcn.iParagraphLines.remove(0)));
            }
         }

      }   // class TextState



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Private Static Methods  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method counts the uncommented lines of code in a java, c, or c++ source code file.

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

   @return
      The number of uncommented lines of code

   @param
      pFileIn is the name of the file to count the lines of code in
   *//*
   ---------------------------------------------------------------------------------------------------- */
   private static int linesOfCode(String pFileIn) throws Exception
      {
      /*.
      ==========================================================================================
      Check the parameters.
      ------------------------------------------------------------------------------------------ */
      if (pFileIn == null)
         {
         throw new Exception("pFileIn is null");
         }
      /*.
      ==========================================================================================
      Counting lines of code is a destructive process to the fille being counted. To prevent
      damage to the file, make a temp file and copy the contents of the original file to it.
      Then do the destructive line counting on the temp file instead of the original.
      ------------------------------------------------------------------------------------------ */
      JavaFile  srcFile = new JavaFile(pFileIn);
      JavaFile  tmpFile = new JavaFile(File.createTempFile("linesOfCode-",".tmp"));
      tmpFile.copyFrom(srcFile);
      /*.
      ==========================================================================================
      This is the destructive part -- get rid of all the lines we don't want to count.
      ------------------------------------------------------------------------------------------ */
      tmpFile.stripComments();
      tmpFile.trim();
      tmpFile.tossBlankLines();
      /*.
      ==========================================================================================
      Count all the lines of code in the uncommented file
      ------------------------------------------------------------------------------------------ */
      int              count   = 0;
      XStringsIterator tmpIter = tmpFile.xstringsIterator();

      while (tmpIter.hasNext())
         {
         XString  line = tmpIter.next();
         char[]   chars = line.toCharArray();
         for (int i=0; i<chars.length; i++)
            {
            if (chars[i] == ';') count++;
            if (chars[i] == '}') count++;
            }
         }
      /*.
      ==========================================================================================
      Now get rid of the temp file.
      ------------------------------------------------------------------------------------------ */
      tmpFile.delete();
      /*.
      ==========================================================================================
      And return the line count
      ------------------------------------------------------------------------------------------ */
      return count;
      }



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Public Static Methods  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method allows this class file to be unit tested 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". Main() is not a required method, but the practice of putting one in each class and
   wrapping class test code within it allows easy unit testing of the class; and main does not need to
   be removed when testing is complete.

   <P>
      <DL>
         <DT>
            <B>
               Command line usage:
            </B>
            <DD>
               Java cosmicabyss.com.lib.JavaFile
            </DD>
         </DT>
      </DL>

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

   @param
      pArgs contains the command line arguments with which this class was invoked as an application.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static void main(String[] pArgs) throws Exception
      {
      /*.
      ==========================================================================================
      Greetings !
      ------------------------------------------------------------------------------------------ */
      cOut.banner(CLASS_NAME);
      /*.
      ==========================================================================================
      Constructor test
      ------------------------------------------------------------------------------------------ */
      /*.
      ==========================================================================================
      Create an object and send its output to the ConsoleStream
      ------------------------------------------------------------------------------------------ */
      System.out.println("Processing: " + pArgs[0]);
      JavaFile  obj = new JavaFile(pArgs[0]);
      /*.
      ==========================================================================================
      Test code
      ------------------------------------------------------------------------------------------ */
      obj.test();
      }



   }  // class JavaFile



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Notes  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */