/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.common.infra;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import junit.framework.TestCase;

/**
 * @author Martin Francisco
 */
public class ImpreciseDateTests
    extends TestCase
{
    private static final Object[] SAMPLE_DATES = new Object[] { "200502", new Date(), "2005",
        "10/01/2004", "10/1/2004", "3/1/2004", "3/11/2004", "20050201", "20050000", "20050700",
        "10/01/2004 17:35", "200502011735", "200502010000", "20050201"};

    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyyMMddHHmmssSSS");
    private static final SimpleDateFormat FORMAT_TIMEZONE = new SimpleDateFormat("yyyyMMddHHmmssSSSZ");

    public ImpreciseDateTests()
    {
        super();
    }

    public ImpreciseDateTests(String name)
    {
        super(name);
    }

    private Calendar createCalender(
        boolean year,
        boolean month,
        boolean day,
        boolean hour,
        boolean minute,
        boolean second,
        boolean millisecond,
        boolean timeZone)
    {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();

        if(year)
        {
            calendar.set(Calendar.YEAR, 1999);
        }

        if(month)
        {
            calendar.set(Calendar.MONTH, Calendar.APRIL);
        }

        if(day)
        {
            calendar.set(Calendar.DAY_OF_MONTH, 1);
        }

        if(hour)
        {
            calendar.set(Calendar.HOUR_OF_DAY, 15);
        }

        if(minute)
        {
            calendar.set(Calendar.MINUTE, 32);
        }

        if(second)
        {
            calendar.set(Calendar.SECOND, 25);
        }

        if(millisecond)
        {
            calendar.set(Calendar.MILLISECOND, 163);
        }

        if(timeZone)
        {
            calendar.setTimeZone(TimeZone.getTimeZone("GMT-0100"));
        }

        return calendar;
    }

    /** Uses ESR ImpreciseDate class */
    public void testStringInputForESR() throws Exception {
        gov.va.med.esr.common.infra.ImpreciseDate date = null;
        Object item = null;
        for (int i = 0; i < SAMPLE_DATES.length; i++) {
            item = SAMPLE_DATES[i];
            System.out.println("**** item: " + item);
            date = (item instanceof String) ? new gov.va.med.esr.common.infra.ImpreciseDate(
                    (String) item)
                    : new gov.va.med.esr.common.infra.ImpreciseDate((Date) item);
            logImpreciseDateForESR(date);
        }
    }

    /** Uses Person Services ImpreciseDate class */
    public void testStringInputForPS() throws Exception {
        Object date = null;
        Object item = null;
        for (int i = 0; i < SAMPLE_DATES.length; i++) {
            item = SAMPLE_DATES[i];
            System.out.println("**** item: " + item);
            try {
                date = (item instanceof String) ? (Object) new gov.va.med.term.access.types.ImpreciseDate((String) item)
                        : item.getClass().getName() + " not supported for construction";
                System.out
                        .println("**** gov.va.med.term.access.types.ImpreciseDate: "
                                + date);
            } catch(Exception e) {
                System.out.println("Unable to parse: [" + item + "] got exception message: " + e.getMessage());
            }
        }
    }

    private void logImpreciseDateForESR(
            gov.va.med.esr.common.infra.ImpreciseDate dt) {
        System.out.println("dt (" + (dt.isImprecise() ? "Imprecise" : "Precise") + ")");
        System.out.println("dt.getYear(): " + dt.getYear());
        System.out.println("dt.toString(): " + dt.toString());
        System.out.println("dt.getDate(): " + dt.getDate());
        System.out.println("dt.getString(): " + dt.getString());
        System.out.println("dt.toStandardFormat(): " + dt.toStandardFormat());
        System.out.println("dt.isTimePresent(): " + dt.isTimePresent());
        if (dt.isImprecise() && dt.getString() == null)
            fail("An ImpreciseDate that is imprecise needs a String value");
    }

    public void testDateConstructor_Null() throws Exception
    {
        try
        {
            new ImpreciseDate((Date)null);
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testCalendarConstructor_Null() throws Exception
    {
        try
        {
            new ImpreciseDate((Calendar)null);
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testImpreciseDateConstructor_Null() throws Exception
    {
        try
        {
            new ImpreciseDate((ImpreciseDate)null);
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testDateConstructor() throws Exception
    {
        Date preciseDate = ImpreciseDateTests.FORMAT_TIMEZONE.parse("19990401153225163-0500");
        ImpreciseDate impreciseDate = new ImpreciseDate(preciseDate);

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(preciseDate, impreciseDate.getDate());
        //super.assertEquals("19990401153225163-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_Year_Invalid() throws Exception
    {
        try
        {
            new ImpreciseDate(this.createCalender(false, false, false, false, false, false, false, false));
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testCalendarConstructor_Year() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, false, false, false, false, false, false, false));

        super.assertEquals(true, impreciseDate.isImprecise());
        super.assertEquals(false, impreciseDate.isPrecise());
        super.assertEquals(false, impreciseDate.isDayPrecise());
        super.assertEquals(false, impreciseDate.isMonthPrecise());
        super.assertEquals(false, impreciseDate.isTimePresent());
        super.assertEquals(null, impreciseDate.getDate());
        super.assertEquals("1999", impreciseDate.getString());
    }

    public void testCalendarConstructor_Year_TimeZone() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, false, false, false, false, false, false, true));

        super.assertEquals(true, impreciseDate.isImprecise());
        super.assertEquals(false, impreciseDate.isPrecise());
        super.assertEquals(false, impreciseDate.isDayPrecise());
        super.assertEquals(false, impreciseDate.isMonthPrecise());
        super.assertEquals(false, impreciseDate.isTimePresent());
        super.assertEquals(null, impreciseDate.getDate());
        super.assertEquals("1999", impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonth_Invalid() throws Exception
    {
        try
        {
            new ImpreciseDate(this.createCalender(false, true, false, false, false, false, false, false));
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testCalendarConstructor_YearMonth() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, false, false, false, false, false, false));

        super.assertEquals(true, impreciseDate.isImprecise());
        super.assertEquals(false, impreciseDate.isPrecise());
        super.assertEquals(false, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(false, impreciseDate.isTimePresent());
        super.assertEquals(null, impreciseDate.getDate());
        super.assertEquals("199904", impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonth_TimeZone() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, false, false, false, false, false, true));

        super.assertEquals(true, impreciseDate.isImprecise());
        super.assertEquals(false, impreciseDate.isPrecise());
        super.assertEquals(false, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(false, impreciseDate.isTimePresent());
        super.assertEquals(null, impreciseDate.getDate());
        super.assertEquals("199904", impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDay_Invalid1()
        throws Exception
    {
        try
        {
            new ImpreciseDate(this.createCalender(false, true, true, false, false, false, false, false));
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testCalendarConstructor_YearMonthDay_Invalid2()
        throws Exception
    {
        try
        {
            new ImpreciseDate(this.createCalender(false, false, true, false, false, false, false, false));
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testCalendarConstructor_YearMonthDay() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, false, false, false, false, false));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(false, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT.parse("19990401000000000"), impreciseDate.getDate());
        //super.assertEquals("19990401000000000-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDay_TimeZone()
        throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, false, false, false, false, true));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(false, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT_TIMEZONE.parse("19990401000000000-0100"), impreciseDate.getDate());
        //super.assertEquals("19990331200000000-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDayHour() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, true, false, false, false, false));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT.parse("19990401150000000"), impreciseDate.getDate());
        //super.assertEquals("19990401150000000-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDayHour_TimeZone()
        throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, true, false, false, false, true));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT_TIMEZONE.parse("19990401150000000-0100"), impreciseDate.getDate());
        //super.assertEquals("19990401110000000-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDayHourMinute()
        throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, true, true, false, false, false));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT.parse("19990401153200000"), impreciseDate.getDate());
        //super.assertEquals("19990401153200000-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDayHourMinute_TimeZone()
        throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, true, true, false, false, true));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT_TIMEZONE.parse("19990401153200000-0100"), impreciseDate.getDate());
        //super.assertEquals("19990401113200000-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDayHourMinuteSecond()
        throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, true, true, true, false, false));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT.parse("19990401153225000"), impreciseDate.getDate());
        //super.assertEquals("19990401153225000-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDayHourMinuteSecond_TimeZone()
        throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, true, true, true, false, true));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT_TIMEZONE.parse("19990401153225000-0100"), impreciseDate.getDate());
        //super.assertEquals("19990401113225000-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDayHourMinuteSecondPlus()
        throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, true, true, true, true, false));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT.parse("19990401153225163"), impreciseDate.getDate());
        //super.assertEquals("19990401153225163-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_YearMonthDayHourMinuteSecondPlus_TimeZone()
        throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, true, true, true, true, true));

        super.assertEquals(false, impreciseDate.isImprecise());
        super.assertEquals(true, impreciseDate.isPrecise());
        super.assertEquals(true, impreciseDate.isDayPrecise());
        super.assertEquals(true, impreciseDate.isMonthPrecise());
        super.assertEquals(true, impreciseDate.isTimePresent());
        super.assertEquals(ImpreciseDateTests.FORMAT_TIMEZONE.parse("19990401153225163-0100"), impreciseDate.getDate());
        //super.assertEquals("19990401113225163-0500", impreciseDate.getString());
        super.assertEquals(null, impreciseDate.getString());
    }

    public void testCalendarConstructor_InvalidMonth()
        throws Exception
    {
        Calendar calendar = this.createCalender(true, true, true, true, true, true, true, true);
        calendar.set(Calendar.MONTH, 23);

        try
        {
            new ImpreciseDate(calendar);
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testCalendarConstructor_InvalidDay()
        throws Exception
    {
        Calendar calendar = this.createCalender(true, true, true, true, true, true, true, true);
        calendar.set(Calendar.DAY_OF_MONTH, 45);

        try
        {
            new ImpreciseDate(calendar);
            super.fail("expected IllegalArgumentException");
        }
        catch(IllegalArgumentException e)
        {
        }
    }

    public void testImpreciseDateConstructor() throws Exception
    {
        Date preciseDate = ImpreciseDateTests.FORMAT_TIMEZONE.parse("19990401153225163-0500");
        ImpreciseDate impreciseDate = new ImpreciseDate(preciseDate);

        super.assertEquals(impreciseDate, new ImpreciseDate(impreciseDate));
    }

    public void testUtils_GetWithDefault_Precise() throws Exception
    {
        Date preciseDate = ImpreciseDateTests.FORMAT_TIMEZONE.parse("19990401153225163-0500");
        ImpreciseDate impreciseDate = new ImpreciseDate(preciseDate);
        Date result = ImpreciseDateUtils.getDateWithDefault(impreciseDate);

        super.assertEquals(preciseDate, result);
    }

    public void testUtils_GetWithDefault_Year() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, false, false, false, false, false, false, false));
        Date result = ImpreciseDateUtils.getDateWithDefault(impreciseDate);

        super.assertEquals(ImpreciseDateTests.FORMAT.parse("19990615000000000"), result);
    }

    public void testUtils_GetWithDefault_YearMonth() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, false, false, false, false, false, false));
        Date result = ImpreciseDateUtils.getDateWithDefault(impreciseDate);

        super.assertEquals(ImpreciseDateTests.FORMAT.parse("19990415000000000"), result);
    }

    public void testUtils_GetWithDefault_YearMonthDay() throws Exception
    {
        ImpreciseDate impreciseDate = new ImpreciseDate(this.createCalender(true, true, true, false, false, false, false, false));
        Date result = ImpreciseDateUtils.getDateWithDefault(impreciseDate);

        super.assertEquals(ImpreciseDateTests.FORMAT.parse("19990401000000000"), result);
    }
}