import java.lang.Math;
import java.lang.Comparable;

/**
 * This class represents a item as a portion of a video.
 * A item is defined by its start and stop time and source (or video), 
 * and also by its sequence number which is
 * its order in a bunch of results (this number should be external to this class but 
 * for convenience it's within the class).
 *
 * @author NIST-ITL-IAD-Retrieval Group
 * This software was produced by NIST, an agency of the
 * U.S. government, and by statute is not subject to copyright in the
 * United States. Recipients of this software assume all
 * responsibilities associated with its operation, modification and
 * maintenance.
 *
 */
public abstract class Item {

    /**
     * The start time of the item.
     * Time format is "*h*m*s*ms".
     */
    protected String start = "";
    /**
     * The stop time of the item.
     * Time format is "*h*m*s*ms".
     *
     */
	protected String stop = "";
    /**
     * The source of the item (or video).
     *
     */
	protected String src = "";    
    /**
     * Indicates if it matched with another item during a comparison.
     *
     */
	protected int matched = 0;
    /**
     * Constructs Item object with the given parameters.
     *
     * @param     start The start time of the item in a defined format ("*h*m*s*ms").
     * @param     stop The stop time of the item in a defined format ("*h*m*s*ms").
     * @param     src The source of the item or video that the item is part of.
     * @param     seqNum The sequence number of the item.
     * @exception TransitionDefinitionException Thrown if the pre frame is not strictly less than the post frame.
     */
	public Item(String start, String stop, String src)throws Exception{
		if(toMilliseconds(start) <= toMilliseconds(stop)){
			this.start = start;
			this.stop = stop;
			this.src = src;
		}
		else throw new Exception("Item definition error: start="+start+" - stop="+stop);
	}
	/**
     * Gets the start time in the defined format ("*h*m*s*ms").
     *
     */
	public String getStart(){
    	return start;
    }
    /**
     * Gets the start time in milliseconds as a double.
     *
     */
    public double getMilliStart(){
    	return toMilliseconds(start);
    }
	/**
     * Gets the stop time in the defined format ("*h*m*s*ms").
     *
     */
	public String getStop(){
    	return stop;
    }
    /**
     * Gets the stop time in milliseconds as a double.
     *
     */
    public double getMilliStop(){
    	return toMilliseconds(stop);
    }
    /**
     * Gets the video source of the item.
     *
     */
   	public String getSrc(){
   		return src;
   	}   	
	/**
     * Gets the sequence number of the item as an integer.
     *
     */
	public double length(){
		return (toMilliseconds(stop) - toMilliseconds(start));		
	}
	/**
     * Returns true if there is an intersection with the given item.
     *
     */
	public boolean intersected(Item t){
			return (this.src.equals(t.getSrc()) && 
				maxTimeMilli(this.start, t.getStart()) < minTimeMilli(this.stop, t.getStop()));
	}	
	/**
     * Returns the greater time of two given times in the "*h*m*s*ms" format.
     *
     */
	public String maxTime(String time1, String time2) throws NumberFormatException{
	
		double temp1 = toMilliseconds(time1);
		if(Math.max(temp1, toMilliseconds(time2)) == temp1)
			return time1;
		else
			return time2;
	}
	/**
     * Returns the smaller time of two given times in the "*h*m*s*ms" format.
     *
     */
	public String minTime(String time1, String time2) throws NumberFormatException{
	
		double temp1 = toMilliseconds(time1);
		if(Math.max(temp1, toMilliseconds(time2)) == temp1)
			return time2;
		else
			return time1;
	}
	/**
     * Returns a double (milliseconds) of the greater time of two given times in the "*h*m*s*ms" format.
     *
     */
	public double maxTimeMilli(String time1, String time2) throws NumberFormatException{
	
		double temp1 = toMilliseconds(time1);
		double temp2 = toMilliseconds(time2);
		if(Math.max(temp1, temp2) == temp1)
			return temp1;
		else
			return temp2;
	}
	/**
     * Returns a double (milliseconds) of the smaller time of two given times in the "*h*m*s*ms" format.
     *
     */
	public double minTimeMilli(String time1, String time2) throws NumberFormatException{
	
		double temp1 = toMilliseconds(time1);
		double temp2 = toMilliseconds(time2);
		if(Math.min(temp1, temp2) == temp1)
			return temp1;
		else
			return temp2;
	}
	/**
     * Returns a double that represents the given time in milliseconds.
     *
     */
	public double toMilliseconds(String time) throws NumberFormatException{
	
		return (extractHours(time)+ extractMinutes(time) + extractSeconds(time) + extractMilliSeconds(time));
	}
	/**
     * Returns the hours in milliseconds of given time in the "*h*m*s*ms" format.
     *
     */
   	static private double extractHours(String time){
		
		double hours = 0;
		try{
			int h = -1;
			if((h = time.indexOf("h")) != -1)
				hours = Double.parseDouble(time.substring(0, h));
		} catch (NumberFormatException ex){
			return 0;
		}		
		return (hours*60*60*1000);				
	}
	/**
     * Returns the minutes in milliseconds of given time in the "*h*m*s*ms" format.
     *
     */
	static private double extractMinutes(String time){
		
		double minutes = 0;
		try{
			int h = -1;
			int m = -1;
			if(time.indexOf("m") != -1)
				if(time.indexOf("ms") != time.indexOf("m")){
					m = time.indexOf("m");
					h = time.indexOf("h");
					minutes = Double.parseDouble(time.substring(h+1, m));
				}
		} catch (NumberFormatException ex){
			return 0;
		}		
		return (minutes*60*1000);
	}
    /**
     * Returns the seconds in milliseconds of given time in the "*h*m*s*ms" format.
     *
     */
	static private double extractSeconds(String time){

		double seconds = 0;
		try{
			if(time.indexOf("s") != -1)
				if(time.indexOf("ms") != time.indexOf("s")-1){
					int s = time.indexOf("s");
					int m = time.indexOf("ms") != time.indexOf("m") ? time.indexOf("m") : -1;
					int h = time.indexOf("h");
					if(m > h)
						seconds = Double.parseDouble(time.substring(m+1, s));
					else
						seconds = Double.parseDouble(time.substring(h+1, s));
				}
		} catch (NumberFormatException ex){
			return 0;
		}
		return (seconds*1000);
	}
	/**
     * Returns the milliseconds of given time in the "*h*m*s*ms" format.
     *
     */
	static private double extractMilliSeconds(String time){
		
		double milliseconds = 0;
		try{
			if(time.indexOf("ms") != -1){
				int ms = time.indexOf("ms");
				int s = ms != time.indexOf("s")-1 ? time.indexOf("s") : -1;
				int m = ms != time.indexOf("m") ? time.indexOf("m") : -1;
				int h = time.indexOf("h");					
				
				int max = Math.max(h,m);
				max = Math.max(max,s);
				
				milliseconds = Double.parseDouble(time.substring(max+1, ms));
			}
		} catch (NumberFormatException ex){
			return 0;
		}		
		return milliseconds;
	}
	/**
     * Returns a Xml formatted string representation of this item and its start and stop values. 
     * For example: "<knownItem src="aVideoName" start="1h10m10s" stop="1h10m25s" />"
     * 
     */
	public abstract String toString();
}
