/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.lang.time;

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

import junit.framework.TestCase;
import junit.framework.Test;
import junit.framework.TestSuite;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;

public class DateUtilsFragmentTest extends TestCase {

    public static Test suite() {
        TestSuite suite = new TestSuite(DateUtilsFragmentTest.class);
        suite.setName("DateUtils Fragment Tests");
        return suite;
    }

	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;

	protected void setUp() {
		aCalendar = Calendar.getInstance();
		aCalendar.set(2005, months, days, hours, minutes, seconds);
		aCalendar.set(Calendar.MILLISECOND, millis);
		aDate = aCalendar.getTime();
	}
	
	public void testNullDate() {
		try {
			DateUtils.getFragmentInMilliseconds((Date) null, Calendar.MILLISECOND);
			fail();
		} catch(IllegalArgumentException iae) {}

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

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

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

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

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

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

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

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

		try {
			DateUtils.getFragmentInDays((Calendar) null, Calendar.MILLISECOND);
			fail();
		} catch(IllegalArgumentException iae) {}
	}
	
	public void testInvalidFragmentWithDate() {
		try {
			DateUtils.getFragmentInMilliseconds(aDate, 0);
			fail();
		} catch(IllegalArgumentException iae) {}

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

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

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

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

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

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

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

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

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

	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));
	}

	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));
	}
	
	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));
	}

	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));
	}
	
	public void testMinuteFragmentInLargerUnitWithDate() {
		assertEquals(0, DateUtils.getFragmentInMinutes(aDate, Calendar.MINUTE));
		assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.MINUTE));
		assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.MINUTE));
	}

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

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

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

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

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

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

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

	//Calendar.SECOND as useful fragment
	
	public void testMillisecondsOfSecondWithDate() {
		long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.SECOND);
		assertEquals(millis, testResult);
	}

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

	//Calendar.MINUTE as useful fragment

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

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

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

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

	//Calendar.HOUR_OF_DAY as useful fragment
	
	public void testMillisecondsOfHourWithDate() {
		long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.HOUR_OF_DAY);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE), testResult);
	}
	
	public void testMillisecondsOfHourWithCalendar() {
		long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.HOUR_OF_DAY);
		assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE), testResult);
	}

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

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

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

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

	//Calendar.DATE and Calendar.DAY_OF_YEAR as useful fragment
	public void testMillisecondsOfDayWithDate() {
		long testresult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.DATE);
		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);
	}
	
	public void testMillisecondsOfDayWithCalendar() {
		long testresult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.DATE);
		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);
	}

	public void testSecondsOfDayWithDate() {
		long testresult = DateUtils.getFragmentInSeconds(aDate, Calendar.DATE);
		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);
	}

	public void testSecondsOfDayWithCalendar() {
		long testresult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.DATE);
		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);
	}

	public void testMinutesOfDayWithDate() {
		long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.DATE);
		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);
	}

	public void testMinutesOfDayWithCalendar() {
		long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.DATE);
		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);
	}
	
	public void testHoursOfDayWithDate() {
		long testResult = DateUtils.getFragmentInHours(aDate, Calendar.DATE);
		long expectedValue = hours; 
		assertEquals(expectedValue,testResult);
		testResult = DateUtils.getFragmentInHours(aDate, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue,testResult);
	}

	public void testHoursOfDayWithCalendar() {
		long testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.DATE);
		long expectedValue = hours; 
		assertEquals(expectedValue, testResult);
		testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.DAY_OF_YEAR);
		assertEquals(expectedValue, testResult);
	}
	
	
	//Calendar.MONTH as useful fragment
	public void testMillisecondsOfMonthWithDate() {
		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);
	}

	public void testMillisecondsOfMonthWithCalendar() {
		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);
	}
	
	public void testSecondsOfMonthWithDate() {
		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);
	}

	public void testSecondsOfMonthWithCalendar() {
		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);
	}

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

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

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

	public void testHoursOfMonthWithCalendar() {
		long testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.MONTH);
		assertEquals( hours +((days * DateUtils.MILLIS_PER_DAY))
						/ DateUtils.MILLIS_PER_HOUR,
				testResult);
	}
	
	//Calendar.YEAR as useful fragment
	public void testMillisecondsOfYearWithDate() {
		long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.YEAR);
		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);
	}

	public void testMillisecondsOfYearWithCalendar() {
		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);
	}
	
	public void testSecondsOfYearWithDate() {
		long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.YEAR);
		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);
	}

	public void testSecondsOfYearWithCalendar() {
		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);
	}

	public void testMinutesOfYearWithDate() {
		long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.YEAR);
		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);
	}

	public void testMinutesOfYearWithCalendar() {
		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);
	}

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

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