# 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, overrides_base_class_function
from timelinelib.calendar.bosparanian.time import BosparanianDelta
from timelinelib.calendar.bosparanian.time import BosparanianTime
from timelinelib.calendar.bosparanian.monthnames import bosp_abbreviated_name_of_month
from timelinelib.calendar.bosparanian.monthnames import bosp_name_of_month
from timelinelib.calendar.bosparanian.weekdaynames import bosp_abbreviated_name_of_weekday
from timelinelib.calendar.bosparanian.bosparanian2julian import ymd_to_bosparanian_day
from timelinelib.calendar.bosparanian.julian2bosparanian import bosparanian_day_to_ymd


class BosparanianDateTime(DateTime):

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

    @classmethod
    def TimeClass(cls):
        return BosparanianTime

    @classmethod
    def julian_day_to_ymd_fn(cls):
        return bosparanian_day_to_ymd

    @classmethod
    def ymd_to_julian_day_fn(cls):
        return ymd_to_bosparanian_day

    @overrides_base_class_function
    def is_bc(self):
        return False

    @property
    def week_number(self):
        """
        returns number of week in year
        """
        def windsday_week_1(year):
            pra_4 = BosparanianDateTime.from_ymd(year, 1, 4).to_time()
            pra_4_day_of_week = pra_4.day_of_week
            return pra_4 - BosparanianDelta.from_days(pra_4_day_of_week)

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

        def days_since_windsday_week_1(time):
            year = BosparanianDateTime.from_time(time).year
            diff = days_between(end=time, start=windsday_week_1(year + 1))
            if diff >= 0:
                return diff
            diff = days_between(end=time, start=windsday_week_1(year))
            if diff >= 0:
                return diff
            diff = days_between(end=time, start=windsday_week_1(year - 1))
            if diff >= 0:
                return diff
            raise ValueError("should not end up here")
        return days_since_windsday_week_1(self.to_time()) // 7 + 1

    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):
        return 365

    @classmethod
    def months_in_year(cls):
        return 13

    @property
    def last_month(self):
        return self.months_in_year()

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

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

    @property
    def month_name(self):
        return bosp_name_of_month(self.month)

    @property
    @overrides_base_class_function
    def formatted_year(self):
        return f"{self.year}BF"

    @property
    def is_leap_year(self):
        return False

    @staticmethod
    def year_is_leap_year(year):
        return False

    @classmethod
    def nbr_of_days_in_month(cls, year, month):
        if month in [13]:
            return 5
        return 30
