//: MyDate.java

/** Simple date class
  * @author Mark Crocker <mcrocker@micron.net>
  * @author http://www.markcrocker.com/~mcrocker/
  * @version 0.96
  */

package com.markcrocker.thoughtworks;

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

public class MyDate {
    
    private static int[] monthLength = {31,28,31,30,31,30,31,31,30,31,30,31};  
                                // Number of days in each month.
    private static int[] monthOffset = {0,31,59,90,120,151,181,212,243,273,304,334}; 
                                // Number of days in year prior to current month
    private int leapMonth;      // The number of days to add to the date to
                                // accomodate the leap day in this year.  Depends
                                // on whether month is after February or not.
    private int leapOffset;     // The number of days to add for all the
                                // leap days in the previous years.
    private int debugLevel = 0; // Vestigal 1960s style debugging tool.
    
    private int date;           // Date as the number of days since 1900-Jan-01

    /** MyDate primary constructor.  Converts date to an internal format for 
      * storage and checks for invalid or out of range dates.
      * @param year year past 1900 (0-199).  Ex: 1981 will be year 81, 2009 is 109.
      * @param month month of the year (1-12).
      * @param day day of the month (1-28,29,30, or 31) depending on the month.
      * @exception BadDateException thrown if the date is malformed or out of range.
      */
    MyDate(int year, int month, int day) throws BadDateException {
	if (debugLevel > 2) { System.out.println("MyData instance constructed with year = " + year + " month = " + month + " day = " + day); }

	/* First check for valid year and month.  These are fixed, so its an easy check */
	if ((year < 0)   ||
	    (year > 199) ||
	    (month < 1)  ||
	    (month > 12)) {
	    throw new BadDateException("-->Error in Year (= " + year +
				       ") or Month (= " + month +
				       ")");
	}

	/* Before checking for valid day, need to figure out leap days.
	 * Also take advantage of the logic to do the leap day offset
         * calculation.*/
	leapMonth = 0;                   // Default.
	if (year%4 == 0) {               // Is it a leap year?
	    if (year > 4) {              // Dont need previous years leap days until 1905
		leapOffset = (year-1)/4; // Leap days for all previous years.
	    } else {
		leapOffset = 0;
	    }
	    if (month == 2) {            // Is it February?
		leapMonth = 1;
	    } else if (month > 2) {      // Is it after February?
		leapOffset += 1;         // Can count leap day of this year.
	    }                            // Must be January, nothing else required.
	} else {                         // NOT a leap year.
	    leapOffset = year/4;         // Leap days for all previous years, this one doesnt have one.
	}

	/* Check for valid day using leapMonth info */
	if ((day < 1) ||
	    (day > monthLength[month-1] + leapMonth)) {
	    throw new BadDateException("-->Error in Day (= " + day +
				       " where Month = " + month +
				       ")");
	}

	/* Finally, decode date into internal format (ie: an integer
	 * representing the number of days since 1900-Jan-01). */
	date = day + monthOffset[month-1] + leapOffset + year*365; // Actual date calculation.

    }

    /** getDate.  Mostly used in calculating date arimthmatic.
      * @return Returns date as the number of days since 1900-Jan-01.
      */
    public int getDate() {  
      return date;
    }

    /** setDebugLevel.  Sets debugLevel variable for 1960s style debugging.
      * @deprecated Only used during code development.
      */
    public void setDebugLevel(int dLevel) {
      debugLevel = dLevel;
    }

    /** toString.  Java default string converter.
      * @return Returns date as a string that represents the number of days since 1900-Jan-01.
      */
    public String toString() {
	return Integer.toString(date);
    }

    /** between.  Calculates the number of days between two dates.  Commutative and exclusive.
      * @return Returns number of days between two dates (exclusive).
      */
    public int between(MyDate someOtherDate) {
	int between = Math.abs(date - someOtherDate.getDate())-1; // basic calculation.
	if (between < 0) // have to watch for case where the two dates are the same.
	    between = 0;
	return between;
    }

} ///:~


/* Todo
-------

1. Change date range from 0-199 to 1900-2099.

 */