//----------------
// TAB Setting: 4
//----------------

import java.io.*;

/**********************************************************************
* This class provides methods for processing command line arguments:
* checking flag arguments, checking the number of data arguments, 
* printing out a usage summary, determining if a flag has been set.
*
* @author   Arch Harris
* @version  01/2009, revision 1
**********************************************************************/
public class ArgsChecker
{
    public static final int AC_UNCHECKED = -1;          /// Arguments not yet checked.
    public static final int AC_OK = 0;                  /// Arguments checked and in proper format.
    public static final int AC_BAD_FLAG = 1;            /// Invalid flag letter specified.
    public static final int AC_NO_FLAG_PARAM = 2;       /// Parameterized flag specified without a parameter.
    public static final int AC_BAD_PARAM_FLAG = 3;      /// Parameterized flag letter found which was not the last character in an flag argument.
    public static final int AC_TOO_FEW_DATA_ARGS = 4;   /// Too few data arguments specified.
    public static final int AC_TOO_MANY_DATA_ARGS = 5;  /// Too many data arguments specified.

    public static final int MAX_LETTER = '~';           /// Maximum possible flag letter value

    private String      programName;                    /// Program name. 
    /******************************************************************
    * Allowed simple flags. The indices are chars, one for each 
    * possible flag letter. The element for a letter is null if the 
    * flag is not permitted, a string describing flag otherwise.
    ******************************************************************/
    private String []   simpleFlags;    
    /******************************************************************
    * Allowed parameterized flags. The indices are chars, one for each
    * possible flag letter. The element for a letter is null if the
    * flag is not permitted, a string describing flag otherwise.
    ******************************************************************/
    private String []   paramFlags;
    private int         minArgCnt;      /// Minimum number of data arguments required.
    private int         maxArgCnt;      /// Maximum number of data arguments allowed, negative indicates there is no maximum.
    private String      argsDescriptor; /// String that describes the data argument usage.
    private int         status;         /// The "check" status, one of the class AC_* constants.

    /******************************************************************
    * If `status' indicates an improper flag has been found, the first 
    * (leftmost) improper flag letter; otherwise the value '\0'.
    ******************************************************************/
    private char        badFlagLetter;  
    /******************************************************************
    * The index of the argument (if any) that specifies a flag. This
    * variable is set by checkArgs. The indices are chars,
    * one for each possible flag letter. The element for a letter
    * is: -1 for a flag that was not specified, the index of
    * the argument that specified the flag if the flag is specified.
    ******************************************************************/
    private int []  flagsUsed;   

    /******************************************************************
    * A constructor that initializes the object with the program name, 
    * that no flags are allowed, the minimum and maximum number of 
    * allowed data arguments, a string describing the data arguments,
    * and a status of AC_UNCHECKED.
    * Methods `addSimpleFlag' and `addParamFlag' must be called
    * to set the flag letters permitted, but the constructor will instantiate the
	 * arrays to 128 elements (large enough to accomodate all of the letters that might
	 * be flags.
    *
    * @param programName    The program name
    * @param minArgCnt      The minimum number of data arguments required
    * @param maxArgCnt      The maximum number of data arguments allowed or -1 if there is no limit
    * @param argsDescriptor The String that describes in the "usage" of the data arguments.
    ******************************************************************/
    public ArgsChecker (String programName, int minArgCnt, int maxArgCnt, String argsDescriptor)
    {
    }

    /******************************************************************
    * Add flag letter `letter' with description `descriptor' to
    * the list of the program's allowed simple flags.
    *
    * @param letter     The flag letter
    * @param descriptor A one-line description of the flag letter
    ******************************************************************/
    public void addSimpleFlag(char letter, String descriptor)
    {
    }

    /******************************************************************
    * Add flag letter `letter' with description `descriptor' to
    * the list of the program's allowed parameterized flags.
    *
    * @param letter     The flag letter
    * @param descriptor A one-line description of the flag letter
    ******************************************************************/
    public void addParamFlag(char letter, String descriptor)
    {
    }

    /******************************************************************
    * If the object's status indicates a problem with a flag,
    * return the first (leftmost) erroneously specified flag letter.
    * If the object's status does not indicate a problem with a flag,
    * return the null character '\0'.
    *
    * @return   The flag letter.
    ******************************************************************/
    public char getBadFlagLetter()
    {
    }

    /******************************************************************
    * Return the status of the object.
    *
    * @return   The argument status, one of the class AC_* constants.
    ******************************************************************/
    public int getStatus()
    {
    }

    /******************************************************************
    * This method indicates whether or not flag `letter' has
    * been set.
    *
    * @param letter The flag letter.
    * @return       Negative if the flag is not set, the index of
    *               the argument that specified the flag if the flag 
    *               is specified.
    ******************************************************************/
    public int getFlag(char letter)
    {
    }

    /******************************************************************
    * This method indicates whether or not flag `letter' is an allowed
    * simple flag.
    *
    * @param letter The flag letter.
    * @return       True if letter is an allowed simple flag, false otherwise.
    ******************************************************************/
    public boolean isSimpleFlag(char letter)
    {
    }

    /******************************************************************
    * This method indicates whether or not flag `letter' is an allowed
    * param flag.
    *
    * @param letter The flag letter.
    * @return       True if letter is an allowed parameterized flag, false otherwise.
    ******************************************************************/
    public boolean isParamFlag(char letter)
    {
    }

    /******************************************************************
    * Checks the command-line arguments for correct usage.  Sets the
    * object's status to one of the class AC_* values.  Sets which flags
    * have been specified.
    *
    * @param args       The array containing the command-line arguments.
    * @param errorStrm  If null and an error is found, the method 
    *                   produces no output and returns.
    *                   If non-null and an error is found, printError
    *                   is called to output an error message to errorStrm
    *                   and abort the program. No output is produced
    *                   by this method if no error is found.
    * @return           If a flag error is encountered, the index
    *                   of the argument containing the error.  
    *                   If no flag error, the index of the first
    *                   data argument. If there are no data arguments, 
	 *                   return -1.
    ******************************************************************/
    public int checkArgs(String args[], PrintStream errorStrm)
    {
    }

    /******************************************************************
    * Check the flag letters specified in a flag argument.
    *
    * @param argIndex   The index of the argument to be checked.
    * @param args       The array containing the command-line arguments.
    * @return           If no error is found and the argument specifies
    *                   a parameterized flag, return the index of the 
    *                   parameter argument.  Otherwise return the index
    *                   of the argument checked.
    ******************************************************************/
    private int checkArg(int argIndex, String [] args)
    {
    }

    /******************************************************************
    * Return a string representing the state of the object.
    *
    * @return   A string representing the object's state.
    ******************************************************************/
    public String toString()
    {
        String ss;
        ss = this.programName + ",simple=";
        for (char letter = 0; letter<=MAX_LETTER; letter++)
            if (this.simpleFlags[letter] != null)
                ss = ss + letter;
        ss = ss + ",param=";
        for (char letter = 0; letter<=MAX_LETTER; letter++)
            if (this.paramFlags[letter] != null)
                ss = ss + letter;
        ss = ss + ",cnt=" + minArgCnt + "/" + maxArgCnt + ":set=";
        for (char letter = 0; letter<=MAX_LETTER; letter++)
            if (this.flagsUsed[letter] != -1)
                ss = ss + letter;
        ss = ss + ":status=" + status + ",bad=" + badFlagLetter;
        return ss;
    }

    /******************************************************************
    * Output to `strm' a usage summary for the program.
    *
    * @param strm   The stream the summary is output to.
    ******************************************************************/
    public void printHelp(PrintStream strm)
    {
        int fieldWidth;
        int length;

        strm.printf("Usage: java %s [Flags]... %s\n", this.programName,
         argsDescriptor);
        strm.printf("Flags:\n");

        for (char letter=0; letter<=MAX_LETTER; letter++)
        {
            if (this.simpleFlags[letter] != null)
                strm.printf("    %c %s %s\n", letter,
                 "   ", this.simpleFlags[letter]);
        }
        for (char letter=0; letter<=MAX_LETTER; letter++)
        {
            if (this.paramFlags[letter] != null)
                strm.printf("    %c %s %s\n", letter,
                 "Arg", this.paramFlags[letter]);
        }
    }

    /******************************************************************
    * If the object's status indicates an error, output to `strm' an 
    * error message, then exit.
    *
    * @param strm       The output stream
    * @param argIndex   The index in the `args' array of the erroneous flag
    * @param args       The array containing the command-line arguments 
    ******************************************************************/
    public void printError(PrintStream strm, int argIndex, String args[])
    {
        if (this.status == this.AC_BAD_FLAG)
        {
            strm.printf("Usage Error: ");
            strm.printf("Invalid flag '%c' specified.\n",
             this.getBadFlagLetter());
            strm.printf("\n");
            this.printHelp(strm);
            System.exit(1);
        }
        else if (this.status == this.AC_NO_FLAG_PARAM)
        {
            strm.printf("Usage Error: ");
            strm.printf("Flag '%c' specified without a parameter.\n",
             this.getBadFlagLetter());
            strm.printf("\n");
            this.printHelp(strm);
            System.exit(1);
        }
        else if (this.status == this.AC_BAD_PARAM_FLAG)
        {
            strm.printf("Usage Error: ");
            strm.printf("In argument \"%s\", parameterized flag '%c' was not the last character.\n", 
             args[argIndex],
             this.getBadFlagLetter());
            strm.printf("\n");
            this.printHelp(strm);
            System.exit(1);
        }
        else if (this.status == this.AC_TOO_FEW_DATA_ARGS)
        {
            strm.printf("Usage Error: ");
            strm.printf("At least %d data argument(s) required, %d specified.\n",
             this.minArgCnt,
             args.length-argIndex);
            strm.printf("\n");
            this.printHelp(strm);
            System.exit(1);
        }
        else if (this.status == this.AC_TOO_MANY_DATA_ARGS)
        {
            strm.printf("Usage Error: ");
            strm.printf("At most %d data argument(s) allowed, %d specified.\n",
             this.maxArgCnt,
             args.length-argIndex);
            strm.printf("\n");
            this.printHelp(strm);
            System.exit(1);
        }
    }
}
