from enum import IntEnum


class SelfStatus(IntEnum):
    """
    Class `SelfStatus` contains all possible variants of Sink Panel Replay Self Status.
    """

    Disable = 0
    Inactive = 1
    Entry = 2
    Active = 3
    InternalError = 7

    def __str__(self):
        if self.value == self.Disable:
            return "Disable"
        elif self.value == self.Inactive:
            return "Inactive"
        elif self.value == self.Entry:
            return "Entry"
        elif self.value == self.Active:
            return "Active"
        elif self.value == self.InternalError:
            return "Internal error"
        else:
            return "Incorrect value"


class FrameStatus(IntEnum):
    """
    Class `FrameStatus` contains all possible variants of Sink Panel Replay frame locked.
    """
    Locked = 0
    Coasting = 1
    Governing = 2
    ReLocking = 3

    def __str__(self):
        if self.value == self.Locked:
            return "Locked"
        elif self.value == self.Coasting:
            return "Coasting"
        elif self.value == self.Governing:
            return "Governing"
        elif self.value == self.ReLocking:
            return "Re Locking"
        else:
            return "Incorrect value"


class SinkPRStatusFlags:

    def __init__(self, active_frame_crc_err: bool = False, rfb_storage_err: bool = False,
                 vsc_sdp_err: bool = False, ass_dp_missing: bool = False, self_status: SelfStatus = SelfStatus.Disable,
                 frame_locked: FrameStatus = FrameStatus.Locked, frame_locked_status_valid: bool = False):
        self.__active_frame_crc_err = active_frame_crc_err
        self.__rfb_storage_err = rfb_storage_err
        self.__vsc_sdp_err = vsc_sdp_err
        self.__ass_dp_missing = ass_dp_missing
        self.__self_status = self_status
        self.__frame_locked = frame_locked
        self.__frame_locked_status_valid = frame_locked_status_valid

    @property
    def active_frame_crc_err(self) -> bool:
        """
        Returns state of flag active frame crc error .

        Returns:
            object of `bool` type
        """
        return self.__active_frame_crc_err

    @property
    def rfb_storage_err(self) -> bool:
        """
        Returns state of flag rfb storage error.

        Returns:
            object of `bool` type
        """
        return self.__rfb_storage_err

    @property
    def vsc_sdp_err(self) -> bool:
        """
        Returns state of flag VSC SDP error.

        Returns:
            object of `bool` type
        """
        return self.__vsc_sdp_err

    @property
    def ass_dp_missing(self) -> bool:
        """
        Returns state of flag ASSDP missing.

        Returns:
            object of `bool` type
        """
        return self.__ass_dp_missing

    @property
    def self_status(self) -> SelfStatus:
        """
        Returns self status.

        Returns:
            object of `SelfStatus` type
        """
        return self.__self_status

    @property
    def frame_locked(self) -> FrameStatus:
        """
        Returns frame locked status.

        Returns:
            object of `FrameStatus` type
        """
        return self.__frame_locked

    @property
    def frame_locked_status_valid(self) -> bool:
        """
        Returns state of valid frame locked status.

        Returns:
            object of `bool` type
        """
        return self.__frame_locked_status_valid

    def __str__(self) -> str:
        return (f"Active frame CRC error: {self.active_frame_crc_err}\n"
                f"RFB Storage error: {self.rfb_storage_err}\n"
                f"PR VSC SDP uncorrectable error: {self.vsc_sdp_err}\n"
                f"Adaptive sync SDP missing and not disabled: {self.ass_dp_missing}\n"
                f"Sink device self refresh status: {self.self_status.__str__()}\n"
                f"Sink frame locked: {self.frame_locked.__str__()}\n"
                f"Sink frame locked status valid: {self.frame_locked_status_valid}\n")


class PRSSelfRefreshStatus(IntEnum):
    InActive = 0
    CaptureAndDisplayEntry = 1
    DisplayFromRFBEntry = 2
    CaptureAndDisplayActive = 3
    CaptureAndDisplayExit = 4
    InternalError = 7

    def __str__(self):
        if self.value == self.InActive:
            return "Inactive"
        elif self.value == self.CaptureAndDisplayEntry:
            return "Capture and display (Entry)"
        elif self.value == self.DisplayFromRFBEntry:
            return "Display from RFB (Entry)"
        elif self.value == self.CaptureAndDisplayActive:
            return "Capture and display (Active)"
        elif self.value == self.CaptureAndDisplayExit:
            return "Capture and display (Exit_"
        elif self.value == self.InternalError:
            return "Internal Error"
        else:
            return "Incorrect version"


class SinkPSRStatusFlags:

    def __init__(self, link_crc_err: bool = False, rfb_storage_err: bool = False, vsc_sdp_err: bool = False,
                 su_psr_caps_change: bool = False, self_refresh: PRSSelfRefreshStatus = PRSSelfRefreshStatus.InActive):
        self.__link_crc_err = link_crc_err
        self.__rfb_storage_err = rfb_storage_err
        self.__vsc_sdp_err = vsc_sdp_err
        self.__su_psr_caps_change = su_psr_caps_change
        self.__self_refresh = self_refresh

    @property
    def link_crc_err(self) -> bool:
        """
        Returns state of link crc error.

        Returns:
            object of `bool` type
        """
        return self.__link_crc_err

    @property
    def rfb_storage_err(self) -> bool:
        """
        Returns state of RFB storage error.

        Returns:
            object of `bool` type
        """
        return self.__rfb_storage_err

    @property
    def vsc_sdp_err(self) -> bool:
        """
        Returns state of vsc sdp error.

        Returns:
            object of `bool` type
        """
        return self.__vsc_sdp_err

    @property
    def su_psr_caps_change(self) -> bool:
        """
        Returns state of su PSR caps change.

        Returns:
            object of `bool` type
        """
        return self.__su_psr_caps_change

    @property
    def self_refresh(self) -> PRSSelfRefreshStatus:
        """
        Returns state of self refresh.

        Returns:
            object of `bool` type
        """
        return self.__self_refresh

    def __str__(self) -> str:
        return (f"Link CRC error: {self.link_crc_err}\n"
                f"FRB storage error: {self.rfb_storage_err}\n"
                f"PSR2 VSC SDP uncorrectable error: {self.vsc_sdp_err}\n"
                f"Sink device SU_PSR capability change: {self.su_psr_caps_change}\n"
                f"Sink device self-refresh status: {self.self_refresh.__str__()}\n")


class PrGranularityCaps(IntEnum):
    Line_1 = 1
    Line_2 = 2
    Line_4 = 4
    Line_8 = 8
    Line_16 = 16

    def __str__(self) -> str:
        if self.value == self.Line_1:
            return "Line 1"
        elif self.value == self.Line_2:
            return "Line 2"
        elif self.value == self.Line_4:
            return "Line 4"
        elif self.value == self.Line_8:
            return "Line 8"
        elif self.value == self.Line_16:
            return "Line 16"
        else:
            return "Incorrect version"


class PRCapsFlags:

    def __init__(self, pr_support: bool = False, selective_update_support: bool = False,
                 early_transport_support: bool = False, dsc_decode_func_support: bool = False,
                 asynch_video_timing_support: bool = False, dsc_src_support: bool = False,
                 granularity_needed: bool = False, y_gran_extended_supported: bool = False,
                 link_off_supported: bool = False):
        self.__pr_support = pr_support
        self.__selective_update_support = selective_update_support
        self.__early_transport_support = early_transport_support
        self.__dsc_decode_func_support = dsc_decode_func_support
        self.__asynch_video_timing_support = asynch_video_timing_support
        self.__dsc_src_support = dsc_src_support
        self.__granularity_needed = granularity_needed
        self.__y_gran_extended_supported = y_gran_extended_supported
        self.__link_off_supported = link_off_supported

    @property
    def pr_support(self) -> bool:
        """
        Returns PR support state.

        Returns:
            object of `bool` type
        """
        return self.__pr_support

    @pr_support.setter
    def pr_support(self, value: bool):
        self.__pr_support = value

    @property
    def selective_update_support(self) -> bool:
        """
        Returns state of selective update support.

        Returns:
            object of `bool` type
        """
        return self.__selective_update_support

    @selective_update_support.setter
    def selective_update_support(self, value: bool):
        self.__selective_update_support = value

    @property
    def early_transport_support(self) -> bool:
        """
        Returns state of early transport support.

        Returns:
            object of `bool` type
        """
        return self.__early_transport_support

    @early_transport_support.setter
    def early_transport_support(self, value: bool):
        self.__early_transport_support = value

    @property
    def dsc_decode_func_support(self) -> bool:
        """
        Returns state of DSC decode function support.

        Returns:
            object of `bool` type
        """
        return self.__dsc_decode_func_support

    @dsc_decode_func_support.setter
    def dsc_decode_func_support(self, value: bool):
        self.__dsc_decode_func_support = value

    @property
    def asynch_video_timing_support(self) -> bool:
        """
        Returns state of supports Asynchronous Video Timing.

        Returns:
            object of `bool` type
        """
        return self.__asynch_video_timing_support

    @asynch_video_timing_support.setter
    def asynch_video_timing_support(self, value: bool):
        self.__asynch_video_timing_support = value

    @property
    def dsc_src_support(self) -> bool:
        """
        Returns state of DSC CRC of multiple SU regions support.

        Returns:
            object of `bool` type
        """
        return self.__dsc_src_support

    @dsc_src_support.setter
    def dsc_src_support(self, value: bool):
        self.__dsc_src_support = value

    @property
    def granularity_needed(self) -> bool:
        """
        Returns state of Panel Replay Selective Update Granularity Needed.

        Returns:
            object of `bool` type
        """
        return self.__granularity_needed

    @granularity_needed.setter
    def granularity_needed(self, value: bool):
        self.__granularity_needed = value

    @property
    def y_gran_extended_supported(self) -> bool:
        """
        Returns state of SU Y Granularity Extended Capabilities supported.

        Returns:
            object of `bool` type
        """
        return self.__y_gran_extended_supported

    @y_gran_extended_supported.setter
    def y_gran_extended_supported(self, value: bool):
        self.__y_gran_extended_supported = value

    @property
    def link_off_supported(self) -> bool:
        """
        Returns state of Link OFF Supported in PR after Adaptive Sync SDP.

        Returns:
            object of `bool` type
        """
        return self.__link_off_supported

    @link_off_supported.setter
    def link_off_supported(self, value: bool):
        self.__link_off_supported = value

    def __str__(self) -> str:
        return (f"Panel Replay support: {self.pr_support}\n"
                f"Selective Update support: {self.selective_update_support}\n"
                f"Early Transport support: {self.early_transport_support}\n"
                f"DSC decode functionality support: {self.dsc_decode_func_support}\n"
                f"Asynchronous Video Timing support: {self.asynch_video_timing_support}\n"
                f"DSC CRC of multiple SU regions support: {self.dsc_src_support}\n"
                f"Panel Replay Selective Update granularity needed: {self.granularity_needed}\n"
                f"SU Y Granularity Extended Capabilities supported: {self.y_gran_extended_supported}\n"
                f"Link OFF Supported in PR after Adaptive Sync SDP: {self.link_off_supported}\n")


class SuYGranularity:

    def __init__(self, value_of_8: bool = False, value_of_10: bool = False, value_of_12: bool = False,
                 value_of_14: bool = False, value_of_15: bool = False, value_of_16: bool = False,
                 value_of_18: bool = False, value_of_20: bool = False, value_of_24: bool = False,
                 value_of_30: bool = False, value_of_32: bool = False, value_of_36: bool = False,
                 value_of_40: bool = False, value_of_48: bool = False, value_of_54: bool = False,
                 value_of_64: bool = False):
        self.__value_of_8 = value_of_8
        self.__value_of_10 = value_of_10
        self.__value_of_12 = value_of_12
        self.__value_of_14 = value_of_14
        self.__value_of_15 = value_of_15
        self.__value_of_16 = value_of_16
        self.__value_of_18 = value_of_18
        self.__value_of_20 = value_of_20
        self.__value_of_24 = value_of_24
        self.__value_of_30 = value_of_30
        self.__value_of_32 = value_of_32
        self.__value_of_36 = value_of_36
        self.__value_of_40 = value_of_40
        self.__value_of_48 = value_of_48
        self.__value_of_54 = value_of_54
        self.__value_of_64 = value_of_64

    @property
    def value_of_8(self) -> bool:
        """
        Supported Y granularity value of 8.

        Returns:
            object of `bool` type
        """
        return self.__value_of_8

    @value_of_8.setter
    def value_of_8(self, value: bool):
        self.__value_of_8 = value

    @property
    def value_of_10(self) -> bool:
        """
        Supported Y granularity value of 10.

        Returns:
            object of `bool` type
        """
        return self.__value_of_10

    @value_of_10.setter
    def value_of_10(self, value: bool):
        self.__value_of_10 = value

    @property
    def value_of_12(self) -> bool:
        """
        Supported Y granularity value of 12.

        Returns:
            object of `bool` type
        """
        return self.__value_of_12

    @value_of_12.setter
    def value_of_12(self, value: bool):
        self.__value_of_12 = value

    @property
    def value_of_14(self) -> bool:
        """
        Supported Y granularity value of 14.

        Returns:
            object of `bool` type
        """
        return self.__value_of_14

    @value_of_14.setter
    def value_of_14(self, value: bool):
        self.__value_of_14 = value

    @property
    def value_of_15(self) -> bool:
        """
        Supported Y granularity value of 15.

        Returns:
            object of `bool` type
        """
        return self.__value_of_15

    @value_of_15.setter
    def value_of_15(self, value: bool):
        self.__value_of_15 = value

    @property
    def value_of_16(self) -> bool:
        """
        Supported Y granularity value of 16.

        Returns:
            object of `bool` type
        """
        return self.__value_of_16

    @value_of_16.setter
    def value_of_16(self, value: bool):
        self.__value_of_16 = value

    @property
    def value_of_18(self) -> bool:
        """
        Supported Y granularity value of 18.

        Returns:
            object of `bool` type
        """
        return self.__value_of_18

    @value_of_18.setter
    def value_of_18(self, value: bool):
        self.__value_of_18 = value

    @property
    def value_of_20(self) -> bool:
        """
        Supported Y granularity value of 20.

        Returns:
            object of `bool` type
        """
        return self.__value_of_20

    @value_of_20.setter
    def value_of_20(self, value: bool):
        self.__value_of_20 = value

    @property
    def value_of_24(self) -> bool:
        """
        Supported Y granularity value of 24.

        Returns:
            object of `bool` type
        """
        return self.__value_of_24

    @value_of_24.setter
    def value_of_24(self, value: bool):
        self.__value_of_24 = value

    @property
    def value_of_30(self) -> bool:
        """
        Supported Y granularity value of 30.

        Returns:
            object of `bool` type
        """
        return self.__value_of_30

    @value_of_30.setter
    def value_of_30(self, value: bool):
        self.__value_of_30 = value

    @property
    def value_of_32(self) -> bool:
        """
        Supported Y granularity value of 32.

        Returns:
            object of `bool` type
        """
        return self.__value_of_32

    @value_of_32.setter
    def value_of_32(self, value: bool):
        self.__value_of_32 = value

    @property
    def value_of_36(self) -> bool:
        """
        Supported Y granularity value of 36.

        Returns:
            object of `bool` type
        """
        return self.__value_of_36

    @value_of_36.setter
    def value_of_36(self, value: bool):
        self.__value_of_36 = value

    @property
    def value_of_40(self) -> bool:
        """
        Supported Y granularity value of 40.

        Returns:
            object of `bool` type
        """
        return self.__value_of_40

    @value_of_40.setter
    def value_of_40(self, value: bool):
        self.__value_of_40 = value

    @property
    def value_of_48(self) -> bool:
        """
        Supported Y granularity value of 48.

        Returns:
            object of `bool` type
        """
        return self.__value_of_48

    @value_of_48.setter
    def value_of_48(self, value: bool):
        self.__value_of_48 = value

    @property
    def value_of_54(self) -> bool:
        """
        Supported Y granularity value of 54.

        Returns:
            object of `bool` type
        """
        return self.__value_of_54

    @value_of_54.setter
    def value_of_54(self, value: bool):
        self.__value_of_54 = value

    @property
    def value_of_64(self) -> bool:
        """
        Supported Y granularity value of 64.

        Returns:
            object of `bool` type
        """
        return self.__value_of_64

    @value_of_64.setter
    def value_of_64(self, value: bool):
        self.__value_of_64 = value

    def combined_value(self) -> int:
        return (self.value_of_8 | (self.value_of_10 << 1) | (self.value_of_12 << 2) | (self.value_of_14 << 3) |
                (self.value_of_15 << 4) | (self.value_of_16 << 5) | (self.value_of_18 << 6) | (self.value_of_20 << 7) |
                (self.value_of_24 << 8) | (self.value_of_30 << 9) | (self.value_of_32 << 10) |
                (self.value_of_36 << 11) | (self.value_of_40 << 12) | (self.value_of_48 << 13) |
                (self.value_of_54 << 14) | (self.value_of_64 << 15))

    def __str__(self) -> str:
        return (f"Value of 8: {self.value_of_8}\n"
                f"Value of 10: {self.value_of_10}\n"
                f"Value of 12: {self.value_of_12}\n"
                f"Value of 14: {self.value_of_14}\n"
                f"Value of 15: {self.value_of_15}\n"
                f"Value of 16: {self.value_of_16}\n"
                f"Value of 18: {self.value_of_18}\n"
                f"Value of 20: {self.value_of_20}\n"
                f"Value of 24: {self.value_of_24}\n"
                f"Value of 30: {self.value_of_30}\n"
                f"Value of 32: {self.value_of_32}\n"
                f"Value of 36: {self.value_of_36}\n"
                f"Value of 40: {self.value_of_40}\n"
                f"Value of 48: {self.value_of_48}\n"
                f"Value of 54: {self.value_of_54}\n"
                f"Value of 64: {self.value_of_64}\n"
                )


class PSRCaps(IntEnum):
    NotSupported = 0,
    PSR1Supported = 1,
    PSR2SUSupported = 2,
    PSR2YcoorSupported = 3,
    PSR2EarlyTransportSupported = 4

    def __str__(self) -> str:
        if self.value == self.NotSupported:
            return "Not supported"
        elif self.value == self.PSR1Supported:
            return "PSR 1 supported"
        elif self.value == self.PSR2SUSupported:
            return "PSR 2 SU supported"
        elif self.value == self.PSR2YcoorSupported:
            return "PSR 2 SU and Y coordinates supported"
        elif self.value == self.PSR2EarlyTransportSupported:
            return "PSR 2 SU, Y coordinates and Early Transport supported"
        else:
            return "Incorrect version"


class PSRSetupTime(IntEnum):
    T_330us = 0,
    T_275us = 1,
    T_220us = 2,
    T_165us = 3,
    T_110us = 4,
    T_55us = 5,
    T_0us = 6,
    T_Reserved = 7

    def __str__(self) -> str:
        if self.value == self.T_330us:
            return "330 us"
        elif self.value == self.T_275us:
            return "275 us"
        elif self.value == self.T_220us:
            return "220 us"
        elif self.value == self.T_165us:
            return "165 us"
        elif self.value == self.T_110us:
            return "110 us"
        elif self.value == self.T_55us:
            return "55 us"
        elif self.value == self.T_0us:
            return "0 us"
        else:
            return "Reserved"


class PSRCapsFlags:

    def __init__(self, psr_caps: PSRCaps = PSRCaps.NotSupported, link_training_req_psr1: bool = False,
                 psr_setup_time: PSRSetupTime = PSRSetupTime.T_330us, y_coor_psr2_su: bool = False,
                 su_coordinates_shall_adhere: bool = False, no_update_aux_frame_sync: bool = False):
        self.__psr_caps = psr_caps
        self.__link_training_req_psr1 = link_training_req_psr1
        self.__psr_setup_time = psr_setup_time
        self.__y_coor_psr2_su = y_coor_psr2_su
        self.__su_coordinates_shall_adhere = su_coordinates_shall_adhere
        self.__no_update_aux_frame_sync = no_update_aux_frame_sync

    @property
    def psr_caps(self) -> PSRCaps:
        """
        Returns PSR caps value from enum.

        Returns:
            object of `PSRCaps` type
        """
        return self.__psr_caps

    @psr_caps.setter
    def psr_caps(self, value: PSRCaps):
        self.__psr_caps = value

    @property
    def link_training_req_psr1(self) -> bool:
        """
        Returns link training request PSR1 flag.

        Returns:
            object of `bool` type
        """
        return self.__link_training_req_psr1

    @link_training_req_psr1.setter
    def link_training_req_psr1(self, value: bool):
        self.__link_training_req_psr1 = value

    @property
    def psr_setup_time(self) -> PSRSetupTime:
        """
        Returns PSR setup time value.

        Returns:
            object of `PSRSetupTime` type
        """
        return self.__psr_setup_time

    @psr_setup_time.setter
    def psr_setup_time(self, value: PSRSetupTime):
        self.__psr_setup_time = value

    @property
    def y_coor_psr2_su(self) -> bool:
        """
        Returns flag for "Y-coordinate for PSR2 SU".

        Returns:
            object of `bool` type
        """
        return self.__y_coor_psr2_su

    @y_coor_psr2_su.setter
    def y_coor_psr2_su(self, value: bool):
        self.__y_coor_psr2_su = value

    @property
    def su_coordinates_shall_adhere(self) -> bool:
        """
        Returns flag for "SU coordinates shall adhere"

        Returns:
            object of `bool` type
        """
        return self.__su_coordinates_shall_adhere

    @su_coordinates_shall_adhere.setter
    def su_coordinates_shall_adhere(self, value: bool):
        self.__su_coordinates_shall_adhere = value

    @property
    def no_update_aux_frame_sync(self) -> bool:
        """
        Returns value for flag "Do not update AUX FRAME SYNC".

        Returns:
            object of `bool` type
        """
        return self.__no_update_aux_frame_sync

    @no_update_aux_frame_sync.setter
    def no_update_aux_frame_sync(self, value: bool):
        self.__no_update_aux_frame_sync = value

    def __str__(self) -> str:
        return (f"Panel Self Refresh supported: {self.psr_caps.__str__()}\n"
                f"Link Training Requirement of Sink: {self.link_training_req_psr1}\n"
                f"PSR Setup time: {self.psr_setup_time.__str__()}\n"
                f"Y-coordinate Requirement of Sink Device: {self.y_coor_psr2_su}\n"
                f"Panel Self Refresh 2 Selective Update Granularity Required: {self.su_coordinates_shall_adhere}\n"
                f"Frame Sync Function Is Not Needed for Selective Update: {self.no_update_aux_frame_sync}\n")
