package jp.sourceforge.glad.calendar.text;

import static jp.sourceforge.glad.calendar.text.ISODateFormat.*;

import java.text.DateFormat;
import java.text.ParseException;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import jp.sourceforge.glad.calendar.CalendarConsts;
import jp.sourceforge.glad.calendar.ISOCalendar;
import jp.sourceforge.glad.calendar.util.ISOTimeZone;
import junit.framework.TestCase;

/**
 * {@link ISODateFormat} の単体テスト。
 * 
 * @author GLAD!!
 */
public class ISODateFormatTest extends TestCase {

    ISOCalendar calendar;

    protected void setUp() throws Exception {
        calendar = new ISOCalendar(2009, 1, 23, 1, 12, 23, 123);
    }

    protected void tearDown() throws Exception {
        calendar = null;
    }

    public void testFormat_BasicDate() {
        ISODateFormat df = ISODateFormat.basicDate();
        assertEquals("20090123", df.format(calendar.toGregorianCalendar()));
        calendar.setTimeZone(CalendarConsts.UTC);
        assertEquals("20090122", df.format(calendar.toGregorianCalendar()));
    }

    public void testFormat_ExtendedDate() {
        ISODateFormat df = ISODateFormat.date();
        assertEquals("2009-01-23", df.format(calendar.toGregorianCalendar()));
        calendar.setTimeZone(CalendarConsts.UTC);
        assertEquals("2009-01-22", df.format(calendar.toGregorianCalendar()));
    }

    public void testFormat_BasicTime() {
        ISODateFormat df = ISODateFormat.basicTime();
        assertEquals("011223.123+0900", df.format(calendar.toGregorianCalendar()));
        calendar.setTimeZone(CalendarConsts.UTC);
        assertEquals("161223.123Z", df.format(calendar.toGregorianCalendar()));
    }

    public void testFormat_ExtendedTime() {
        ISODateFormat df = ISODateFormat.time();
        assertEquals("01:12:23.123+09:00", df.format(calendar.toGregorianCalendar()));
        calendar.setTimeZone(CalendarConsts.UTC);
        assertEquals("16:12:23.123Z", df.format(calendar.toGregorianCalendar()));
    }

    public void testFormat_BasicDateTime() {
        ISODateFormat df = ISODateFormat.basicDateTime();
        assertEquals("20090123T011223.123+0900",
                df.format(calendar.toGregorianCalendar()));
        calendar.setTimeZone(CalendarConsts.UTC);
        assertEquals("20090122T161223.123Z",
                df.format(calendar.toGregorianCalendar()));
    }

    public void testFormat_ExtendedDateTime() {
        ISODateFormat df = ISODateFormat.dateTime();
        assertEquals("2009-01-23T01:12:23.123+09:00",
                df.format(calendar.toGregorianCalendar()));
        calendar.setTimeZone(CalendarConsts.UTC);
        assertEquals("2009-01-22T16:12:23.123Z",
                df.format(calendar.toGregorianCalendar()));
    }

    public void testParse_BasicDate() throws Exception {
        ISODateFormat df = ISODateFormat.basicDate();
        df.setLenient(false);
        GregorianCalendar cal = df.parseCalendar("20090123");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(2009, calendar.getYear());
        assertEquals( 1, calendar.getMonth());
        assertEquals(23, calendar.getDay());
        assertEquals( 0, calendar.getMillisOfDay());
        assertEquals(TimeZone.getDefault(), calendar.getTimeZone());
        
        // 異なるフォーマット。
        try {
            df.parse("2009-01-23");
            System.out.println(new ISOCalendar(df.getCalendar()));
            fail();
        } catch (ParseException e) {}
    }

    public void testParse_ExtendedDate() throws Exception {
        ISODateFormat df = ISODateFormat.date();
        df.setLenient(false);
        GregorianCalendar cal = df.parseCalendar("2009-01-23");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(2009, calendar.getYear());
        assertEquals( 1, calendar.getMonth());
        assertEquals(23, calendar.getDay());
        assertEquals( 0, calendar.getMillisOfDay());
        assertEquals(TimeZone.getDefault(), calendar.getTimeZone());
        
        // 0 の省略。
        cal = df.parseCalendar("2009-1-23");
        calendar = new ISOCalendar(cal);
        assertEquals(2009, calendar.getYear());
        assertEquals( 1, calendar.getMonth());
        assertEquals(23, calendar.getDay());
        assertEquals( 0, calendar.getMillisOfDay());
        assertEquals(TimeZone.getDefault(), calendar.getTimeZone());
        
        // 異なるフォーマット。
        try {
            df.parse("20090123");
            fail();
        } catch (ParseException e) {}
    }

    public void testParse_BasicTime() throws Exception {
        ISODateFormat df = ISODateFormat.basicTime();
        df.setLenient(false);
        GregorianCalendar cal = df.parseCalendar("011223.123+0900");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.JST, calendar.getTimeZone());
        
        // 異なるタイムゾーン。
        cal = df.parseCalendar("011223.123Z");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(ISOTimeZone.UTC, calendar.getTimeZone());
        
        // フィールドの省略。
        try {
            df.parse("011223+0900");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("011223");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("0112");
            fail();
        } catch (ParseException e) {}
        
        // 異なるフォーマット。
        try {
            df.parse("01:12:23.123+09:00");
            fail();
        } catch (ParseException e) {}
    }

    public void testParse_BasicTimeUTC() throws Exception {
        ISODateFormat df = ISODateFormat.basicTime();
        df.setLenient(false);
        df.setTimeZone(CalendarConsts.UTC);
        GregorianCalendar cal = df.parseCalendar("011223.123Z");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.UTC, calendar.getTimeZone());
        
        // 異なるタイムゾーン。
        cal = df.parseCalendar("011223.123+0900");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(ISOTimeZone.JST, calendar.getTimeZone());
        
        // フィールドの省略。
        try {
            df.parse("011223Z");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("011223");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("0112");
            fail();
        } catch (ParseException e) {}
        
        // 異なるフォーマット。
        try {
            df.parse("01:12:23.123Z");
            fail();
        } catch (ParseException e) {}
    }

    public void testParse_BasicTimeNoTZ() throws Exception {
        ISODateFormat df = new ISODateFormat(BASIC_TIME_MEDIUM_FORMAT);
        df.setLenient(false);
        GregorianCalendar cal = df.parseCalendar("011223");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals( 0, calendar.getMillis());
        assertEquals(TimeZone.getDefault(), calendar.getTimeZone());
        
        // 異なるタイムゾーン。
        df.setTimeZone(CalendarConsts.UTC);
        cal = df.parseCalendar("011223");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals( 0, calendar.getMillis());
        assertEquals(CalendarConsts.UTC, calendar.getTimeZone());
    }

    public void testParse_ExtendedTime() throws Exception {
        ISODateFormat df = ISODateFormat.time();
        df.setLenient(false);
        GregorianCalendar cal = df.parseCalendar("01:12:23.123+09:00");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.JST, calendar.getTimeZone());
        
        // 0 の省略。
        cal = df.parseCalendar("1:12:23.123+09:00");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.JST, calendar.getTimeZone());
        
        // 異なるタイムゾーン。
        cal = df.parseCalendar("01:12:23.123Z");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(ISOTimeZone.UTC, calendar.getTimeZone());
        
        // フィールドの省略。
        try {
            df.parse("01:12:23+09:00");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("01:12:23");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("01:12");
            fail();
        } catch (ParseException e) {}
        
        // 異なるフォーマット。
        try {
            df.parse("011223.123+0900");
            fail();
        } catch (ParseException e) {}
    }

    public void testParse_ExtendedTimeUTC() throws Exception {
        ISODateFormat df = ISODateFormat.time();
        df.setLenient(false);
        df.setTimeZone(CalendarConsts.UTC);
        GregorianCalendar cal = df.parseCalendar("01:12:23.123Z");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.UTC, calendar.getTimeZone());
        
        // 0 の省略。
        cal = df.parseCalendar("1:12:23.123Z");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.UTC, calendar.getTimeZone());
        
        // 異なるタイムゾーン。
        cal = df.parseCalendar("01:12:23.123+09:00");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(ISOTimeZone.JST, calendar.getTimeZone());
        
        // フィールドの省略。
        try {
            df.parse("01:12:23+09:00");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("01:12:23");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("01:12");
            fail();
        } catch (ParseException e) {}
        
        // 異なるフォーマット。
        try {
            df.parse("011223.123Z");
            fail();
        } catch (ParseException e) {}
    }

    public void testParse_ExtendedTimeNoTZ() throws Exception {
        ISODateFormat df = ISODateFormat.time(DateFormat.MEDIUM);
        df.setLenient(false);
        GregorianCalendar cal = df.parseCalendar("01:12:23.123");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals( 0, calendar.getMillis());
        assertEquals(TimeZone.getDefault(), calendar.getTimeZone());
        
        // 0 の省略。
        cal = df.parseCalendar("1:12:23.123");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals( 0, calendar.getMillis());
        assertEquals(TimeZone.getDefault(), calendar.getTimeZone());
        
        // 異なるタイムゾーン。
        df.setTimeZone(CalendarConsts.UTC);
        cal = df.parseCalendar("01:12:23.123");
        calendar = new ISOCalendar(cal);
        assertEquals(1970, calendar.getYear());
        assertEquals( 1, calendar.getDayOfYear());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals( 0, calendar.getMillis());
        assertEquals(CalendarConsts.UTC, calendar.getTimeZone());
    }

    public void testParse_BasicDateTime() throws Exception {
        ISODateFormat df = ISODateFormat.basicDateTime();
        df.setLenient(false);
        GregorianCalendar cal =
                df.parseCalendar("20090123T011223.123+0900");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(2009, calendar.getYear());
        assertEquals( 1, calendar.getMonth());
        assertEquals(23, calendar.getDay());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.JST, calendar.getTimeZone());
        
        // 異なるタイムゾーン。
        cal = df.parseCalendar("20090123T011223.123Z");
        calendar = new ISOCalendar(cal);
        assertEquals(2009, calendar.getYear());
        assertEquals( 1, calendar.getMonth());
        assertEquals(23, calendar.getDay());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(ISOTimeZone.UTC, calendar.getTimeZone());
        
        // フィールドの省略。
        try {
            df.parse("20090123T011223+0900");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("20090123T011223");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("090123T0112");
            fail();
        } catch (ParseException e) {}
        
        // 異なるフォーマット。
        try {
            df.parse("2009-01-23T01:12:23.123+09:00");
            fail();
        } catch (ParseException e) {}
    }

    public void testParse_ExtendedDateTime() throws Exception {
        ISODateFormat df = ISODateFormat.dateTime();
        df.setLenient(false);
        GregorianCalendar cal =
                df.parseCalendar("2009-01-23T01:12:23.123+09:00");
        ISOCalendar calendar = new ISOCalendar(cal);
        assertEquals(2009, calendar.getYear());
        assertEquals( 1, calendar.getMonth());
        assertEquals(23, calendar.getDay());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.JST, calendar.getTimeZone());
        
        // 0 の省略。
        cal = df.parseCalendar("2009-1-23T1:12:23.123+09:00");
        calendar = new ISOCalendar(cal);
        assertEquals(2009, calendar.getYear());
        assertEquals( 1, calendar.getMonth());
        assertEquals(23, calendar.getDay());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(CalendarConsts.JST, calendar.getTimeZone());
        
        // 異なるタイムゾーン。
        cal = df.parseCalendar("2009-01-23T01:12:23.123Z");
        calendar = new ISOCalendar(cal);
        assertEquals(2009, calendar.getYear());
        assertEquals( 1, calendar.getMonth());
        assertEquals(23, calendar.getDay());
        assertEquals( 1, calendar.getHour());
        assertEquals(12, calendar.getMinute());
        assertEquals(23, calendar.getSecond());
        assertEquals(123, calendar.getMillis());
        assertEquals(ISOTimeZone.UTC, calendar.getTimeZone());
        
        // フィールドの省略。
        try {
            df.parse("2009-01-23T01:12:23+09:00");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("2009-01-23T01:12:23");
            fail();
        } catch (ParseException e) {}
        try {
            df.parse("09-01-23T01:12");
            fail();
        } catch (ParseException e) {}
        
        // 異なるフォーマット。
        try {
            df.parse("20090123T011223.123+0900");
            fail();
        } catch (ParseException e) {}
    }

}
