package org.jcon.df.column;

import org.jcon.param.Param;
//import java.text.ParsePosition;
//import java.text.SimpleDateFormat;
//import java.util.Date;
import java.util.StringTokenizer;

/**
 * A date of the format m/d/yyyy. A planned future
 * enhancement is min and max date. ***
 *
 * This class represents an empty value as "".
 *
 * @author Tom Rouse
 */
public class DateColumn extends ColumnDef {

//---------- Private Fields ------------------------------
private int minYear = 1950;
private int maxYear = 2050;

//---------- Initialization ------------------------------
/**
 * No-arg to allow serialization.
 */
public DateColumn() {
    super();
    setDefaultValue("");
    type = "Date";
}
/**
 * A convience constructor. Also sets default to "".
 */
public DateColumn(String name) {
    this();
    setName(name);
}
public static void main(String args[]) {
    DateColumn test = new DateColumn();
    test.runUnitTest(args);
}
//---------- Abstract Implementation ---------------------
public void initFromParam(Param param) {
    checkStandardProperties(param); // superclass
    if (param.hasProperty("MinYear")) {
        setMinYear(param.getInt("MinYear"));
    }
    if (param.hasProperty("MaxYear")) {
        setMaxYear(param.getInt("MaxYear"));
    }
}
/**
 * Checks for valid date of the format m/d/yyyy.
 */
public String validateString(String text) {
    if (validateDate(text) == false) {
        return "'" + text + "' is an invalid date.\n" +
        displayName + " must be a date of the format 'M/D/YYYY'\n" +
        "In the range " + getRangeDescription();
    } else {
        return null; // Okay
    }
}
public String getMyPropertySummary() {
    return "format=m/d/yyyy,";
}
//---------- Superclass Overrides ------------------------
public int getPreferredLength() {
    return 10; // For mm/dd/yyyy
}
protected String getAutomaticDescription() { // 99
    return "The date may be entered as MM/DD/YY or MM/DD/YYYY " +
        "in the range " + getRangeDescription();
}
//---------- Public Methods ------------------------------
//--- Pair
public int getMinYear() {
    return minYear;
}
public void setMinYear(int minYear) {
    this.minYear = minYear;
}
//--- Pair
public int getMaxYear() {
    return maxYear;
}
public void setMaxYear(int maxYear) {
    this.maxYear = maxYear;
}
//--- Other
public String getRangeDescription() {
    return "1/1/" + minYear + " to " + "12/31/" + maxYear + ".";
}
//---------- Private Methods -----------------------------
private boolean validateDate(String text) {

    StringTokenizer tokens = new StringTokenizer(text,"/");

    String month, day, year;
    try {
        month = tokens.nextToken();
        day   = tokens.nextToken();
        year  = tokens.nextToken();
    }
    catch (Exception ex) {
        return false;
    }
    if(validateMonth(month) == false) return false;
    if(validateYear(year) == false) return false;
    if(validateDay(month, day, year) == false) return false;
    return true;
}
private boolean validateMonth(String text) {
    // Must be an int
    if (! isInt(text) ) return false;
    // If in range then month is okay
    int month = Integer.parseInt(text);
    return isBetween(1, month, 12);
}
private boolean validateDay(String textMonth,
        String textDay, String textYear) {

    if (! isInt(textDay) ) return false;

    int day = Integer.parseInt(textDay);
    if (day < 1) return false;
    int month = Integer.parseInt(textMonth);
    int year = Integer.parseInt(textYear);

    if (month == 2 && year % 4 == 0) {
        // February and leap year
        if (day > 29) return false;

    } else if (month == 2) {
        // February
        if (day > 28) return false;

    } else if (month == 4 || month == 6 || month == 9 || month == 11) {
        // April, June, September, November
        if (day > 30) return false;

    } else {
        // All other months
        if (day > 31) return false;
    }
    return true;
}
private boolean validateYear(String text) {
    // Must be an int
    if (! isInt(text) ) return false;
    // If in range then year is okay
    int month = Integer.parseInt(text);
    return isBetween(minYear, month, maxYear);
}
//----- Helpers
private boolean isInt(String text) {
    try {
        int irrelevant = Integer.parseInt(text);
        return true;
    } catch(Exception ex) {
        return false;
    }
}
private boolean isBetween(int first, int value, int second) {
    if (first <= value && value <= second) {
        return true;
    } else {
        return false;
    }
}
//----- Other
private void runUnitTest(String args[]) {
    /** if (args.length == 0) {
        print("Enter test values after className, such as:"
            + ">java DateColumn 3/2/97 33/2/1998 xxx");
        return;
    } */
    for (int i = 0; i < args.length; i++) {
        String value = args[i];
        String result = validate(value);
        if (result == null) {
            print(value + " is okay");
        } else {
            print(value + " is invalid");
        }
    }
    /** // Built in tests
    testDate("xxx");
    testDate("2/28/1990");
    testDate("2/29/1990");
    testDate("2/29/1991");
    testDate("0/1/1998");
    testDate("xxx"); */

    print("Test complete");
}
//--- Std
private void print(String text) {
    System.out.println(text);
}

} // End class
