# -*- coding: utf-8 -*-


class HolidayUtil:
    """
    法定节假日工具（自2001年12月29日起）
    """

    __SIZE = 18
    __ZERO = 48
    __TAG_REMOVE = "~"
    NAMES = ("元旦节", "春节", "清明节", "劳动节", "端午节", "中秋节", "国庆节", "国庆中秋", "抗战胜利日")
    __DATA = "[encoded data, 15480 characters]"

    __NAMES_IN_USE = NAMES
    __DATA_IN_USE = __DATA

    def __init__(self):
        pass

    @staticmethod
    def __padding(n):
        return ("0" if n < 10 else "") + str(n)

    @staticmethod
    def __buildHolidayForward(s):
        day = s[0:8]
        name = HolidayUtil.__NAMES_IN_USE[ord(s[8:9]) - HolidayUtil.__ZERO]
        work = ord(s[9:10]) == HolidayUtil.__ZERO
        target = s[10:18]
        from .. import Holiday
        return Holiday(day, name, work, target)

    @staticmethod
    def __buildHolidayBackward(s):
        size = len(s)
        day = s[size - 18:size - 10]
        name = HolidayUtil.__NAMES_IN_USE[ord(s[size - 10:size - 9]) - HolidayUtil.__ZERO]
        work = ord(s[size - 9:size - 8]) == HolidayUtil.__ZERO
        target = s[size - 8:]
        from .. import Holiday
        return Holiday(day, name, work, target)

    @staticmethod
    def __findForward(key):
        start = HolidayUtil.__DATA_IN_USE.find(key)
        if start < 0:
            return None
        right = HolidayUtil.__DATA_IN_USE[start:]
        n = len(right) % HolidayUtil.__SIZE
        if n > 0:
            right = right[n:]
        while not right.startswith(key) and len(right) >= HolidayUtil.__SIZE:
            right = right[HolidayUtil.__SIZE:]
        return right

    @staticmethod
    def __findBackward(key):
        start = HolidayUtil.__DATA_IN_USE.rfind(key)
        if start < 0:
            return None
        key_size = len(key)
        left = HolidayUtil.__DATA_IN_USE[0:start + key_size]
        size = len(left)
        n = size % HolidayUtil.__SIZE
        if n > 0:
            left = left[0:size - n]
        size = len(left)
        while size - key_size != left.rfind(key) and size >= HolidayUtil.__SIZE:
            left = left[0:size - HolidayUtil.__SIZE]
            size = len(left)
        return left

    @staticmethod
    def __findHolidaysForward(key):
        arr = []
        s = HolidayUtil.__findForward(key)
        if s is None:
            return arr
        while s.startswith(key):
            arr.append(HolidayUtil.__buildHolidayForward(s))
            s = s[HolidayUtil.__SIZE:]
        return arr

    @staticmethod
    def __findHolidaysBackward(key):
        arr = []
        s = HolidayUtil.__findBackward(key)
        if s is None:
            return arr
        size = len(s)
        key_size = len(key)

        while size - key_size == s.rfind(key):
            arr.append(HolidayUtil.__buildHolidayBackward(s))
            s = s[0:size - HolidayUtil.__SIZE:]
            size = len(s)
        arr.reverse()
        return arr

    @staticmethod
    def __getHoliday(year, month=0, day=0):
        y = str(year)
        if month == 0 or day == 0:
            arr = HolidayUtil.__findHolidaysForward(y.replace("-", ""))
        else:
            arr = HolidayUtil.__findHolidaysForward(y + HolidayUtil.__padding(month) + HolidayUtil.__padding(day))
        return None if len(arr) < 1 else arr[0]

    @staticmethod
    def __getHolidays(year, month=0):
        y = str(year)
        if month == 0:
            arr = HolidayUtil.__findHolidaysForward(y.replace("-", ""))
        else:
            arr = HolidayUtil.__findHolidaysForward(y + HolidayUtil.__padding(month))
        return arr

    @staticmethod
    def __getHolidaysByTarget(year, month=0, day=0):
        y = str(year)
        if month == 0 or day == 0:
            arr = HolidayUtil.__findHolidaysBackward(y.replace("-", ""))
        else:
            arr = HolidayUtil.__findHolidaysBackward(y + HolidayUtil.__padding(month) + HolidayUtil.__padding(day))
        return arr

    @staticmethod
    def getHoliday(year, month=0, day=0):
        """
        获取指定年月日的节假日信息，如果不存在，返回None
        :param year: 年或者yyyy-mm-dd格式的日期
        :param month: 月，数字1到12，如果year使用yyyy-mm-dd则不传该参数或设为0
        :param day: 日，数字1到31，如果year使用yyyy-mm-dd则不传该参数或设为0
        :return: Holiday或者None
        """
        return HolidayUtil.__getHoliday(year, month, day)

    @staticmethod
    def getHolidays(year, month=0):
        return HolidayUtil.__getHolidays(year, month)

    @staticmethod
    def getHolidaysByTarget(year, month=0, day=0):
        return HolidayUtil.__getHolidaysByTarget(year, month, day)

    @staticmethod
    def fix(names, data):
        """
        修正或追加节假日数据。节假日名称下标从0开始，超过9的，按ASCII码表依次往后排列；调休标识0为上班，否则放假
        :param names: 用于替换默认的节假日名称列表，传None即可使用默认名称
        :param data: 需要修正或追加的节假日数据，每18位表示1天依次排列，格式：当天年月日YYYYMMDD(8位)+节假日名称下标(1位)+调休标识(1位)+节假日当天YYYYMMDD(8位)。例：202005023120200501代表2020-05-02为劳动节放假，对应节假日为2020-05-01
        :return:
        """
        if names is not None:
            HolidayUtil.__NAMES_IN_USE = names
        if data is None:
            return
        append = ""
        while len(data) >= HolidayUtil.__SIZE:
            segment = data[:HolidayUtil.__SIZE]
            day = segment[:8]
            remove = HolidayUtil.__TAG_REMOVE == segment[8:9]
            holiday = HolidayUtil.getHoliday(day)
            if holiday is None:
                if not remove:
                    append += segment
            else:
                name_index = -1
                for i in range(0, len(HolidayUtil.__NAMES_IN_USE)):
                    if HolidayUtil.__NAMES_IN_USE[i] == holiday.getName():
                        name_index = i
                        break
                if name_index > -1:
                    old = day + chr(name_index + HolidayUtil.__ZERO) + ("0" if holiday.isWork() else "1") + holiday.getTarget().replace("-", "")
                    HolidayUtil.__DATA_IN_USE = HolidayUtil.__DATA_IN_USE.replace(old, "" if remove else segment)
            data = data[HolidayUtil.__SIZE:]
        if len(append) > 0:
            HolidayUtil.__DATA_IN_USE += append
