//[0
/**
 * A class (rather than an enum) for the months of the year.
 *
 * @author  Prof. David Bernstein, James Madison University
 */
public class Month
{
//]0
    private static final Month[]  VALUES = new Month[12];

    private static       int      next   = 0;    

    private static final String[] IDS = 
    {
        "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
        "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"
    };

//[0
    public static final Month JANUARY   = new Month("January",  31);
    public static final Month FEBRUARY  = new Month("February", 28);
    public static final Month MARCH     = new Month("March",    31);
    public static final Month APRIL     = new Month("April",    30);    
    public static final Month MAY       = new Month("May",      31);
    public static final Month JUNE      = new Month("June",     30);
    public static final Month JULY      = new Month("July",     31);    
    public static final Month AUGUST    = new Month("August",   31);
    public static final Month SEPTEMBER = new Month("September",30);
    public static final Month OCTOBER   = new Month("October",  31);
    public static final Month NOVEMBER  = new Month("November", 30);
    public static final Month DECEMBER  = new Month("December", 31);

    private final int    days;
    private final String name;

    /**
     * Explicit Value Constructor.
     *
     * @param name   The name of the Month
     * @param days   The number of days in the Month
     */
    private Month(String name, int days)
    {
        this.name = name;
        this.days = days;
//]0        
        VALUES[next] = this;
        ++next;
//[0
    }
//]0
    /**
     * Compare this Month to the given month.
     *
     * @param other  The Month of interest
     * @return       -1, 0, or 1
     */
    public int compareTo(Month other)
    {
        if       (this.ordinal() < other.ordinal())  return -1;
        else if  (this.ordinal() == other.ordinal()) return  0;
        else                                         return  1;
    }
//[0
    /**
     * Get the 3-letter abbreviation for this Month.
     *
     * @return  The 3-letter abbreviation
     */
    public String getAbbreviation()
    {
        String       result;
      
        if (name.length() > 3) result = name.substring(0,3)+".";
        else                   result = name;

        return result;      
    }

    /**
     * Get the numeric value of this Month (in the interval [1,12]).
     *
     * @return  The numeric value of this Month
     */
    public int getNumber()
    {
        return ordinal()+1; // ordinal() returns the position in the declaration
    }

    /**
     * Get the (normal) number of days in this Month.
     *
     * @return  The normal number of days in this Month.
     */
    public int getLength()
    {
        return days;      
    }
//]0
    /**
     * Return the ordinal value of this instance.
     *
     * @return  The ordinal value (0-based)
     */
    public int ordinal()
    {
        for (int i=0; i<VALUES.length; i++)
        {
            if (this == VALUES[i]) return i;            
        }
        // Shouldn't get here!
        return -1;
    }
//[0   
    /**
     * Return the Month that corresponds to a given String.
     *
     * @param s   The String representation
     * @return    The corresponding Month
     * @throws    IllegalArgumentException if there is no match
     */
    public Month parseMonth(String s) throws IllegalArgumentException
    {
        Month   result;
        String  u;
       
        u = s.toUpperCase();
       
        result = Month.valueOf(u);           
        return result;

       
        // A more elaborate version
        //
        // Month[] all;
        // all = Month.values();
        // for (int i=0; i<all.length; i++)
        // {
        //    if (s.equalsIgnoreCase(all[i].name) 
        //        || s.equalsIgnoreCase(all[i].getAbbreviation()))
        //    {
        //        return all[i];
        //    }
        // }
        // throw new IllegalArgumentException("No such Month");
    }
   
    /**
     * Get a String representation of this Month
     *
     * @return   The String representation (i.e., the name)
     */
    public String toString()
    {
        return name;      
    }
//]0
    /**
     * Get all of the Month objects.
     *
     * @return An array containing all instances
     */
    public static Month[] values()
    {
        return VALUES;
    }

    /**
     * Get the Month associated with a particaulr identifier.
     *
     * @param s  The identifier
     * @return   The corresponding Month (or null)
     */
    public static Month valueOf(String s)
    {
        for (int i=0; i<IDS.length; i++)
        {
            if (s.equals(IDS[i])) return VALUES[i];
        }
        return null;
    }
//[0
}
//]0
