package org.treesched;

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

/**
 * A representation of an interval between two dates.
 * 
 * @author Rob Gordon
 */

public class Interval implements Serializable {

    private static final long serialVersionUID = 20050226;
    
	private final Date fromDate;
	private final Date toDate;
	
	/**
	 * Constructor for an interval that is for ever from the date.
	 * 
	 * @param at the start date for the inerval.
	 */
	public Interval(Date at) {
		fromDate = new Date(at.getTime());
		toDate = new Date(Long.MAX_VALUE);
	}
	
	/**
	 * Constructor for an interval between two dates.
	 * 
	 * @param from The starting date.
	 * @param to The ending date.
	 */
	public Interval(Date from, Date to) {
		fromDate = new Date(from.getTime());
		toDate = new Date(to.getTime());
	}
	
	/**
	 * Constructor for an interval between a date given as milliseconds and for ever.
	 * 
	 * @param fromTime The date given in milliseconds.
	 */
	public Interval(long fromTime) {
		this(new Date(fromTime));
	}
	
	/**
	 * Constructor for an interval between two dates given as milliseconds.
	 * 
	 * @param fromTime
	 * @param toTime
	 */
	public Interval(long fromTime, long toTime) {
		fromDate = new Date(fromTime);
		toDate = new Date(toTime);
	}

	/**
	 * The copy constructor. This is a shallow copy.
	 *  
	 * @param other The other interval.
	 */
	public Interval(Interval other) {
		this.fromDate = new Date(other.fromDate.getTime());
		this.toDate = new Date(other.toDate.getTime());
	}

	/**
	 * Get the from date of the interval.
	 * 
	 * @return The from date.
	 */
	public Date getFromDate() {
		return fromDate;
	}
	
	/**
	 * Get the to date of the interval.
	 * 
	 * @return The to date.
	 */	
	public Date getToDate() {
		return toDate;
	}
	
	/**
	 * Crude implementation of hashCode, so intervals could
	 * be stored in HashSets.
	 * 
	 */
	public int hashCode() {
		return fromDate.hashCode() + toDate.hashCode();
	}

	/**
	 * Test if two interval are equivelent.
	 * <p>
	 * Intervals are equivelant if there start and end times are the same.
	 * 
	 * @param other The interval to test against.
	 * @return true if they are equal.
	 */
	public boolean equals(Object other) {
		if (!(other instanceof Interval)) {
			return false;
		}
		return this.toDate.equals(((Interval)other).toDate) 
				&& this.fromDate.equals(((Interval)other).fromDate);
	}
	
	/**
	 * Test if this interval is before the other interval.
	 * <p> 
	 * This happens when this from time is less than other from time.
	 * <pre>
	 * this:    ----    or   ----
	 * other:    ----             ----
	 * </pre>
	 * @param other
	 * @return true if this is before the other.
	 */

	public boolean isBefore(Interval other) {
	    if (other == null) {
	        return true;
	    }
		return this.fromDate.getTime() < other.fromDate.getTime();
	}
	
	/**
	 * Test if this interval is past the other interval.
	 * <p>
	 * This happens when the this from time is greater than the other ones to time.
	 * <pre>
	 * this:         ----
	 * other:   ----
	 * </pre>
	 * @return true if this is past the other.
	 */
	
	public boolean isPast(Interval other) {
	    if (other == null) {
	        return true;
	    }
		return this.fromDate.getTime() > other.toDate.getTime();		
	}
			
	/**
	 * Limit the interval.
	 * 
	 * @param other The other interval. may be null.
	 * @return The new interval.
	 */

	public Interval limit(Interval limit) {
	    if (limit == null) {
	        return this;
	    }
	    if (limit.fromDate.compareTo(this.fromDate) > 0
	       || this.fromDate.compareTo(limit.toDate) > 0) {
	        return null;
	    }
	    return this;
	}

	/**
	 * Return a string representation of this interval.
	 */		
	public String toString() {
		SimpleDateFormat format = new SimpleDateFormat("dd-MMM-yy HH:mm:ss:SSS");
		String toString = format.format(toDate);
		return format.format(fromDate) + " to " + toString;	
	}
} 
