# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Timeline 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Timeline.  If not, see <http://www.gnu.org/licenses/>.


from timelinelib.calendar.gregorian.time import GregorianTime
from timelinelib.calendar.generic.datetime import DateTime
from timelinelib.test.cases.unit import UnitTestCase


class TestDateTime(DateTime):
    pass


class DescribeDateTime(UnitTestCase):

    def test_can_compare(self):
        self.assertTrue(self.dt1 == self.dt1)
        self.assertFalse(self.dt1 == self.dt2)
        self.assertFalse(self.dt1 != self.dt1)
        self.assertTrue(self.dt1 != self.dt2)
        self.assertTrue(TestDateTime.from_ymd(2020, 1, 1) != DateTime.from_ymd(2020, 1, 1))

    def test_months_in_year_is_not_implemented(self):
        with self.assertRaises(NotImplementedError) as ctx:
            TestDateTime.months_in_year()
        self.assertEqual('The months_in_year() has not yet been defined in TestDateTime', str(ctx.exception))

    def test_nbr_of_days_in_month_is_not_implemented(self):
        with self.assertRaises(NotImplementedError) as ctx:
            TestDateTime.nbr_of_days_in_month(2020, 5)
        self.assertEqual('The nbr_of_days_in_month() has not yet been defined in TestDateTime', str(ctx.exception))

    def test_time_class_is_not_implemented(self):
        with self.assertRaises(NotImplementedError) as ctx:
            self.dt1.TimeClass()
        self.assertEqual('The TimeClass() has not yet been defined in TestDateTime', str(ctx.exception))

    def test_julian_day_to_ymd_fn_is_not_implemented(self):
        with self.assertRaises(NotImplementedError) as ctx:
            self.dt1.julian_day_to_ymd_fn()
        self.assertEqual('The julian_day_to_ymd_fn() has not yet been defined in TestDateTime', str(ctx.exception))

        with self.assertRaises(NotImplementedError) as ctx:
            self.dt1.from_time(GregorianTime(1, 0))
        self.assertEqual('The julian_day_to_ymd_fn() has not yet been defined in TestDateTime', str(ctx.exception))

    def test_ymd_to_julian_day_fn_is_not_implemented(self):
        with self.assertRaises(NotImplementedError) as ctx:
            self.dt1.ymd_to_julian_day_fn()
        self.assertEqual('The ymd_to_julian_day_fn() has not yet been defined in TestDateTime', str(ctx.exception))

        with self.assertRaises(NotImplementedError) as ctx:
            self.dt1.to_time()
        self.assertEqual('The ymd_to_julian_day_fn() has not yet been defined in TestDateTime', str(ctx.exception))

    def test_has_year_property(self):
        self.assertEqual(2013, self.dt1.year)
        self.assertEqual(-2013, self.dt2.year)

    def test_has_formatted_year_property(self):
        self.assertEqual("2013", self.dt1.formatted_year)
        self.assertEqual(f"2014 {self.dt2.BC}", self.dt2.formatted_year)

    def test_has_month_property(self):
        self.assertEqual(6, self.dt1.month)
        self.assertEqual(6, self.dt2.month)

    def test_has_day_property(self):
        self.assertEqual(11, self.dt1.day)
        self.assertEqual(11, self.dt2.day)

    def test_has_hour_property(self):
        self.assertEqual(15, self.dt1.hour)
        self.assertEqual(16, self.dt2.hour)

    def test_has_minute_property(self):
        self.assertEqual(23, self.dt1.minute)
        self.assertEqual(24, self.dt2.minute)

    def test_has_second_property(self):
        self.assertEqual(11, self.dt1.second)
        self.assertEqual(12, self.dt2.second)

    def test_has_is_bc_function(self):
        self.assertFalse(self.dt1.is_bc())
        self.assertTrue(self.dt2.is_bc())

    def test_has_is_first_day_in_year_function(self):
        self.assertFalse(self.dt1.is_first_day_in_year())
        self.assertFalse(self.dt2.is_first_day_in_year())
        self.assertTrue(self.dt3.is_first_day_in_year())
        self.assertTrue(self.dt4.is_first_day_in_year())
        self.assertFalse(self.dt5.is_first_day_in_year())
        self.assertFalse(self.dt6.is_first_day_in_year())

    def test_has_is_first_of_month_function(self):
        self.assertFalse(self.dt1.is_first_of_month())
        self.assertFalse(self.dt2.is_first_of_month())
        self.assertTrue(self.dt3.is_first_of_month())
        self.assertTrue(self.dt4.is_first_of_month())
        self.assertFalse(self.dt5.is_first_of_month())
        self.assertFalse(self.dt6.is_first_of_month())

    def test_has_is_valid_time_function(self):
        self.assertTrue(TestDateTime.is_valid_time(0, 0, 0))
        self.assertTrue(TestDateTime.is_valid_time(23, 59, 59))
        self.assertFalse(TestDateTime.is_valid_time(23, 60, 0))
        self.assertFalse(TestDateTime.is_valid_time(24, 0, 0))

    def test_has_from_ymd_function(self):
        dt = TestDateTime.from_ymd(2020, 6, 11)
        self.assertEqual('TestDateTime<2020-06-11 00:00:00>', str(dt))

    def test_has_to_tuple_function(self):
        self.assertEqual((2013, 6, 11, 15, 23, 11), self.dt1.to_tuple())

    def test_has_to_date_tuple_function(self):
        self.assertEqual((2013, 6, 11), self.dt1.to_date_tuple())

    def test_has_to_time_tuple_function(self):
        self.assertEqual((15, 23, 11), self.dt1.to_time_tuple())

    def test_has_replace_function(self):
        self.assertEqual('TestDateTime<2020-06-11 15:23:11>', str(self.dt1.replace(year=2020)))
        self.assertEqual('TestDateTime<2013-12-11 15:23:11>', str(self.dt1.replace(month=12)))
        self.assertEqual('TestDateTime<2013-06-02 15:23:11>', str(self.dt1.replace(day=2)))
        self.assertEqual('TestDateTime<2013-06-11 16:23:11>', str(self.dt1.replace(hour=16)))
        self.assertEqual('TestDateTime<2013-06-11 15:13:11>', str(self.dt1.replace(minute=13)))
        self.assertEqual('TestDateTime<2013-06-11 15:23:55>', str(self.dt1.replace(second=55)))

    def setUp(self):
        self.dt1 = TestDateTime(2013, 6, 11, 15, 23, 11)
        self.dt2 = TestDateTime(-2013, 6, 11, 16, 24, 12)
        self.dt3 = TestDateTime(2013, 1, 1, 0, 0, 0)
        self.dt4 = TestDateTime(-2013, 1, 1, 0, 0, 0)
        self.dt5 = TestDateTime(2013, 1, 1, 15, 23, 11)
        self.dt6 = TestDateTime(-2013, 1, 1, 16, 24, 12)
