package de.fitsample.timerecording;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A container for hours and minutes.
 * 
 * @author Ralf
 */
public class Time implements Comparable {

	/**
	 * The expression for the Time format.
	 */
	public static final String TIME_REGEX = "([0-1]?[0-9]|2[0-3]):[0-5]?[0-9]";

	private static Pattern pattern = Pattern.compile(TIME_REGEX);

	private int hours;

	private int minutes;

	/**
	 * Creates a Time instances.
	 * 
	 * @param hours    the hours of the Time. If hour < 0, or hour > 23, an
	 *                 IllegalArgumentException is thrown.
	 * @param minutes  the minutes of the Time. If minutes < 0, or minutes > 59, an
	 *                 IllegalArgumentException is thrown.
	 * 
	 * @throws IllegalArgumentException
	 */
	public Time(int hours, int minutes) throws IllegalArgumentException {
		if ((hours < 0) || (hours > 23)) {
			throw new IllegalArgumentException(
					"Parameter 'hours' must be 0 < hours < 23: " + hours);
		}
		if ((minutes < 0) || (minutes > 59)) {
			throw new IllegalArgumentException(
					"Parameter 'minutes' must be 0 < minutes < 59: " + minutes);
		}
		this.hours = hours;
		this.minutes = minutes;
	}

	/**
	 * @return the hours of the Time.
	 */
	public int getHours() {
		return hours;
	}

	/**
	 * @return the minutes of the Time.
	 */
	public int getMinutes() {
		return minutes;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Object other) {
		if (!(other instanceof Time)) {
			return false;
		}
		Time otherTime = (Time) other;
		return (getHours() == otherTime.getHours())
				&& (getMinutes() == otherTime.getMinutes());
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		return getHours() + 13 * getMinutes();
	}

	/**
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(Object other) {
		Time otherTime = (Time) other;
		if (getHours() == otherTime.getHours()) {
			return sign(getMinutes() - otherTime.getMinutes());
		}
		return sign(getHours() - otherTime.getHours());
	}

	private int sign(int value) {
		if (value < 0) {
			return -1;
		}
		if (value > 0) {
			return 1;
		}
		return 0;
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		if (getHours() < 10) {
			buffer.append("0");
		}
		buffer.append(Integer.toString(getHours()));
		buffer.append(":");
		if (getMinutes() < 10) {
			buffer.append("0");
		}
		buffer.append(Integer.toString(getMinutes()));
		return buffer.toString();
	}

	/**
	 * Returns the Time as a double value, where the minutes are the fraction of
	 * the hours. E.g. <code>01:15</code> will result in the double value
	 * <code>1.25</code>.
	 * 
	 * @return the Time as a double value.
	 */
	public double doubleValue() {
		return getHours() + getMinutes() / 60.0;
	}

	/**
	 * Creates a Time from the given text representation.
	 * 
	 * @param text  the text representation of the Time.
	 * 
	 * @return the created Time instance.
	 * 
	 * @throws IllegalArgumentException if parsing the text failed.
	 */
	public static Time valueOf(String text) throws IllegalArgumentException {
		Matcher matcher = pattern.matcher(text);
		if (!matcher.matches()) {
			throw new IllegalArgumentException(
					"Time must be of format hh:mm, but is " + text);
		}
		String[] parts = text.split(":");
		return new Time(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
	}

}
