import java.io.*;
/**
 * Offers the user of a mail box several options, such as the width of the line
 * lets the user design a personal signature, stores some personal information 
 * about the user and contains an address book.
 * @author Khong Lovan
 * @author Elias Vafiadis
 * @author Anthony Nakaar
 * @author Wanlin Liu
 * version 1.0 of October, 1999
 */

public class Options 
    implements OptionsInterface {
    //+--------+----------------------------------------------------------
    //| Fields |
    //+--------+
    
    /** The maximum number of options an array can store. */
    final int MAX = 50;

    /** An array of options.*/
    OptionField[] optionTable = new OptionField[MAX];
   
   

    //+--------------+---------------------------------------------------------
    //| Constructors |
    //+--------------+
    
    /**
     * Takes the user name as a parameter and builds a new Options object
     * With the username and the usrName, and provide some basic options
     * such as password, personalInfo, etc.
     */
    public Options(String usrName){
        // Open the file that stores options.
        File file = new File(usrName + ".opt");
        if (file.exists() == true) {   
            try{
                DataInputStream inFile = 
                    new DataInputStream(new FileInputStream(usrName + ".opt"));
                int i = 0;
                try {
                    char ch = inFile.readChar();
                    // Read in from the file unti the file ends.
                    while(ch != -1) {           
                        // Read one line and create an option.
                        // str will store all the characters in one line.
                        String str = "";
                        // Continue reading until the end of the line.
                        while(ch != '\n') {
                            // Add the new character to the string.
                            str = str + ch; 
                            // read the next character.
                            ch = inFile.readChar();
                        }//while
                        // Create a new option.
                        try{
                            optionTable[i++] = new OptionField(str);
                            System.out.println("Option " + optionTable[i-1].getOptionName() + " built successfully.");
                           
                            System.out.println(optionTable[i-1].toString());
                        }//try
                        
                        catch(OptionException e) {
                        }// catch(OptionException)
                        // Skip the "/n" and read the next character.
                        ch = inFile.readChar();
                    }//while
                    // Close the file after all the information is read.
                    inFile.close();
                    System.out.println("File loaded and closed");
                }// try     
                catch(IOException e) {
                }// catch(IOException)
            }// try
            catch(FileNotFoundException e) {
            }// catch
        }// if
        else {
            
            // Provide two integer-value options, line width and messages 
            // per page.
            optionTable[0] = 
                new OptionField("lineWidth", "java.lang.Integer", new Integer(80)); 
            optionTable[1] = 
                new OptionField("msgPerPage", "java.lang.Integer", new Integer(20));
            // Provide basic string-valued options.     
            // name that appears in out going mail.
            optionTable[2] = 
                new OptionField("nameInOutgoingMail", "java.lang.String", usrName);
                            
            // Provide basic boolean valued options, all options are true for now.
            /* The option to save sent mails. */
            optionTable[3] = 
                new OptionField("saveSentMails", "java.lang.Boolean", 
                                new Boolean(true));              
            /* The option to attach the original message in the reply. */
            optionTable[4] = 
                new OptionField("quote", "java.lang.Boolean", new Boolean(true));    
            /* The option to separate the quoted message. */
            optionTable[5] = 
                new OptionField("separator", "java.lang.Boolean",
                                new Boolean(true));    
            /* The option to preview a message. */
            optionTable[6] =
                new OptionField("previewMessages", "java.lang.Boolean",
                                new Boolean(true));

            /* User's full name. */
            optionTable[7] = 
                new OptionField("fullName", "Name", new Name( "unknown", usrName));
            /**optionTable[7] = 
                new OptionField("fullName", "Name", new Name("Wanlin", "Liu"));
            */
            
            /* The preferred filter. Waiting to be defined.*/
            /* Filter preferredFilter;*/   
        }// else
    }//Options(String)
    
    
    //+------------+---------------------------------------------------------
    //| Extractors |
    //+------------+
    
    /**
     * Purpose: Get an option whose value is a number.  For now, use integers as
     * our numbers.
     * Parameter option name
     * Pre:  The option is initialized.
     * Post: The option is unchanged.
     * Return: The value of the given option.
     * @exception OptionException
     * If that option is undefined.
     */
   public int getNumericOption(String optionName) 
       throws OptionException {
       /** Scan through the numeric option array.*/
       int i = 0;
       while(optionTable[i] != null) {
           /** If the option is defined, return the value. */
           if(optionTable[i].getOptionName().equals(optionName)) {
               return ((Integer) optionTable[i].getOptionValue()).intValue();
           }//if
       }//for
       /** If the option has not been defined, throw an exception. */
       throw new OptionException("Option undefined.");                      
   }//getNumericOption(String)
    
    /**
     * Purpose: Get an option whose value is a String. 
     * Parameter option name
     * Pre:  The option is initialized.
     * Post: The option is unchanged.
     * Return: The value of the given option.
     * @exception OptionException
     * If that option is undefined.
     */
    public String getStringOption(String optionName) 
        throws OptionException {
        /** Scan through the string option array.*/
        int i = 0;
        while(optionTable[i] != null) {
            /** If the option is defined, return the value. */
            if(optionTable[i].getOptionName().equals(optionName)) {
                return (String)optionTable[i].getOptionValue();
            }//if
        }//for
        /** If the option has not been defined, throw an exception. */
        throw new OptionException("Option undefined.");    
    }//getStringOption(String)
    
    
    /**
     * Purpose: Get an option whose value is some other object.
     * Parameter: option name
     * Pre: The option is initialized
     * Post: The option is unchanged.
     * Return: The value of the given option.
     * @exception OptionException
     *   If that option is undefined.
     */
    public Object getOption(String optionName)
        throws OptionException {
        /** Scan through the object option array.*/
        int i = 0;
        while(optionTable[i] != null) 
            /** If the option is defined, return the value. */
            if(optionTable[i].getOptionName().equals(optionName)) {
                return optionTable[i].getOptionValue();
            }//if
        
        /** If the option has not been defined, throw an exception. */
        throw new OptionException("Option undefined.");    
    }//getOption(String)
    
    
    /**
     * Purpose: Get a flag: something that can either be on (true) or
     * off (false).
     * Parameter: the name of the flag.
     * Pre: The flag has been initialized.
     * Post: The flag has not been changed.
     * Return: the value of the flag, e.g. on or off.
     * @exception OptionException
     * if that option is undefined.
     */
    public boolean getFlag(String flagName)
        throws OptionException {
        /** Scan through the boolean option array.*/
        int i = 0;
        while(optionTable[i] != null) {            
            /** If the option is defined, return the value. */
            if(optionTable[i].getOptionName().equals(flagName)) {
                return ((Boolean)optionTable[i].getOptionValue()).booleanValue();
            }//if
        }//for
        /** If the option has not been defined, throw an exception. */
        throw new OptionException("Option undefined.");    
    }//getFlag(String)
    
    
    //+-----------+--------------------------------------------------------
    //| Modifiers |
    //+-----------+

     /**
     * Purpose: Set an option whose value is a string.  return the old value.
     * Parameter: option name and the new value.
     * Pre: the option is initialized.
     * Post: The option takes on the new value, no other option value is changed.
     * Return: The old value of the given option.
     */
    public void setStringOption(String optionName,String newVal) 
        throws OptionException{
         /** Scan through the string option array.*/
        int i = 0;
        while(optionTable[i] != null) {
            /** If the option is defined, modifier the value and leave the loop. */
            if((optionTable[i].getOptionName().equals(optionName)) &&
               (optionTable[i].getOptionType().equals("java.lang.String"))){
                optionTable[i].setOptionValue((String)newVal);
                break;
            }//if
            else {
                i++;
            }// else
        }// while
        /** If the option has not been defined, throw an exception. */
        if(optionTable[i] == null) {
            throw new OptionException();
        }   
    }// setStringOption
    
    /**
     * Purpose: Set an option whose value is a number.
     * For now, we assume that all values are of integer type.
     * Parameter: option name and the new value.
     * Pre: the option is initialized.
     * Post: The option takes on the new value, no other option value is changed.
     * Return: nothing
     */   
     public void setNumericOption(String optionName, int newVal)
         throws OptionException {
         /** Scan through the numeric option array.*/ 
         int i = 0;
         while(optionTable[i] != null) {
             /** If the option is defined, modifier the value and leave the loop. */
             if((optionTable[i].getOptionName().equals(optionName)) &&
                (optionTable[i].getOptionType().equals("java.lang.Integer"))){
                optionTable[i].setOptionValue(new Integer(newVal));
                break;
             }//if
             else {
                 i++;
             }// else
         }// while
         /** If the option has not been defined, throw an exception. */
         if(optionTable[i] == null) {
             throw new OptionException();
         }     
     }// setNumericOption
    
    /**
     * Purpose: Set a flag, i.e. turn it on or off.
     * Parameter: the name of the flag and the new value.
     * Pre: The flag has been initialized.
     * Post: The flag has been changed.
     * Return: nothing.
     */
    
    public void setFlag(String flagName, boolean flagValue)
        throws OptionException{
        /** Scan through the numeric option array.*/ 
        int i = 0;
        while(optionTable[i] != null) {
            /** If the option is defined, modifie the value and leave the loop. */
            if((optionTable[i].getOptionName().equals(flagName)) &&
               (optionTable[i].getOptionType().equals("java.lang.Boolean"))){
                optionTable[i].setOptionValue(new Boolean(flagValue));
                break;
            }//if
            else {
                i++;
            }// else
        }// while
        /** If the option has not been defined, throw an exception. */
        if(optionTable[i] == null) {
            throw new OptionException();
        }   
    }// setFlag      
    
    /**
     * Purpose: Set an option whose value is an object.
     * Parameter: option name and the new value.
     * Pre: the option is initialized.
     * Post: The option takes on the new value, no other option value is changed.
     * Return: The old value of the given option.
     */
    public void setOption(String optionName, String optionType, Object newVal) 
        throws OptionException{
        /** Scan through the numeric option array.*/ 
        int i = 0;
        while(optionTable[i] != null) {
            /** If the option is defined, modifier the value and leave the loop. */
            if((optionTable[i].getOptionName().equals(optionName)) &&
               (optionTable[i].getOptionType().equals(optionType))){
                optionTable[i].setOptionValue(newVal);
                break;
            }//if
            else {
                i++;
            }// else
        }// while
        /** If the option has not been defined, throw an exception. */
        if(optionTable[i] == null) {
            throw new OptionException();
        }   
    }// setOption      
    
    
    
    //+--------------+--------------------------------------------------
    //| Capabilities |
    //+--------------+
    
    /** 
     * Purpose: convert the contents of the object to a displayable string.
     * Paramter: none.
     * Pre: all the fields of the objects are initialized.
     * Post: no value is changed.
     * Return: a string containing all values of fields of this object.
     * Throws no exceptions.
     */
    public String toString(){
        String stuff = "The options of the user is " + "\n";
        int i = 0;
        // All the numeric options.
        while(optionTable[i] != null) {
            stuff = stuff + optionTable[i++].toString();
        }// while   
        return stuff;
    }// toString()
    
    /** Save the user's option info to a local file.
     *  takes the user name as the parameter.
     */
    public void save(String usrName) {
        try{
            DataOutputStream outFile = 
                new DataOutputStream(new FileOutputStream(usrName + ".opt"));
            int i = 0;
            while(optionTable[i] != null){
                outFile.writeChars(optionTable[i++].toString());
                System.out.println(optionTable[i-1].getOptionName() + " saved.");
            }//while
            // Signaling the end of the file.
            outFile.writeChar(-1);
            outFile.close();
            System.out.println("File saved and closed.");
        }// try
        catch(IOException e) {
        }//catch       
        
    }//save(String)
}

