from enum import IntEnum


class Timing:

    """
    Class `Timing` contains information about Timing: all resolutions, timing id, frame rate, `AspectRatio`,
    `Standard`, `ReduceBlanking`.
    """

    class Standard(IntEnum):
        """
        Class `Standard` contains all possible variants of timing standards.
        """
        SD_NONE = 0
        SD_CVT = 1
        SD_DMT = 2
        SD_CTA = 3
        SD_UGF = 4
        SD_OVT = 5

    class AspectRatio(IntEnum):
        """
        Class `AspectRatio` contains all possible variants of timing aspect ratio.
        """
        AR_NONE = 0
        AR_4_3 = 1
        AR_16_9 = 2

    class ReduceBlanking(IntEnum):
        """
        Class `ReduceBlanking` contains all possible variants of timing reduce blanking.
        """
        RB_NONE = 0
        RB1 = 1
        RB2 = 2
        RB3 = 3

    def __init__(self):
        self.frame_rate = 0.0
        self.hactive = 0
        self.vactive = 0
        self.htotal = 0
        self.vtotal = 0
        self.hstart = 0
        self.vstart = 0
        self.hswidth = 0
        self.vswidth = 0
        self.id = 0
        self.aspect_ratio = self.AspectRatio.AR_NONE
        self.standard = self.Standard.SD_NONE
        self.reduce_blanking = self.ReduceBlanking.RB_NONE

    def __str__(self):
        return f"{self.frame_rate / 1000:03} " \
               f"{self.htotal} {self.hstart} {self.hactive} {self.hswidth:+} " \
               f"{self.vtotal} {self.vstart} {self.vactive} {self.vswidth:+}"

    def __eq__(self, other) -> bool:
        return self.hactive == other.hactive and self.vactive == other.vactive and self.htotal == other.htotal and \
               self.vtotal == other.vtotal and self.hstart == other.hstart and self.vstart == other.vstart and \
               self.hswidth == other.hswidth and self.vswidth == other.vswidth

    def is_valid(self) -> bool:
        """
        Check that timing is correct (Resolutions and frame rate more than 0)

        Returns:
            is valid (bool) - valid (True) or not (False)
        """
        return self.hactive > 0 and \
               self.vactive > 0 and \
               self.htotal > 0 and \
               self.vtotal > 0 and \
               self.hstart > 0 and \
               self.vstart > 0 and \
               self.frame_rate > 0

    @property
    def pixel_clock(self) -> float:
        """
        Returns calculated pixel clock required for this video mode in MHz. 0.0 if video mode is not valid.

        Returns:
            pixel clock (float)
        """
        if self.is_valid():
            return round(self.htotal * self.vtotal * self.frame_rate / 1000000000.0, 3)
        else:
            return 0.0
