package org.treesched;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Utility methods to do things with dates and intervals.
 * 
 * @author Rob Gordon
 */

public class DateUtils {

	/**
	 * Private constructor as instantiating this utility class 
	 * is meaningless.
	 */
	private DateUtils() {
	}

	/**
	 * Calculate the start of day date time (i.e. at 00:00) for a given date.
	 * 
	 * @param inDate The date to cacluate start of day from.
	 * @return The Date at the start of the day.
	 */
	public static Date startOfDay(Date inDate) {
		GregorianCalendar c1 = new GregorianCalendar();
		c1.setTime(inDate);
		GregorianCalendar c2 = new GregorianCalendar(
				c1.get(Calendar.YEAR), c1.get(Calendar.MONTH),
				c1.get(Calendar.DATE));
		return c2.getTime();		
	}
		
	/**
	 * Calculate the date time at the end of the day (one millisecond before midnight)
	 * for the given date.
	 * 
	 * @param inDate The given date.
	 * @return The Date at the end of the day.
	 */
	public static Date endOfDay(Date inDate) {
		Calendar inCalendar = new GregorianCalendar();
		inCalendar.setTime(startOfDay(inDate));
		Calendar nextDay = new GregorianCalendar(
		        inCalendar.get(Calendar.YEAR),
		        inCalendar.get(Calendar.MONTH),
		        inCalendar.get(Calendar.DAY_OF_MONTH) + 1);
		return new Date(nextDay.getTime().getTime() - 1);
	}
	
	/**
	 * Calculate the day number for the given date.
	 * 
	 * @param inDate The given date.
	 * @return The day number.
	 */
	public static int dayOfWeek(Date inDate) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(inDate);

		return calendar.get(Calendar.DAY_OF_WEEK);
	}
	
	/**
	 * Calcuate the month number (0 - 11) for the given date.
	 * 
	 * @param inDate The given date.
	 * @return The month number.
	 */	
	public static int month(Date inDate) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(inDate);

		return calendar.get(Calendar.MONTH);
	}
	
	/**
	 * Calculate the day of the month (1 - 31) for the given date.
	 * 
	 * @param inDate The given date.
	 * @return The day of the month.
	 */
	public static int dayOfMonth(Date inDate) {	
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(inDate);

		return calendar.get(Calendar.DAY_OF_MONTH);
	}
	
	/**
	 * Calculate the date at the start of the month for the given date.
	 * 
	 * @param inDate The given date.
	 * @return The date at the start of the month.
	 */
	public static Date startOfMonth(Date inDate) {
		GregorianCalendar c1 = new GregorianCalendar();
		c1.setTime(inDate);
		
		GregorianCalendar c2 = new GregorianCalendar(
				c1.get(Calendar.YEAR), c1.get(Calendar.MONTH), 1);
		return c2.getTime();		
	}

	/**
	 * Calculate the date at the end of the month for the given date.
	 * 
	 * @param inDate The given date.
	 * @return The date at the end of the month.
	 */
	public static Date endOfMonth(Date inDate) {
		GregorianCalendar c1 = new GregorianCalendar();
		c1.setTime(inDate);
		
		// get the date at the beginning of next month
		GregorianCalendar c2 = new GregorianCalendar(
				c1.get(Calendar.YEAR), c1.get(Calendar.MONTH) + 1, 1);

		// and take off a millisecond.
		return oneMillisBefore(c2.getTime());
	}
	
	/**
	 * Calculate the day of the year for the given
	 * date.
	 * 
	 * @param forDate The date.
	 * @return The day of the year.
	 */
	public static int dayOfYear(Date forDate) {
	    Calendar calendar = Calendar.getInstance();
	    calendar.setTime(forDate);
	    return calendar.get(Calendar.DAY_OF_YEAR);
	}
			
	/**
	 * Calculate the date at the start of the year for the given date.
	 * 
	 * @param inDate The given date.
	 * @return The date at the start of the year.
	 */
	public static Date startOfYear(Date inDate) {
		GregorianCalendar c1 = new GregorianCalendar();
		c1.setTime(inDate);
		
		GregorianCalendar c2 = new GregorianCalendar(
				c1.get(Calendar.YEAR), 0, 1);

		return c2.getTime();		
	}

	/**
	 * Calcuate the date at the end of the year from the
	 * given date.
	 * 
	 * @param inDate The given date.
	 * @return The date at the end of the year.
	 */
	public static Date endOfYear(Date inDate) {
		GregorianCalendar c1 = new GregorianCalendar();
		c1.setTime(inDate);
		
		// get the date at the beginning of next month
		GregorianCalendar c2 = new GregorianCalendar(
				c1.get(Calendar.YEAR) + 1, 0, 1);

		// and take off a millisecond.
		return oneMillisBefore(c2.getTime());
	}

	/**
	 * Return a date which is 1 millisecond after the given date.
	 * 
	 * @param date The given date.
	 * @return The date one millisecond later.
	 */	
	public static Date oneMillisAfter(Date date) {
		return new Date(date.getTime() + 1);
	}
	
	/**
	 * Return a date which is 1 millisecond before the given date.
	 * 
	 * @param date The given date.
	 * @return The date one millisecond before.
	 */	
	public static Date oneMillisBefore(Date date) {
		return new Date(date.getTime() - 1);
	}

}

