/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 *
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.core.lang.time;

import org.junit.Test;
import org.junit.Before;
import static org.junit.Assert.*;
import java.util.Calendar;
import java.util.Date;

public class DateUtilsFragmentTest {

	private static final int months = 7; // second final prime before 12
	private static final int days = 23; // second final prime before 31 (and valid)
	private static final int hours = 19; // second final prime before 24
	private static final int minutes = 53; // second final prime before 60
	private static final int seconds = 47; // third final prime before 60
	private static final int millis = 991; // second final prime before 1000

	private Date aDate;
	private Calendar aCalendar;

	@Before
	public void setUp() {
		aCalendar = Calendar.getInstance();
		aCalendar.set(2005, months, days, hours, minutes, seconds);
		aCalendar.set(Calendar.MILLISECOND, millis);
		aDate = aCalendar.getTime();
	}

	@Test
	public void testNullDate() {
		try {
			DateUtils.getFragmentInMilliseconds((Date)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInSeconds((Date)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInMinutes((Date)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInHours((Date)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInDays((Date)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}
	}

	@Test
	public void testNullCalendar() {
		try {
			DateUtils.getFragmentInMilliseconds((Calendar)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInSeconds((Calendar)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInMinutes((Calendar)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInHours((Calendar)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInDays((Calendar)null, Calendar.MILLISECOND);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}
	}

	@Test
	public void testInvalidFragmentWithDate() {
		try {
			DateUtils.getFragmentInMilliseconds(aDate, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInSeconds(aDate, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInMinutes(aDate, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInHours(aDate, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInDays(aDate, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}
	}

	@Test
	public void testInvalidFragmentWithCalendar() {
		try {
			DateUtils.getFragmentInMilliseconds(aCalendar, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInSeconds(aCalendar, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInMinutes(aCalendar, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInHours(aCalendar, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}

		try {
			DateUtils.getFragmentInDays(aCalendar, 0);
			fail();
		}
		catch (final IllegalArgumentException iae) {
		}
	}

	@Test
	public void testMillisecondFragmentInLargerUnitWithDate() {
		assertEquals(0, DateUtils.getFragmentInMilliseconds(aDate, Calendar.MILLISECOND));
		assertEquals(0, DateUtils.getFragmentInSeconds(aDate, Calendar.MILLISECOND));
		assertEquals(0, DateUtils.getFragmentInMinutes(aDate, Calendar.MILLISECOND));
		assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.MILLISECOND));
		assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.MILLISECOND));
	}

	@Test
	public void testMillisecondFragmentInLargerUnitWithCalendar() {
		assertEquals(0, DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.MILLISECOND));
		assertEquals(0, DateUtils.getFragmentInSeconds(aCalendar, Calendar.MILLISECOND));
		assertEquals(0, DateUtils.getFragmentInMinutes(aCalendar, Calendar.MILLISECOND));
		assertEquals(0, DateUtils.getFragmentInHours(aCalendar, Calendar.MILLISECOND));
		assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.MILLISECOND));
	}

	@Test
	public void testSecondFragmentInLargerUnitWithDate() {
		assertEquals(0, DateUtils.getFragmentInSeconds(aDate, Calendar.SECOND));
		assertEquals(0, DateUtils.getFragmentInMinutes(aDate, Calendar.SECOND));
		assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.SECOND));
		assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.SECOND));
	}

	@Test
	public void testSecondFragmentInLargerUnitWithCalendar() {
		assertEquals(0, DateUtils.getFragmentInSeconds(aCalendar, Calendar.SECOND));
		assertEquals(0, DateUtils.getFragmentInMinutes(aCalendar, Calendar.SECOND));
		assertEquals(0, DateUtils.getFragmentInHours(aCalendar, Calendar.SECOND));
		assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.SECOND));
	}

	@Test
	public void testMinuteFragmentInLargerUnitWithDate() {
		assertEquals(0, DateUtils.getFragmentInMinutes(aDate, Calendar.MINUTE));
		assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.MINUTE));
		assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.MINUTE));
	}

	@Test
	public void testMinuteFragmentInLargerUnitWithCalendar() {
		assertEquals(0, DateUtils.getFragmentInMinutes(aCalendar, Calendar.MINUTE));
		assertEquals(0, DateUtils.getFragmentInHours(aCalendar, Calendar.MINUTE));
		assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.MINUTE));
	}

	@Test
	public void testHourOfDayFragmentInLargerUnitWithDate() {
		assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.HOUR_OF_DAY));
		assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.HOUR_OF_DAY));
	}

	@Test
	public void testHourOfDayFragmentInLargerUnitWithCalendar() {
		assertEquals(0, DateUtils.getFragmentInHours(aCalendar, Calendar.HOUR_OF_DAY));
		assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.HOUR_OF_DAY));
	}

	@Test
	public void testDayOfYearFragmentInLargerUnitWithDate() {
		assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.DAY_OF_YEAR));
	}

	@Test
	public void testDayOfYearFragmentInLargerUnitWithCalendar() {
		assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.DAY_OF_YEAR));
	}

	@Test
	public void testDateFragmentInLargerUnitWithDate() {
		assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.DATE));
	}

	@Test
	public void testDateFragmentInLargerUnitWithCalendar() {
		assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.DATE));
	}

	// Calendar.SECOND as useful fragment

	@Test
	public void testMillisecondsOfSecondWithDate() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.SECOND);
		assertEquals(millis, testResult);
	}

	@Test
	public void testMillisecondsOfSecondWithCalendar() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.SECOND);
		assertEquals(millis, testResult);
		assertEquals(aCalendar.get(Calendar.MILLISECOND), testResult);
	}

	// Calendar.MINUTE as useful fragment

	@Test
	public void testMillisecondsOfMinuteWithDate() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.MINUTE);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND), testResult);
	}

	@Test
	public void testMillisecondsOfMinuteWithCalender() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.MINUTE);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND), testResult);
	}

	@Test
	public void testSecondsofMinuteWithDate() {
		final long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.MINUTE);
		assertEquals(seconds, testResult);
	}

	@Test
	public void testSecondsofMinuteWithCalendar() {
		final long testResult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.MINUTE);
		assertEquals(seconds, testResult);
		assertEquals(aCalendar.get(Calendar.SECOND), testResult);
	}

	// Calendar.HOUR_OF_DAY as useful fragment

	@Test
	public void testMillisecondsOfHourWithDate() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.HOUR_OF_DAY);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE),
			testResult);
	}

	@Test
	public void testMillisecondsOfHourWithCalendar() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.HOUR_OF_DAY);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE),
			testResult);
	}

	@Test
	public void testSecondsofHourWithDate() {
		final long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.HOUR_OF_DAY);
		assertEquals(seconds + (minutes * DateUtils.MILLIS_PER_MINUTE / DateUtils.MILLIS_PER_SECOND), testResult);
	}

	@Test
	public void testSecondsofHourWithCalendar() {
		final long testResult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.HOUR_OF_DAY);
		assertEquals(seconds + (minutes * DateUtils.MILLIS_PER_MINUTE / DateUtils.MILLIS_PER_SECOND), testResult);
	}

	@Test
	public void testMinutesOfHourWithDate() {
		final long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.HOUR_OF_DAY);
		assertEquals(minutes, testResult);
	}

	@Test
	public void testMinutesOfHourWithCalendar() {
		final long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.HOUR_OF_DAY);
		assertEquals(minutes, testResult);
	}

	// Calendar.DATE and Calendar.DAY_OF_YEAR as useful fragment
	@Test
	public void testMillisecondsOfDayWithDate() {
		long testresult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.DATE);
		final long expectedValue = millis + (seconds * DateUtils.MILLIS_PER_SECOND)
				+ (minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR);
		assertEquals(expectedValue, testresult);
		testresult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testresult);
	}

	@Test
	public void testMillisecondsOfDayWithCalendar() {
		long testresult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.DATE);
		final long expectedValue = millis + (seconds * DateUtils.MILLIS_PER_SECOND)
				+ (minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR);
		assertEquals(expectedValue, testresult);
		testresult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testresult);
	}

	@Test
	public void testSecondsOfDayWithDate() {
		long testresult = DateUtils.getFragmentInSeconds(aDate, Calendar.DATE);
		final long expectedValue = seconds
				+ ((minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR))
				/ DateUtils.MILLIS_PER_SECOND;
		assertEquals(expectedValue, testresult);
		testresult = DateUtils.getFragmentInSeconds(aDate, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testresult);
	}

	@Test
	public void testSecondsOfDayWithCalendar() {
		long testresult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.DATE);
		final long expectedValue = seconds
				+ ((minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR))
				/ DateUtils.MILLIS_PER_SECOND;
		assertEquals(expectedValue, testresult);
		testresult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testresult);
	}

	@Test
	public void testMinutesOfDayWithDate() {
		long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.DATE);
		final long expectedValue = minutes + ((hours * DateUtils.MILLIS_PER_HOUR)) / DateUtils.MILLIS_PER_MINUTE;
		assertEquals(expectedValue, testResult);
		testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testResult);
	}

	@Test
	public void testMinutesOfDayWithCalendar() {
		long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.DATE);
		final long expectedValue = minutes + ((hours * DateUtils.MILLIS_PER_HOUR)) / DateUtils.MILLIS_PER_MINUTE;
		assertEquals(expectedValue, testResult);
		testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testResult);
	}

	@Test
	public void testHoursOfDayWithDate() {
		long testResult = DateUtils.getFragmentInHours(aDate, Calendar.DATE);
		final long expectedValue = hours;
		assertEquals(expectedValue, testResult);
		testResult = DateUtils.getFragmentInHours(aDate, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testResult);
	}

	@Test
	public void testHoursOfDayWithCalendar() {
		long testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.DATE);
		final long expectedValue = hours;
		assertEquals(expectedValue, testResult);
		testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testResult);
	}

	// Calendar.MONTH as useful fragment
	@Test
	public void testMillisecondsOfMonthWithDate() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.MONTH);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE)
				+ (hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY), testResult);
	}

	@Test
	public void testMillisecondsOfMonthWithCalendar() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.MONTH);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE)
				+ (hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY), testResult);
	}

	@Test
	public void testSecondsOfMonthWithDate() {
		final long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.MONTH);
		assertEquals(
			seconds
					+ ((minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY))
					/ DateUtils.MILLIS_PER_SECOND, testResult);
	}

	@Test
	public void testSecondsOfMonthWithCalendar() {
		final long testResult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.MONTH);
		assertEquals(
			seconds
					+ ((minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY))
					/ DateUtils.MILLIS_PER_SECOND, testResult);
	}

	@Test
	public void testMinutesOfMonthWithDate() {
		final long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.MONTH);
		assertEquals(minutes + ((hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY))
				/ DateUtils.MILLIS_PER_MINUTE, testResult);
	}

	@Test
	public void testMinutesOfMonthWithCalendar() {
		final long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.MONTH);
		assertEquals(minutes + ((hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY))
				/ DateUtils.MILLIS_PER_MINUTE, testResult);
	}

	@Test
	public void testHoursOfMonthWithDate() {
		final long testResult = DateUtils.getFragmentInHours(aDate, Calendar.MONTH);
		assertEquals(hours + ((days * DateUtils.MILLIS_PER_DAY)) / DateUtils.MILLIS_PER_HOUR, testResult);
	}

	@Test
	public void testHoursOfMonthWithCalendar() {
		final long testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.MONTH);
		assertEquals(hours + ((days * DateUtils.MILLIS_PER_DAY)) / DateUtils.MILLIS_PER_HOUR, testResult);
	}

	// Calendar.YEAR as useful fragment
	@Test
	public void testMillisecondsOfYearWithDate() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.YEAR);
		final Calendar cal = Calendar.getInstance();
		cal.setTime(aDate);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE)
				+ (hours * DateUtils.MILLIS_PER_HOUR) + (cal.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY),
			testResult);
	}

	@Test
	public void testMillisecondsOfYearWithCalendar() {
		final long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.YEAR);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE)
				+ (hours * DateUtils.MILLIS_PER_HOUR)
				+ (aCalendar.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY), testResult);
	}

	@Test
	public void testSecondsOfYearWithDate() {
		final long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.YEAR);
		final Calendar cal = Calendar.getInstance();
		cal.setTime(aDate);
		assertEquals(
			seconds
					+ ((minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR) + (cal.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
					/ DateUtils.MILLIS_PER_SECOND, testResult);
	}

	@Test
	public void testSecondsOfYearWithCalendar() {
		final long testResult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.YEAR);
		assertEquals(
			seconds
					+ ((minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR) + (aCalendar.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
					/ DateUtils.MILLIS_PER_SECOND, testResult);
	}

	@Test
	public void testMinutesOfYearWithDate() {
		final long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.YEAR);
		final Calendar cal = Calendar.getInstance();
		cal.setTime(aDate);
		assertEquals(minutes
				+ ((hours * DateUtils.MILLIS_PER_HOUR) + (cal.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
				/ DateUtils.MILLIS_PER_MINUTE, testResult);
	}

	@Test
	public void testMinutesOfYearWithCalendar() {
		final long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.YEAR);
		assertEquals(
			minutes
					+ ((hours * DateUtils.MILLIS_PER_HOUR) + (aCalendar.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
					/ DateUtils.MILLIS_PER_MINUTE, testResult);
	}

	@Test
	public void testHoursOfYearWithDate() {
		final long testResult = DateUtils.getFragmentInHours(aDate, Calendar.YEAR);
		final Calendar cal = Calendar.getInstance();
		cal.setTime(aDate);
		assertEquals(hours + ((cal.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY)) / DateUtils.MILLIS_PER_HOUR,
			testResult);
	}

	@Test
	public void testHoursOfYearWithCalendar() {
		final long testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.YEAR);
		assertEquals(hours + ((aCalendar.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
				/ DateUtils.MILLIS_PER_HOUR, testResult);
	}
}
