package lib206;

import java.util.*;
import java.io.*;

/****
 *
 * Class Enum is an abstract parent class for an enumerated data type.
 * Enumeration literal values are represented as Strings.  The public data
 * member <tt>value</tt> holds the string value of an enumeration literal.
 *                                                                      <p>
 * Extending classes represent an enumerated type as a protected array of
 * strings, each string being one of the legal enumeration literals of the
 * type.  The extending constructor calls the Enum constructor with a string
 * enumeration value provided by its caller, and the list of legal enumeration
 * values.  The Enum constructor validates the caller-provided value, and if
 * legal assigns it to this.value.  If the caller-provided enumeration value is
 * illegal, the Enum constructor throws an IllegalEnumException.
 *                                                                          <p>
 * Here is an example of an extending class that defines an enumerated type for
 * the seven days of the week:
 *                                                                        <pre>
 *  class DayOfTheWeek extends Enum {
 *      public DayOfTheWeek(String value) {
 *          super(value, possibles);
 *      }
 *      static protected String[] possibles = {
 *        "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"
 *      };
 *  }                                                                    </pre>
 *
 *
 * Here are a legal and illegal construction of enumerated DayOfTheWeek
 * values: 
 *                                                                        <pre>
 *  DayOfTheWeek goodDay = new DayOfTheWeek("Monday");
 *  DayOfTheWeek badDay = new DayOfTheWeek("Greenday");			 </pre>
 *
 * Here is how the public <tt>value</tt> field is used to access a DayOfTheWeek
 * value:
 *                                                                        <pre>
 *  if (goodDay.value == "Monday") ...					 </pre>
 *
 * As in Pascal-class languages of yesteryear, an enumation literal can be
 * treated as an integer value.  There are next and previous methods that
 * return enumeration string values based on the relative ordering in the
 * enumeration.  There is also a getPosition method that returns the relative
 * integer value of an enumeration literal directly.  There is a constructor
 * overload that builds an enumation literal given its ordinal position in a
 * list of possibles.  If an extending class wants to make this form of
 * construction available to users, it implements its own int-valued
 * constructor overload.  E.g., here is such a constructor for the DayOfTheWeek
 * example:
 *                                                                        <pre>
 *     public DayOfTheWeek(int position) {
 *         super(position, possibles);
 *     }                                                                 </pre>
 *
 */

public abstract class Enum implements Serializable {

    /**
     * Construct an enumerated literal object of the given string value, if
     * that string value is one of the legal values in the given possibles
     * array.  If the given string value is not among the possibles, throw an
     * IllegalEnumException.
     */
    public Enum(String value, String[] possibles) throws IllegalEnumException {

        /*
         * Save a reference to the possibles list for use in the previous and
         * next methods.
         */
        this.possibles = possibles;

        /*
         * Loop through the possibles looking for the given value, and if found
         * make the value of this the given value.  Otherwise throw the
         * exception.
         */
        for (int i=0; i<=possibles.length-1; i++) {
            if (possibles[i] == value) {
                this.value = value;
                this.position = i;
                return;
            }
        }
        throw new IllegalEnumException();
    }

    /**
     * Construct an enumerated literal object from the given position in the
     * given possibles.  If position < 0 or position > possibles.length, throw
     * an IllegalEnumException.
     */
    public Enum(int position, String[] possibles) throws IllegalEnumException {
        this.possibles = possibles;
        if ((position >= 0) && (position < possibles.length)) {
            value = possibles[position];
	    this.position = position;
        }
        else {
            throw new IllegalEnumException();
        }
    }

    /**
     * Return the next enum value in the list of possibles if there is one,
     * null otherwise.  E.g., if
     *                                                                    <pre>
     *     DayOfTheWeek day = new DayOfTheWeek("Wednesday")
     *                                                                   </pre>
     * then <tt>day.next</tt> = <tt>"Thursday"</tt>
     */
    public String next() {
        if (position < possibles.length - 1)
            return possibles[position + 1];
        else
            return null;
    }

    /**
     * Return the previous enum value in the list of possibles if there is one,
     * null otherwise.  E.g., if
     *                                                                    <pre>
     *     DayOfTheWeek day = new DayOfTheWeek("Wednesday")
     *                                                                   </pre>
     * then <tt>day.previous</tt> = <tt>"Tuesday"</tt>
     */
    public String previous() {
        if (position > 0)
            return possibles[position - 1];
        else
            return null;
    }

    /**
     * Convert this to a string by returning the value.
     */
    public String toString() {
	return value;
    }

    /**
     * Return the numeric position of this in the list of possibles.
     */
    public int getPosition() {
	return position;
    }

    /** Enumerated literal value for this enumerated type */
    public String value;

    /** The ordinal position of this enum literal in the list of possibles */
    protected int position;

    /** Reference to the list of possibles in the extending class.  This
	reference is used in next and previous methods.
     */ 
    protected String[] possibles;

}