package jp.sourceforge.glad.calendar.era;

import static jp.sourceforge.glad.calendar.CalendarConsts.*;
import jp.sourceforge.glad.calendar.ISOCalendar;
import junit.framework.TestCase;

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

    JapaneseEras eras;

    protected void setUp() throws Exception {
        eras = JapaneseEras.getInstance();
    }

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

    public void testBeforeMeiji() {
        JapaneseEra era = eras.getJapaneseEra(BEFORE_MEIJI);
        assertEquals(BEFORE_MEIJI, era.getId());
        
        ISOCalendar c18671231 = new ISOCalendar(1867, 12, 31, 23, 59, 59, 999);
        checkEra_same(era, c18671231);
        checkEraId_equals(BEFORE_MEIJI, c18671231);
        checkYearOfEra_equals(1867, c18671231);
        
        assertEquals(1867, eras.getGregorianYear(BEFORE_MEIJI, 1867));
    }

    /**
     * 明治に関するテスト。
     */
    public void testMeiji() {
        JapaneseEra era = eras.getJapaneseEra(MEIJI);
        assertEquals(MEIJI, era.getId());
        assertEquals("Meiji", era.getName());
        assertEquals("M",     era.getAbbr());
        assertEquals(-3218832000000L, era.getSince());
        assertEquals(1868, era.getSinceYear());

        // 1873-01-01 までは旧暦なので、正確には日付が異なるが、
        // Java SE 6.0 の実装に合わせた。
        ISOCalendar c18671231 = new ISOCalendar(1867, 12, 31, 23, 59, 59, 999);
        checkEra_notSame(era, c18671231);
        
        ISOCalendar c18680101 = new ISOCalendar(1868, 1, 1, 0, 0, 0, 0);
        checkEra_same(era, c18680101);
        checkEraId_equals(MEIJI, c18680101);
        checkYearOfEra_equals(1, c18680101);
        
        // 1873-01-01 から新暦 (グレゴリオ暦採用) を採用。
        ISOCalendar c18730101 = new ISOCalendar(1873, 1, 1, 0, 0, 0, 0);
        checkEra_same(era, c18730101);
        checkEraId_equals(MEIJI, c18730101);
        checkYearOfEra_equals(6, c18730101);
        
        // 明治最後の日。
        ISOCalendar c19120729 = new ISOCalendar(1912, 7, 29, 23, 59, 59, 999);
        checkEra_same(era, c19120729);
        checkEraId_equals(MEIJI, c19120729);
        checkYearOfEra_equals(45, c19120729);
        
        ISOCalendar c19120730 = new ISOCalendar(1912, 7, 30, 0, 0, 0, 0);
        checkEra_notSame(era, c19120730);
        
        // 和暦から西暦へ。
        try {
            eras.getGregorianYear(MEIJI, 0);
            fail();
        } catch (IllegalArgumentException e) {}
        assertEquals(1868, eras.getGregorianYear(MEIJI, 1));
        assertEquals(1873, eras.getGregorianYear(MEIJI, 6));
        assertEquals(1912, eras.getGregorianYear(MEIJI, 45));
        assertEquals(1913, eras.getGregorianYear(MEIJI, 46));
    }

    /**
     * 大正に関するテスト。
     */
    public void testTaisho() {
        JapaneseEra era = eras.getJapaneseEra(TAISHO);
        assertEquals(TAISHO, era.getId());
        assertEquals("Taisho", era.getName());
        assertEquals("T",      era.getAbbr());
        assertEquals(-1812153600000L, era.getSince());
        assertEquals(1912, era.getSinceYear());
        
        ISOCalendar c19120729 = new ISOCalendar(1912, 7, 29, 23, 59, 59, 999);
        checkEra_notSame(era, c19120729);
        
        // 大正最初の日。
        ISOCalendar c19120730 = new ISOCalendar(1912, 7, 30, 0, 0, 0, 0);
        checkEra_same(era, c19120730);
        checkEraId_equals(TAISHO, c19120730);
        checkYearOfEra_equals(1, c19120730);
        
        // 大正最後の日。
        ISOCalendar c19261224 = new ISOCalendar(1926, 12, 24, 23, 59, 59, 999);
        checkEra_same(era, c19261224);
        checkEraId_equals(TAISHO, c19261224);
        checkYearOfEra_equals(15, c19261224);
        
        ISOCalendar c19261225 = new ISOCalendar(1926, 12, 25, 0, 0, 0, 0);
        checkEra_notSame(era, c19261225);
        
        // 和暦から西暦へ。
        try {
            eras.getGregorianYear(TAISHO, 0);
            fail();
        } catch (IllegalArgumentException e) {}
        assertEquals(1912, eras.getGregorianYear(TAISHO, 1));
        assertEquals(1926, eras.getGregorianYear(TAISHO, 15));
        assertEquals(1927, eras.getGregorianYear(TAISHO, 16));
    }

    /**
     * 昭和に関するテスト。
     */
    public void testShowa() {
        JapaneseEra era = eras.getJapaneseEra(SHOWA);
        assertEquals(SHOWA, era.getId());
        assertEquals("Showa", era.getName());
        assertEquals("S",     era.getAbbr());
        assertEquals(-1357603200000L, era.getSince());
        assertEquals(1926, era.getSinceYear());
        
        ISOCalendar c19261224 = new ISOCalendar(1926, 12, 24, 23, 59, 59, 999);
        checkEra_notSame(era, c19261224);
        
        // 昭和最初の日。
        ISOCalendar c19261225 = new ISOCalendar(1926, 12, 25, 0, 0, 0, 0);
        checkEra_same(era, c19261225);
        checkEraId_equals(SHOWA, c19261225);
        checkYearOfEra_equals(1, c19261225);
        
        // 昭和最後の日。
        ISOCalendar c19890107 = new ISOCalendar(1989, 1, 7, 23, 59, 59, 999);
        checkEra_same(era, c19890107);
        checkEraId_equals(SHOWA, c19890107);
        checkYearOfEra_equals(64, c19890107);
        
        ISOCalendar c19890108 = new ISOCalendar(1989, 1, 8, 0, 0, 0, 0);
        checkEra_notSame(era, c19890108);
        
        // 和暦から西暦へ。
        try {
            eras.getGregorianYear(SHOWA, 0);
            fail();
        } catch (IllegalArgumentException e) {}
        assertEquals(1926, eras.getGregorianYear(SHOWA, 1));
        assertEquals(1989, eras.getGregorianYear(SHOWA, 64));
        assertEquals(1990, eras.getGregorianYear(SHOWA, 65));
    }

    /**
     * 平成に関するテスト。
     */
    public void testHeisei() {
        JapaneseEra era = eras.getJapaneseEra(HEISEI);
        assertEquals(HEISEI, era.getId());
        assertEquals("Heisei", era.getName());
        assertEquals("H",      era.getAbbr());
        assertEquals(600220800000L, era.getSince());
        assertEquals(1989, era.getSinceYear());
        
        ISOCalendar c19890107 = new ISOCalendar(1989, 1, 7, 23, 59, 59, 999);
        checkEra_notSame(era, c19890107);
        
        // 平成最初の日。
        ISOCalendar c19890108 = new ISOCalendar(1989, 1, 8, 0, 0, 0, 0);
        checkEra_same(era, c19890108);
        checkEraId_equals(HEISEI, c19890108);
        checkYearOfEra_equals(1, c19890108);
        
        ISOCalendar c20080123 = new ISOCalendar(2008, 1, 23, 1, 23, 45, 123);
        checkEra_same(era, c20080123);
        checkEraId_equals(HEISEI, c20080123);
        checkYearOfEra_equals(20, c20080123);
        
        // 和暦から西暦へ。
        try {
            eras.getGregorianYear(HEISEI, 0);
            fail();
        } catch (IllegalArgumentException e) {}
        assertEquals(1989, eras.getGregorianYear(HEISEI, 1));
        assertEquals(2008, eras.getGregorianYear(HEISEI, 20));
    }

    void checkEra_same(JapaneseEra era, ISOCalendar calendar) {
        assertSame(era, eras.getJapaneseEra(
                calendar.getYear(), calendar.getMonth(), calendar.getDay()));
        assertSame(era, eras.getJapaneseEra(
                calendar.getTimeInMillis(), calendar.getTimeZone()));
        assertSame(era, eras.getJapaneseEra(calendar.toGregorianCalendar()));
        assertSame(era, eras.getJapaneseEra(calendar.toDate()));
        assertSame(era, eras.getJapaneseEra(calendar));
    }

    void checkEra_notSame(JapaneseEra era, ISOCalendar calendar) {
        assertNotSame(era, eras.getJapaneseEra(
                calendar.getYear(), calendar.getMonth(), calendar.getDay()));
        assertNotSame(era, eras.getJapaneseEra(
                calendar.getTimeInMillis(), calendar.getTimeZone()));
        assertNotSame(era, eras.getJapaneseEra(calendar.toGregorianCalendar()));
        assertNotSame(era, eras.getJapaneseEra(calendar.toDate()));
        assertNotSame(era, eras.getJapaneseEra(calendar));
    }

    void checkEraId_equals(int id, ISOCalendar calendar) {
        assertEquals(id, eras.getEraId(
                calendar.getYear(), calendar.getMonth(), calendar.getDay()));
        assertEquals(id, eras.getEraId(
                calendar.getTimeInMillis(), calendar.getTimeZone()));
        assertEquals(id, eras.getEraId(calendar.toGregorianCalendar()));
        assertEquals(id, eras.getEraId(calendar.toDate()));
        assertEquals(id, eras.getEraId(calendar));
    }

    void checkYearOfEra_equals(int yearOfEra, ISOCalendar calendar) {
        assertEquals(yearOfEra, eras.getYearOfEra(
                calendar.getYear(), calendar.getMonth(), calendar.getDay()));
        assertEquals(yearOfEra, eras.getYearOfEra(
                calendar.getTimeInMillis(), calendar.getTimeZone()));
        assertEquals(yearOfEra, eras.getYearOfEra(calendar.toGregorianCalendar()));
        assertEquals(yearOfEra, eras.getYearOfEra(calendar.toDate()));
        assertEquals(yearOfEra, eras.getYearOfEra(calendar));
    }

}
