# -*- coding: utf-8 -*-
from raw._ebuttdt import *
from raw import _ebuttdt as ebuttdt_raw
from datetime import timedelta
from decimal import Decimal
import re, logging
import six
from pyxb.exceptions_ import SimpleTypeValueError, SimpleFacetValueError
from ebu_tt_live.errors import TimeFormatOverflowError, ExtentMissingError
from ebu_tt_live.strings import ERR_TIME_FORMAT_OVERFLOW, ERR_SEMANTIC_VALIDATION_TIMING_TYPE, ERR_1DIM_ONLY, \
    ERR_2DIM_ONLY
from .pyxb_utils import get_xml_parsing_context
from .validation.base import SemanticValidationMixin
from .validation.presentation import SizingValidationMixin

log = logging.getLogger(__name__)


def _get_time_members(checked_time):
    hours, seconds = divmod(checked_time.seconds, 3600)
    hours += checked_time.days * 24
    minutes, seconds = divmod(seconds, 60)
    milliseconds, _ = divmod(checked_time.microseconds, 1000)
    return hours, minutes, seconds, milliseconds


class _TimedeltaBindingMixin(object):
    """
    Wiring in timedelta assignment and conversion operators
    """

    # For each timing attribute a list of timeBases is specified, which represents the valid timeBase, timing attribute
    # and timing type semantic constraint.
    _compatible_timebases = {
        'begin': [],
        'dur': [],
        'end': []
    }

    @classmethod
    def compatible_timebases(cls):
        return cls._compatible_timebases

    @classmethod
    def _ConvertArguments_vx(cls, args, kw):
        """
        This hook is called before the type in question is instantiated. This is meant to do some normalization
        of input parameters and convert them to tuple. In this function we check the timeBase and the attribute name
        against our compatible_timebases mapping inside the timing type class. If an invalid scenario is encountered
        SimpleTypeValueError is raised, which effectively prevents the timingType union to instantiate the type.

        :raises pyxb.SimpleTypeValueError:
        :param args:
        :param kw:
        :return: tuple of converted input parameters.
        """
        result = []
        # In parsing mode check timebase compatibility at instantiation time. This prevents pyxb instantiating
        # the wrong type given 2 types having overlapping values in a union as it happens in full and limited
        # clock timing types.
        context = get_xml_parsing_context()
        if context is not None:
            # This means we are in XML parsing context. There should be a timeBase and a timing_attribute_name in the
            # context object.
            time_base = context['timeBase']
            # It is possible for a timing type to exist as the value of an element not an attribute,
            # in which case no timing_attribute_name is in the context; in that case don't attempt
            # to validate the data against a timebase. At the moment this only affects the
            # documentStartOfProgramme metadata element.
            if 'timing_attribute_name' in context:
                timing_att_name = context['timing_attribute_name']
                if time_base not in cls._compatible_timebases[timing_att_name]:
                    log.debug(ERR_SEMANTIC_VALIDATION_TIMING_TYPE.format(
                        attr_name=timing_att_name,
                        attr_type=cls,
                        attr_value=args,
                        time_base=time_base
                    ))
                    raise pyxb.SimpleTypeValueError(ERR_SEMANTIC_VALIDATION_TIMING_TYPE.format(
                        attr_name=timing_att_name,
                        attr_type=cls,
                        attr_value=args,
                        time_base=time_base
                    ))
        for item in args:
            if isinstance(item, timedelta):
                result.append(cls.from_timedelta(item))
            else:
                result.append(item)
        return tuple(result)

    @property
    def timedelta(self):
        return self.as_timedelta(self)


def cells_to_pixels(cells_in, root_extent, cell_resolution):
    if not isinstance(root_extent, PixelExtentType):
        raise Exception()
    if cells_in.horizontal is not None:
        # 2dimensional
        return cells_in.horizontal * root_extent.horizontal / cell_resolution.horizontal, \
               cells_in.vertical * root_extent.vertical / cell_resolution.vertical
    else:
        return cells_in.vertical * root_extent.vertical / cell_resolution.vertical,


def pixels_to_cells(pixels_in, root_extent, cell_resolution):
    if not isinstance(root_extent, PixelExtentType):
        raise Exception()
    if pixels_in.horizontal is not None:
        return pixels_in.horizontal * cell_resolution.horizontal / root_extent.horizontal, \
               pixels_in.vertical * cell_resolution.vertical / root_extent.vertical
    else:
        return pixels_in.vertical * cell_resolution.vertical / root_extent.vertical,


def named_color_to_rgba(named_color):
    color_map = {
        "transparent": "00000000",
        "black": "000000ff",
        "silver": "c0c0c0ff",
        "gray": "808080ff",
        "white": "ffffffff",
        "maroon": "800000ff",
        "red": "ff0000ff",
        "purple": "800080ff",
        "fuchsia": "ff00ffff",
        "magenta": "ff00ffff",
        "green": "008000ff",
        "lime": "00ff00ff",
        "olive": "808000ff",
        "yellow": "ffff00ff",
        "navy": "000080ff",
        "blue": "0000ffff",
        "teal": "008080ff",
        "aqua": "00ffffff",
        "cyan": "00ffffff"
    }
    return '#{}'.format(color_map[named_color])