from enum import IntEnum


class ColorInfo:
    """

    Class contains information of frame `ColorFormat`, `DynamicRange`, `Colorimetry`.

    """
    class ColorFormat(IntEnum):
        """
        Contains values of possible color format.
        """
        CF_NONE = 0
        CF_UNKNOWN = 1
        CF_RGB = 2
        CF_YCbCr_422 = 3
        CF_YCbCr_444 = 4
        CF_YCbCr_420 = 5
        CF_IDO_DEFINED = 6
        CF_Y_ONLY = 7
        CF_RAW = 8
        CF_DSC = 9

    class DynamicRange(IntEnum):
        """
        Contains values of possible dynamic range.
        """
        DR_UNKNOWN = -1
        DR_VESA = 0
        DR_CTA = 1

    class Colorimetry(IntEnum):
        """
        Contains values of possible colorimetry.
        """
        CM_NONE = 0
        CM_RESERVED = 1
        CM_sRGB = 2
        CM_SMPTE_170M = 3
        CM_ITUR_BT601 = 4
        CM_ITUR_BT709 = 5
        CM_xvYCC601 = 6
        CM_xvYCC709 = 7
        CM_sYCC601 = 8
        CM_AdobeYCC601 = 9
        CM_AdobeRGB = 10
        CM_ITUR_BT2020_YcCbcCrc = 11
        CM_ITUR_BT2020_YCbCr = 12
        CM_ITUR_BT2020_RGB = 13
        CM_RGB_WIDE_GAMUT_FIX = 14
        CM_RGB_WIDE_GAMUT_FLT = 15
        CM_DCI_P3 = 16
        CM_DICOM_1_4_GRAY_SCALE = 17
        CM_CUSTOM_COLOR_PROFILE = 18

        CM_opYCC601 = CM_AdobeYCC601
        CM_opRGB = CM_AdobeRGB

    __COMPONENT_MULTIPLIER = {
        ColorFormat.CF_RGB: 3,
        ColorFormat.CF_YCbCr_422: 2,
        ColorFormat.CF_YCbCr_444: 3,
        ColorFormat.CF_YCbCr_420: 3 / 2,
        ColorFormat.CF_Y_ONLY: 1,
        ColorFormat.CF_RAW: 3
    }

    def __init__(self):
        self.colorimetry = self.Colorimetry.CM_NONE
        self.color_format = self.ColorFormat.CF_NONE
        self.dynamic_range = self.DynamicRange.DR_VESA
        self.bpc = 0

    def __str__(self):
        return f"Color format: {self.color_format.name}\n" \
               f"Colorimetry: {self.colorimetry.name}\n" \
               f"Dynamic Range: {self.dynamic_range.name}\n" \
               f"BPC: {self.bpc}"

    def __eq__(self, other):
        return self.bpc == other.bpc and\
               self.color_format == other.color_format and\
               self.colorimetry == other.colorimetry and\
               self.dynamic_range == other.dynamic_range

    def is_valid(self) -> bool:
        """

        Check that information is valid (not equal NONE state and bpc more than 0).

        Returns:
            object of bool type.
        """
        return self.bpc > 0 and\
               self.color_format != self.ColorFormat.CF_NONE and\
               self.colorimetry != self.Colorimetry.CM_NONE

    @property
    def bpp(self) -> int:
        """

        Returns calculated bits per pixel for this color info (except DSC). 0 if color info is not valid.

        Returns:
            object of int type.
        """
        if self.is_valid() and self.color_format != self.ColorFormat.CF_DSC:
            return round(self.bpc * self.__COMPONENT_MULTIPLIER.get(self.color_format, 1))
        else:
            return 0
