# 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.generic.datetime import DateTime
from timelinelib.calendar.coptic.time import CopticDelta
from timelinelib.calendar.coptic.time import CopticTime
from timelinelib.calendar.coptic.monthnames import abbreviated_name_of_month
from timelinelib.calendar.coptic.weekdaynames import abbreviated_name_of_weekday
from timelinelib.calendar.coptic.coptic2julian import coptic_ymd_to_julian_day
from timelinelib.calendar.coptic.julian2coptic import julian_day_to_coptic_ymd


class CopticDateTime(DateTime):

    def __init__(self, year, month, day, hour, minute, second):
        if not self.is_valid(year, month, day):
            raise ValueError("Invalid coptic date %s-%s-%s" % (year, month, day))
        DateTime.__init__(self, year, month, day, hour, minute, second)

    @classmethod
    def TimeClass(cls):
        return CopticTime

    @classmethod
    def julian_day_to_ymd_fn(cls):
        return julian_day_to_coptic_ymd

    @classmethod
    def ymd_to_julian_day_fn(cls):
        return coptic_ymd_to_julian_day

    @property
    def week_number(self):

        def tkyriaka_week_1(year):
            thoth_4 = CopticDateTime.from_ymd(year, 1, 4).to_time()
            thoth_4_day_of_week = thoth_4.day_of_week
            return thoth_4 - CopticDelta.from_days(thoth_4_day_of_week)

        def days_between(end, start):
            return end.julian_day - start.julian_day

        def days_since_tkyriaka_week_1(time):
            year = CopticDateTime.from_time(time).year
            diff = days_between(end=time, start=tkyriaka_week_1(year + 1))
            if diff >= 0:
                return diff
            diff = days_between(end=time, start=tkyriaka_week_1(year))
            if diff >= 0:
                return diff
            diff = days_between(end=time, start=tkyriaka_week_1(year - 1))
            if diff >= 0:
                return diff
            raise ValueError("should not end up here")

        return days_since_tkyriaka_week_1(self.to_time()) // 7 + 1

    @property
    def abbreviated_month_name(self):
        return abbreviated_name_of_month(self.month)

    @property
    def abbreviated_weekday_name(self):
        return abbreviated_name_of_weekday(self.to_time().day_of_week)

    @property
    def is_leap_year(self):
        return self.year_is_leap_year(self.year)

    def days_in_month(self):
        return self.nbr_of_days_in_month(self.year, self.month)

    @property
    def days_in_week(self):
        return 7

    @property
    def days_in_year(self):
        if self.is_leap_year:
            return 366
        else:
            return 365

    @classmethod
    def months_in_year(cls):
        return 13

    @classmethod
    def nbr_of_days_in_month(cls, year, month):
        if month <= 12:
            return 30
        elif cls.year_is_leap_year(year):
            return 6
        else:
            return 5

    @staticmethod
    def year_is_leap_year(year):
        if year > 0 and (year + 1) % 4 == 0:
            return True
        elif year < 0 and year % 4 == 0:
            return True
        else:
            return False
