/*
 * Copyright (c) 2008-2009 OrangeSignal.com All rights reserved.
 * 
 * これは Apache ライセンス Version 2.0 (以下、このライセンスと記述) に
 * 従っています。このライセンスに準拠する場合以外、このファイルを使用
 * してはなりません。このライセンスのコピーは以下から入手できます。
 * 
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 * 
 * 適用可能な法律がある、あるいは文書によって明記されている場合を除き、
 * このライセンスの下で配布されているソフトウェアは、明示的であるか暗黙の
 * うちであるかを問わず、「保証やあらゆる種類の条件を含んでおらず」、
 * 「あるがまま」の状態で提供されるものとします。
 * このライセンスが適用される特定の許諾と制限については、このライセンス
 * を参照してください。
 */

package jp.sf.orangesignal.ta.data;

import java.io.Serializable;
import java.util.Calendar;

/**
 * 任意の初期値で切捨て可能な日時切捨て用クラスを提供します。
 * 
 * @author 杉澤 浩二
 */
public class DateTruncater implements Serializable {

	private static final long serialVersionUID = -8138802794223889395L;

	/**
	 * デフォルトコンストラクタです。
	 */
	public DateTruncater() {}

	/**
	 * 年の初期値を保持します。
	 */
	private int year = 1970;

	/**
	 * 年の初期値を返します。
	 * デフォルトは <code>1970</code> です。
	 * 
	 * @return 年の初期値
	 */
	public int getYear() { return year; }

	/**
	 * 年の初期値を設定します。
	 * 
	 * @param year 年の初期値
	 */
	public void setYear(final int year) { this.year = year; }

	/**
	 * 月の初期値を保持します。
	 */
	private int month = Calendar.JANUARY;

	/**
	 * 月の初期値を返します。
	 * デフォルトは {@link Calendar#JANUARY} です。
	 * 
	 * @return 月の初期値
	 */
	public int getMonth() { return month; }

	/**
	 * 月の初期値を設定します。
	 * 
	 * @param month 月の初期値
	 */
	public void setMonth(final int month) { this.month = month; }

	/**
	 * 日の初期値を保持します。
	 */
	private int date = 1;

	/**
	 * 日の初期値を返します。
	 * デフォルトは <code>1</code> です。
	 * 
	 * @return 日の初期値
	 */
	public int getDate() { return date; }

	/**
	 * 日の初期値を設定します。
	 * 
	 * @param date 日の初期値
	 */
	public void setDate(final int date) { this.date = date; }

	/**
	 * 時の初期値を保持します。
	 */
	private int hour = 0;

	/**
	 * 時の初期値を返します。
	 * デフォルトは <code>0</code> です。
	 * 
	 * @return 時の初期値
	 */
	public int getHour() { return hour; }

	/**
	 * 時の初期値を設定します。
	 * 
	 * @param hour 時の初期値
	 */
	public void setHour(final int hour) { this.hour = hour; }

	/**
	 * 分の初期値を保持します。
	 */
	private int minute = 0;

	/**
	 * 分の初期値を返します。
	 * デフォルトは <code>0</code> です。
	 * 
	 * @return 分の初期値
	 */
	public int getMinute() { return minute; }

	/**
	 * 分の初期値を設定します。
	 * 
	 * @param minute 分の初期値
	 */
	public void setMinute(final int minute) { this.minute = minute; }

	/**
	 * 秒の初期値を保持します。
	 */
	private int second = 0;

	/**
	 * 秒の初期値を返します。
	 * デフォルトは <code>0</code> です。
	 * 
	 * @return 秒の初期値
	 */
	public int getSecond() { return second; }

	/**
	 * 秒の初期値を設定します。
	 * 
	 * @param second 秒の初期値
	 */
	public void setSecond(final int second) { this.second = second; }

	/**
	 * ミリ秒の初期値を保持します。
	 */
	private int millisecond = 0;

	/**
	 * ミリ秒の初期値を返します。
	 * デフォルトは <code>0</code> です。
	 * 
	 * @return ミリ秒の初期値
	 */
	public int getMillisecond() { return millisecond; }

	/**
	 * ミリ秒の初期値を設定します。
	 * 
	 * @param millisecond ミリ秒の初期値
	 */
	public void setMillisecond(final int millisecond) { this.millisecond = millisecond; }

	/**
	 * 曜日の初期値を保持します。
	 * 
	 * @since 2.2
	 */
	private int dayOfWeek = -1;

	/**
	 * 曜日の初期値を返します。
	 * 
	 * @return 曜日の初期値
	 * @since 2.2
	 */
	public int getDayOfWeek() { return dayOfWeek; }

	/**
	 * 曜日の初期値を設定します。
	 * 
	 * @param dayOfWeek 曜日の初期値
	 * @since 2.2
	 */
	public void setDayOfWeek(final int dayOfWeek) { this.dayOfWeek = dayOfWeek; }

	/**
	 * 指定されたカレンダーを指定された精度で切捨てて返します。
	 * 
	 * @param calendar カレンダー
	 * @param unit 切捨て精度
	 * @return 指定された精度で切捨てられたカレンダー
	 */
	public Calendar truncate(final Calendar calendar, final int unit) {
		final Calendar c = (Calendar) calendar.clone();

		if (unit == Calendar.DAY_OF_WEEK) {
			final int first = dayOfWeek != -1 ? dayOfWeek : c.getFirstDayOfWeek();
			final int current = c.get(Calendar.DAY_OF_WEEK);
			c.add(Calendar.DATE, first - current);
			return truncate(c, Calendar.HOUR_OF_DAY);
		}

		switch (unit) {
			case Calendar.ERA:
			case Calendar.YEAR:
				c.set(Calendar.YEAR, year);
			case Calendar.MONTH:
				c.set(Calendar.MONTH, month);
			case Calendar.DATE:	// with Calendar.DAY_OF_MONTH ...
				c.set(Calendar.DATE, date);
			case Calendar.AM_PM:
			case Calendar.HOUR:
			case Calendar.HOUR_OF_DAY:
				c.set(Calendar.HOUR_OF_DAY, hour);
			case Calendar.MINUTE:
				c.set(Calendar.MINUTE, minute);
			case Calendar.SECOND:
				c.set(Calendar.SECOND, second);
			case Calendar.MILLISECOND:
				c.set(Calendar.MILLISECOND, millisecond);
				break;
			default:
		}
		return c;
	}

}
