/*::.
==================================================================================================================================
=================================================¦ Copyright © 2001 Allen Baker ¦=================================================
                                                 +------------------------------+
File:       PropertyFile.java
Originator: Allen Baker (2001.09.02)
LayoutRev:  5
================================================================================================================================== */



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



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



/*::
=====================================================================================7=================================== *//**
Instances of this class are persistent sets of properties that are loaded from a file.<P>

Each PropertyFile object is loaded by reading a property list (key and element pairs) from the a file. The file is
assumed to be using the ISO 8859-1 character encoding. Every property occupies one line of the file. Each line is
terminated by a line terminator (\n or \r or \r\n). Lines from the file are processed until end of file is reached on the
file.<P>

A line that contains only whitespace or whose first non-whitespace character is an ASCII # is ignored (thus, # indicate
comment lines).<P>

Every line other than a blank line or a comment line describes one property to be added to the table (except that if a
line ends with \, then the following line, if it exists, is treated as a continuation line, as described below). The key
consists of all the characters in the line starting with the first non-whitespace character and up to, but not including,
the first ASCII =, :, or whitespace character. All of the key termination characters may be included in the key by
preceding them with a \. Any whitespace after the key is skipped; if the first non-whitespace character after the key is
= or :, then it is ignored and any whitespace characters after it are also skipped. All remaining characters on the line
become part of the associated element string. Within the element string, the ASCII escape sequences \t, \n, \r, \\, \",
\', \ (a backslash and a space), and \\uxxxx are recognized and converted to single characters. Moreover, if the last
character on the line is \, then the next line is treated as a continuation of the current line; the \ and line
terminator are simply discarded, and any leading whitespace characters on the continuation line are also discarded and
are not part of the element string.<P>

As an example, each of the following four lines specifies the key "Truth" and the associated element value "Beauty":

   <BLOCKQUOTE>
      <PRE id="unindent">
         Truth = Beauty
            Truth:Beauty
         Truth       :Beauty
      </PRE>
   </BLOCKQUOTE>

As another example, the following three lines specify a single property:

   <BLOCKQUOTE>
      <PRE id="unindent">
         fruits            apple, banana, pear, \
                           cantaloupe, watermelon, \
                           kiwi, mango
      </PRE>
   </BLOCKQUOTE>

The key is "fruits" and the associated element is:

   <BLOCKQUOTE>
      <PRE id="unindent">
         "apple, banana, pear, cantaloupe, watermelon,kiwi, mango"
      </PRE>
   </BLOCKQUOTE>

Note that a space appears before each \ so that a space will appear after each comma in the final result; the \, line
terminator, and leading whitespace on the continuation line are merely discarded and are not replaced by one or more
other characters. As a third example, the lines:

   <BLOCKQUOTE>
      <PRE id="unindent">
         cheese
         crackers =
      </PRE>
   </BLOCKQUOTE>

specifies that the keys are "cheese" and "crackers" and the associated element is the empty string for both "cheese" and
"crackers".<P>

<P>
   <DL>
      <DT>
         <B>
            Example usage:
         </B>
         <DD>
            <BLOCKQUOTE>
               <PRE id="unindent">
                  =========================================================================================
                  Create a PropertyFile from the contents of the
                  file ..\map\CGSUpdate.prop and list all the properties
                  on stdout.
                  -----------------------------------------------------------------------------------------
                  PropertyFile pf = new PropertyFile("../map/CGSUpdate.prop");
                  pf.list(System.out);
               </PRE>
            </BLOCKQUOTE>
         </DD>
      </DT>
      <DT>
         <B>
            View Source:
         </B>
         <DD>
            <A href="PropertyFile.java.html">
               PropertyFile.java
            </A>
         </DD>
      </DT>
      <DT>
         <B>
            Author:
         </B>
         <DD>
            <A href="mailto:sourcecode.v01@cosmicabyss.com">
               Allen Baker
            </A>
         </DD>
      </DT>
   </DL>
*//*
======================================================================================================================== */
public class PropertyFile extends Properties
   {



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates a PropertyFile object and loads it by reading a property list (key and element
   pairs) from the specified file.

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

   @param
      pFile is the File to read the properties from
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public PropertyFile(File pFile) throws IOException
      {
      BufferedInputStream mStream = new BufferedInputStream
         (
         new FileInputStream(pFile)
         );
      load(mStream);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method creates a PropertyFile object and loads it by reading a property list (key and element
   pairs) from the specified file.

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

   @param
      pFileName is the name of the file to read the properties from
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public <Type> PropertyFile(Type pFileName) throws IOException
      {
      BufferedInputStream mStream = new BufferedInputStream
         (
         new FileInputStream(UString.toString(pFileName))
         );
      load(mStream);
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method writes all the properties to a specified MessageLog object

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

   @param
      pMsgLog is the MessageLog that the properties are written to
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public void logList()
      {
      logList("");
      }



   /*:                                    
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method writes all the properties to a specified MessageLog object along with a title string

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

   @param
      pMsgLog is the MessageLog that the properties are written to
   @param
      pTitle is a title sting that is places at the top of the list.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public <Type> void logList(Type pTitle)
      {
      /*.
      ==========================================================================================
      Figure out how long the longest property name is
      ------------------------------------------------------------------------------------------ */
      Set       propKeys = keySet();
      int       maxLen   = 0;
      Iterator  iter     = propKeys.iterator();
      while (iter.hasNext())
         {
         String propertyName = (String)iter.next();
         maxLen = UMath.max(maxLen,propertyName.length());
         }
      /*.
      ==========================================================================================
      Add each property name and its value to a buffer
      ------------------------------------------------------------------------------------------ */
      StringBuffer  bigBuf = new StringBuffer();
      int           i      = 0;
      iter = propKeys.iterator();
      while (iter.hasNext())
         {
         /*.
         ==========================================================================================
         Add the property an its value to the buffer
         ------------------------------------------------------------------------------------------ */
         String propertyName  = (String)iter.next();
         String propertyValue = getProperty(propertyName);
         while (propertyName.length() < maxLen)
            {
            propertyName += " ";
            }
         bigBuf.append(propertyName + " = " + propertyValue + "\n\n");
         }
      /*.
      ==========================================================================================
      Send the whole thing to the log
      ------------------------------------------------------------------------------------------ */
      cOut.println(pTitle,bigBuf.toString());
      }



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

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

   @return
      A reference to this object

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

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



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



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



   /*.
   ==========================================================================================
   Class Constants
      CLASS_NAME : the name of this class DFLT_LINE_LEN : the default line length for word
      wrapping
   ------------------------------------------------------------------------------------------ */
   private static final XString  CLASS_NAME    = new XString(PropertyFile.class.getName());
   private static final int      DFLT_LINE_LEN = ConsoleMessage.defaultLineLength();
   /*.
   ==========================================================================================
   Class variables
      cOut : console output.
   ------------------------------------------------------------------------------------------ */
   private static ConsoleStream  cOut = ConsoleStream.getSingleton();



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



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  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.PropertyFile
            </DD>
         </DT>
      </DL>

   <P><B>Implementation: </B><A HREF="PropertyFile.java.html#006">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);
      /*.
      ==========================================================================================
      Create an object and send its output to the ConsoleStream
      ------------------------------------------------------------------------------------------ */
      PropertyFile  obj = new PropertyFile("./JBotherBundle.properties");
      /*.
      ==========================================================================================
      Test code
      ------------------------------------------------------------------------------------------ */
      obj.test();
      obj.setOut(cOut);
      obj.logList("The properties");



      }



   }  // class PropertyFile



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