package ch.epfl.isochrone.timetable;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Random;

import org.junit.Test;

import ch.epfl.isochrone.timetable.Date.DayOfWeek;
import ch.epfl.isochrone.timetable.Date.Month;

public class TestDate {
    @Test(expected = java.lang.IllegalArgumentException.class)
    public void testConstructorDayTooSmall() {
        new Date(0, Month.JANUARY, 1);
    }

    @Test(expected = java.lang.IllegalArgumentException.class)
    public void testConstructorDayTooBig() {
        new Date(29, Month.FEBRUARY, 2100);
    }

    @Test(expected = java.lang.IllegalArgumentException.class)
    public void testConstructorIntMonthTooSmall() {
        new Date(1, 0, 1);
    }

    @Test(expected = java.lang.IllegalArgumentException.class)
    public void testConstructorIntMonthTooBig() {
        new Date(1, 13, 1);
    }

    @SuppressWarnings("deprecation")
    @Test
    public void testConstructorFromJavaDate() {
        assertEquals(new Date(17, Month.FEBRUARY, 2014), new Date(
                new java.util.Date(114, 1, 17)));
    }

    @Test
    public void testDay() {
        for (int d = 1; d <= 31; ++d)
            assertEquals(d, (new Date(d, Month.JANUARY, 2014)).day());
    }

    @Test
    public void testMonth() {
        for (Month m : Month.values())
            assertEquals(m, (new Date(1, m, 2014)).month());
    }

    @Test
    public void testIntMonth() {
        for (int m = 1; m <= 12; ++m)
            assertEquals(m, (new Date(15, m, 2000)).intMonth());
    }

    @Test
    public void testYear() {
        Random rng = new Random();
        for (int i = 0; i < 100; ++i) {
            int y = rng.nextInt();
            assertEquals(y, (new Date(12, Month.MARCH, y)).year());
        }
    }

    @Test
    public void testDayOfWeek() {
        assertEquals(DayOfWeek.SUNDAY,
                new Date(24, Month.JULY, -586).dayOfWeek());
        assertEquals(DayOfWeek.MONDAY,
                new Date(1, Month.JANUARY, 1).dayOfWeek());
        assertEquals(DayOfWeek.SUNDAY,
                new Date(2, Month.AUGUST, 1953).dayOfWeek());
        assertEquals(DayOfWeek.MONDAY,
                new Date(1, Month.OCTOBER, 1973).dayOfWeek());
        assertEquals(DayOfWeek.FRIDAY,
                new Date(11, Month.OCTOBER, 2013).dayOfWeek());
    }

    @Test
    public void testRelative() {
        assertEquals(new Date(1, Month.MARCH, 2000), new Date(29,
                Month.FEBRUARY, 2000).relative(1));
        assertEquals(new Date(1, Month.MARCH, 2100), new Date(28,
                Month.FEBRUARY, 2100).relative(1));
        assertEquals(new Date(1, Month.OCTOBER, 1973), new Date(25,
                Month.NOVEMBER, 2013).relative(-14665));
        assertEquals(new Date(1, Month.OCTOBER, 1973), new Date(1,
                Month.OCTOBER, 1973).relative(0));
    }

    @SuppressWarnings("deprecation")
    @Test
    public void testToJavaDate() {
        assertEquals(new java.util.Date(114, 1, 17), new Date(17,
                Month.FEBRUARY, 2014).toJavaDate());
    }

    // equals is extensively tested by all the assertEquals calls, we do not
    // test it further here.

    @Test
    public void testToString() {
        assertEquals("2014-02-17",
                new Date(17, Month.FEBRUARY, 2014).toString());
    }

    @Test
    public void testCompareTo() {
        assertTrue(new Date(1, Month.JANUARY, 2014).compareTo(new Date(31,
                Month.DECEMBER, 2013)) > 0);
        assertTrue(new Date(1, Month.JANUARY, 2014).compareTo(new Date(31,
                Month.DECEMBER, 2014)) < 0);
        assertTrue(new Date(1, Month.JANUARY, 2014).compareTo(new Date(1,
                Month.JANUARY, 2014)) == 0);
    }
}
