/**
 * Copyright (C) 2019 Patrik Dufresne Service Logiciel <info@patrikdufresne.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package com.planimod.core;

import static com.planimod.core.TimeUtils.dateTime;
import static com.planimod.core.TimeUtils.time;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Calendar;

import org.junit.Test;

public class TimeRangesTest {

    @Test
    public void testContainsEquals() {
        Shift e1 = new Shift();
        Shift e2 = new Shift();

        // 1 before 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 8:00"));
        e2.setEndDate(time("Mon 9:00"));
        assertFalse(TimeRanges.containsEquals(e1, e2));
        assertFalse(TimeRanges.containsEquals(e2, e1));

        // 1 before-touch 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 7:00"));
        e2.setEndDate(time("Mon 8:00"));
        assertFalse(TimeRanges.containsEquals(e1, e2));
        assertFalse(TimeRanges.containsEquals(e2, e1));

        // 1 before-intersect 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:30"));
        e2.setStartDate(time("Mon 7:00"));
        e2.setEndDate(time("Mon 8:00"));
        assertFalse(TimeRanges.containsEquals(e1, e2));
        assertFalse(TimeRanges.containsEquals(e2, e1));

        // 1 before-in-touch 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 6:30"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertFalse(TimeRanges.containsEquals(e1, e2));
        assertTrue(TimeRanges.containsEquals(e2, e1));

        // 1 after-in-touch 2
        e1.setStartDate(time("Mon 6:30"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertFalse(TimeRanges.containsEquals(e1, e2));
        assertTrue(TimeRanges.containsEquals(e2, e1));

        // 1 in 2
        // 2 in 1
        e1.setStartDate(time("Mon 6:15"));
        e1.setEndDate(time("Mon 6:45"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertFalse(TimeRanges.containsEquals(e1, e2));
        assertTrue(TimeRanges.containsEquals(e2, e1));

        // 1 equals 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertTrue(TimeRanges.containsEquals(e1, e2));

    }

    @Test
    public void testIntersect() {
        Shift e1 = new Shift();
        Shift e2 = new Shift();

        // 1 before 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 8:00"));
        e2.setEndDate(time("Mon 9:00"));
        assertFalse(TimeRanges.intersects(e1, e2));
        assertFalse(TimeRanges.intersects(e2, e1));

        // 1 before-touch 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 7:00"));
        e2.setEndDate(time("Mon 8:00"));
        assertFalse(TimeRanges.intersects(e1, e2));
        assertFalse(TimeRanges.intersects(e2, e1));

        // 1 before-intersect 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:30"));
        e2.setStartDate(time("Mon 7:00"));
        e2.setEndDate(time("Mon 8:00"));
        assertTrue(TimeRanges.intersects(e1, e2));
        assertTrue(TimeRanges.intersects(e2, e1));

        // 1 before-in-touch 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 6:30"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertFalse(TimeRanges.intersects(e1, e2));
        assertFalse(TimeRanges.intersects(e2, e1));

        // 1 after-in-touch 2
        e1.setStartDate(time("Mon 6:30"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertFalse(TimeRanges.intersects(e1, e2));
        assertFalse(TimeRanges.intersects(e2, e1));

        // 1 in 2
        // 2 in 1
        e1.setStartDate(time("Mon 6:15"));
        e1.setEndDate(time("Mon 6:45"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertFalse(TimeRanges.intersects(e1, e2));
        assertFalse(TimeRanges.intersects(e2, e1));

        // 1 equals 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertFalse(TimeRanges.intersects(e1, e2));

    }

    @Test
    public void testIntersectEquals() {
        Shift e1 = new Shift();
        Shift e2 = new Shift();

        // 1 before 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 8:00"));
        e2.setEndDate(time("Mon 9:00"));
        assertFalse(TimeRanges.intersectEquals(e1, e2));
        assertFalse(TimeRanges.intersectEquals(e2, e1));

        // 1 before-touch 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 7:00"));
        e2.setEndDate(time("Mon 8:00"));
        assertFalse(TimeRanges.intersectEquals(e1, e2));
        assertFalse(TimeRanges.intersectEquals(e2, e1));

        // 1 before-intersect 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:30"));
        e2.setStartDate(time("Mon 7:00"));
        e2.setEndDate(time("Mon 8:00"));
        assertTrue(TimeRanges.intersectEquals(e1, e2));
        assertTrue(TimeRanges.intersectEquals(e2, e1));

        // 1 before-in-touch 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 6:30"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertTrue(TimeRanges.intersectEquals(e1, e2));
        assertTrue(TimeRanges.intersectEquals(e2, e1));

        // 1 after-in-touch 2
        e1.setStartDate(time("Mon 6:30"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertTrue(TimeRanges.intersectEquals(e1, e2));
        assertTrue(TimeRanges.intersectEquals(e2, e1));

        // 1 in 2
        // 2 in 1
        e1.setStartDate(time("Mon 6:15"));
        e1.setEndDate(time("Mon 6:45"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertTrue(TimeRanges.intersectEquals(e1, e2));
        assertTrue(TimeRanges.intersectEquals(e2, e1));

        // 1 equals 2
        e1.setStartDate(time("Mon 6:00"));
        e1.setEndDate(time("Mon 7:00"));
        e2.setStartDate(time("Mon 6:00"));
        e2.setEndDate(time("Mon 7:00"));
        assertTrue(TimeRanges.intersectEquals(e1, e2));

    }

    /**
     * Check the result of previousWeek() function with a time range not corresponding to a week.
     */
    @Test
    public void testPreviousWeek_WithUnpreciseRange() {
        TimeRange range = new ConcreteTimeRange(dateTime("2013-01-10 Thu 10:32"), dateTime("2013-01-11 Fri 1:45"));
        assertEquals(new ConcreteTimeRange(dateTime("2012-12-30 Sun 0:00"), dateTime("2013-01-06 Sun 0:00")), TimeRanges.previousWeek(range, Calendar.SUNDAY));
    }

    /**
     * Check the result of previousWeek() function with a time range corresponding to a week.
     */
    @Test
    public void testPreviousWeek_WithPreciseRange() {
        TimeRange range = new ConcreteTimeRange(dateTime("2013-01-06 Sun 0:00"), dateTime("2013-01-13 Sun 0:00"));
        assertEquals(new ConcreteTimeRange(dateTime("2012-12-30 Sun 0:00"), dateTime("2013-01-06 Sun 0:00")), TimeRanges.previousWeek(range, Calendar.SUNDAY));
    }

    /**
     * Check the result of previousWeek() function with a time range corresponding to a week.
     */
    @Test
    public void testPreviousWeek_WithDaylightSaving() {
        TimeRange range;
        range = new ConcreteTimeRange(dateTime("2013-03-11 Mon 6:00"), dateTime("2013-03-11 Mon 15:00"));
        assertEquals(new ConcreteTimeRange(dateTime("2013-03-03 Sun 0:00"), dateTime("2013-03-10 Sun 0:00")), TimeRanges.previousWeek(range, Calendar.SUNDAY));

        range = new ConcreteTimeRange(dateTime("2013-03-18 Mon 6:00"), dateTime("2013-03-18 Mon 15:00"));
        assertEquals(new ConcreteTimeRange(dateTime("2013-03-10 Sun 0:00"), dateTime("2013-03-17 Sun 0:00")), TimeRanges.previousWeek(range, Calendar.SUNDAY));
    }

    @Test
    public void GetFirstDayOfFirstWeekOfMonth() {

        assertEquals(dateTime("2013-03-31 Sun 00:00"), TimeRanges.getFirstDayOfFirstWeekOfMonth(dateTime("2013-04-09 Tue 6:00"), Calendar.SUNDAY));

        assertEquals(dateTime("2012-11-25 Sun 00:00"), TimeRanges.getFirstDayOfFirstWeekOfMonth(dateTime("2012-12-13 Thu 6:00"), Calendar.SUNDAY));

        assertEquals(dateTime("2012-01-29 Sun 00:00"), TimeRanges.getFirstDayOfFirstWeekOfMonth(dateTime("2012-02-29 Wed 6:00"), Calendar.SUNDAY));
    }

    @Test
    public void GetLastDayOfLastWeekOfMonth() {

        assertEquals(dateTime("2013-04-28 Sun 00:00"), TimeRanges.getLastDayOfLastWeekOfMonth(dateTime("2013-04-09 Tue 6:00"), Calendar.SUNDAY));

        assertEquals(dateTime("2012-12-30 Sun 00:00"), TimeRanges.getLastDayOfLastWeekOfMonth(dateTime("2012-12-13 Thu 6:00"), Calendar.SUNDAY));

    }

    @Test
    public void GetWeekStart() {

        assertEquals(dateTime("2012-08-19 Sun 00:00"), TimeRanges.getWeekStart(dateTime("2012-08-21 Tue 16:42"), Calendar.SUNDAY));

        assertEquals(dateTime("2011-10-02 Sun 00:00"), TimeRanges.getWeekStart(dateTime("2011-10-05 Wed 16:42"), Calendar.SUNDAY));

    }

    @Test
    public void GetWeekStart_WithDaylightSaving() {

        assertEquals(dateTime("2012-11-04 Sun 00:00"), TimeRanges.getWeekStart(dateTime("2012-11-06 Tue 16:42"), Calendar.SUNDAY));

    }

    @Test
    public void GetWeekEnd_WithDaylightSaving() {

        assertEquals(dateTime("2012-11-11 Sun 00:00"), TimeRanges.getWeekEnd(dateTime("2012-11-06 Tue 16:42"), Calendar.SUNDAY));

    }

    @Test
    public void GetWeekEnd() {

        assertEquals(dateTime("2012-08-26 Sun 00:00"), TimeRanges.getWeekEnd(dateTime("2012-08-21 Tue 16:42"), Calendar.SUNDAY));

    }
}
