package org.treesched.schedules;

import java.io.Serializable;
import java.util.Date;

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

/**
 * This schedule returns up to count number of child schedules. It is typically
 * used to count a number intervals for re-trying something, But could be used to count
 * the first n days of the month for instance.
 * <p>
 * The count will be reset if the end interval changes, i.e. when counting n days of the month,
 * and the month moves on. However in the retry situation to reset the count schedule it would
 * need to be reset.
 * <p>
 * Typical configuration would be:
 * <code><pre>
 * &lt;count count="5"&gt;
 *   &lt;interval interval="00:15"/&gt;
 * &lt;/count&gt;
 * 
 * @author Rob Gordon
 */

final public class CountSchedule extends AbstractSchedule implements Serializable {

    private static final long serialVersionUID = 20050226;
    
    private static final Logger logger = Logger.getLogger(CountSchedule.class);
    
    private int countTo;
	private int counted = 0;
	
	/** Remembers the last end time of the parent interval. */
	private Date last = new Date(0);

	/**
	 * Set the number to count to.
	 * 
	 * @param count The number to count to.
	 */
	public void setCount(String count) {	
		this.countTo = Integer.parseInt(count);
	}

	/**
	 * Get the number to count to.
	 * 
	 * @return The number to count to.
	 */
	public String getCount() {	
		return Integer.toString(countTo);
	}

	/*
	 *  (non-Javadoc)
	 * @see org.treesched.Schedule#nextDue(java.util.Date)
	 */
	public Interval nextDue(Date now) {
	    if (now == null) {
	        throw new NullPointerException();
	    }
		if (getChildSchedule() == null) {
		    throw new IllegalStateException("Count must have a child schedule.");
		}
		
		logger.debug(this + ": in date is " + now + ", count is " + counted);
		
		if (!last.equals(now)) {
		    ++counted;
		    last = now;
		}

		if ( counted <= countTo) {
			Schedule child = getChildSchedule();
			child.setLimits(getLimits());
			return child.nextDue(now);
		}
		else {
			return null;			
		}
	}

	/**
	 * Reset the count.
	 */
	public void reset() {
		counted=0;
		last = new Date(0);
	}
	
	/**
	 * Override toString to be more meaningful.
	 */

	public String toString() {
		return "Count Schedule, count to " + countTo;
	}
}
