package org.treesched.schedules;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.Logger;
import org.treesched.AbstractSchedule;
import org.treesched.DateUtils;
import org.treesched.Interval;
import org.treesched.Schedule;

/**
 * Provide a schedule for a specific date or between two dates.
 * <p>
 * Allowed attributes:
 * <table border="1">
 *   <tr><td>format</td><td>The date format to use to parse the other attributes.</td>
 *     <td><i>Optional</i></td></tr>
 *   <tr><td>from</td><td>The from date for the schedule. Defaults to the the
 *     0 java date.</td><td><i>Optional</i></td></tr>
 *   <tr><td>to</td><td>The to date for the schedule. Defaults to the max java date.</td>
 *     <td><i>Optional</i></td></tr>
 *   <tr><td>on</td><td>A specific date on which to provide the schedule.</td>
 *     <td><i>Optional</i></td></tr>
 * </table>
 * <p>
 * Any number of nested sub schedules are allowed.
 * <p>
 * typical configuration is:
 * <code><pre>
 * &lt;date on="25-dec-04"/&gt;
 * </pre></code>
 * 
 * @author Rob Gordon
*/


final public class DateSchedule extends AbstractSchedule implements Serializable {

    private static final long serialVersionUID = 20050226;
    
    private static Logger logger = Logger.getLogger(DateSchedule.class);
    
	public static final String DEFAULT_DATE_FORMAT = "dd-MMM-yy";
	private String format = DEFAULT_DATE_FORMAT;
	
	private Date startDate;
	private Date endDate;

	/**
	 * Set the date format to use for translating string attributes.
	 * 
	 * @param dateFormat The date format.
	 */		
	public void setFormat(String dateFormat) {	
		this.format = dateFormat;
	}

	/**
	 * Get the date format used for translating string attributes.
	 * 
	 * @return The date format being used.
	 */
	public String getFormat() {		
		return this.format;	
	}
	
	/**
	 * Set the from date as a String.
	 * 
	 * @param startDateString The from date. May be null which 
	 * indicates the beginning of the time.
	 * @throws ParseException If the String isn't a Date.
	 */
	public void setFrom(String startDateString) 
			throws ParseException {
	    if (startDateString == null) {
	        startDate = null;
	    }
	    else {
	        SimpleDateFormat format = new SimpleDateFormat(getFormat());
	        startDate = format.parse(startDateString);
	    }
	}
	
	/**
	 * Get the from Date as a String.
	 * 
	 * @return The from date. May be null.
	 */
	public String getFrom() {
	    if (startDate == null) {
	        return null;
	    }
		SimpleDateFormat format = new SimpleDateFormat(getFormat());
		return format.format(startDate);
	}

	/**
	 * Set the end date as a String.
	 * 
	 * @param endDateString The end date. May be null.
	 * @throws ParseException If the string isn't a valid date.
	 */
	public void setTo(String endDateString) 
			throws ParseException {
	    if (endDateString == null) {
	        endDate = null;
	    }
	    else {
	        SimpleDateFormat format = new SimpleDateFormat(getFormat());
	        endDate = format.parse(endDateString);
	    }
	}

	/**
	 * Return the to date as a string.
	 * 
	 * @return The to date, may be null.
	 */
	public String getTo() {
	    if (endDate == null) {
	        return null;
	    }
		SimpleDateFormat format = new SimpleDateFormat(getFormat());
		return format.format(endDate);
	}

	/**
	 * Set the on date as a string.
	 * 
	 * @param in The on text.
	 * @throws ParseException If the string isn't a date.
	 */
	public void setOn(String on) throws ParseException {		
		setFrom(on);
		setTo(on);
	}

	
	/**
	 * Return the start date.
	 * 
	 * @return The start date.
	 */	
	public Date getStartDate(Date now) {
	    if (startDate == null) {
	        return new Date(0);
	    }
		return startDate;
	}

	/**
	 * Return the end date.
	 * 
	 * @return The end date.
	 */
	public Date getEndDate(Date now) {
	    if (endDate == null) {
	        return new Date(Long.MAX_VALUE);
	    }
		return DateUtils.endOfDay(endDate);
	}

	/*
	 *  (non-Javadoc)
	 * @see org.treesched.Schedule#nextDue(java.util.Date)
	 */
	public Interval nextDue(Date now) {
	    if (now == null) {
	        throw new NullPointerException();
	    }
	    if (now.compareTo(getEndDate(now)) > 0) {
	        return null;
	    }
	    Interval nextInterval = new Interval(getStartDate(now), getEndDate(now));
		Schedule child = getChildSchedule();
		if (child == null) {
			return nextInterval;						
		}
		child.setLimits(nextInterval);
	    return child.nextDue(now);
	}
	/**
	 * Override toString.
	 */
	public String toString() {
		
		return this.getClass().getName() + " from " + getFrom() + " to " + getTo();
	}
}
