from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .pr_sink_private_types import SinkPanelReplayCapsStruct, SinkPanelSelfRefreshCapsStruct
from .pr_sink_types import PRCapsFlags, PrGranularityCaps, SuYGranularity, PSRCapsFlags, PSRCaps, PSRSetupTime
from UniTAP.libs.lib_tsi.tsi import *
from typing import Tuple


class SinkPanelReplayCaps:
    """
    Class `SinkPanelReplayCaps` contains information about Sink Panel Replay capabilities.
    - Set configuration with parameters: `PRCapsFlags`, `PrGranularityCaps`, PrGranularityCaps`, `SuYGranularity`.
    Function `set`.
    - Get configuration: Tuple[`PRCapsFlags`, `PrGranularityCaps`, `PrGranularityCaps`, `SuYGranularity``].
    Function `get`.
    """

    def __init__(self, port_io: PortIO):
        self.__io = port_io

    def set(self, flags: PRCapsFlags = PRCapsFlags(),
            x_granularity: PrGranularityCaps = PrGranularityCaps.Line_1,
            y_granularity: PrGranularityCaps = PrGranularityCaps.Line_1,
            granularity: SuYGranularity = SuYGranularity()):
        flags_value = (flags.pr_support | (flags.selective_update_support << 1) | (flags.early_transport_support << 2) |
                       (flags.dsc_decode_func_support << 10) | (flags.asynch_video_timing_support << 11) |
                       (flags.dsc_src_support << 12) | (flags.granularity_needed << 13) |
                       (flags.y_gran_extended_supported << 14) | (flags.link_off_supported << 15))

        self.__write([flags_value, x_granularity.value, y_granularity.value, granularity.combined_value()])
        self.__io.set(TSI_DPRX_HPD_PULSE_W, 500000, c_int)

    def get(self) -> Tuple[PRCapsFlags, PrGranularityCaps, PrGranularityCaps, SuYGranularity]:
        caps = self.__read()

        flags = PRCapsFlags(pr_support=caps.pr_support,
                            selective_update_support=caps.selective_update_support,
                            early_transport_support=caps.early_transport_support,
                            dsc_decode_func_support=caps.dsc_decode_func_support,
                            asynch_video_timing_support=caps.asynch_video_timing_support,
                            dsc_src_support=caps.dsc_src_support,
                            granularity_needed=caps.granularity_needed,
                            y_gran_extended_supported=caps.y_gran_extended_supported,
                            link_off_supported=caps.link_off_supported)

        x_granularity = PrGranularityCaps(caps.pr_x_granularity if caps.pr_x_granularity != 0 else 1)
        y_granularity = PrGranularityCaps(caps.pr_y_granularity if caps.pr_y_granularity != 0 else 1)

        granularity = SuYGranularity(value_of_8=caps.su_y_granularity.value_of_8,
                                     value_of_10=caps.su_y_granularity.value_of_10,
                                     value_of_12=caps.su_y_granularity.value_of_12,
                                     value_of_14=caps.su_y_granularity.value_of_14,
                                     value_of_15=caps.su_y_granularity.value_of_15,
                                     value_of_16=caps.su_y_granularity.value_of_16,
                                     value_of_18=caps.su_y_granularity.value_of_18,
                                     value_of_20=caps.su_y_granularity.value_of_20,
                                     value_of_24=caps.su_y_granularity.value_of_24,
                                     value_of_30=caps.su_y_granularity.value_of_30,
                                     value_of_32=caps.su_y_granularity.value_of_32,
                                     value_of_36=caps.su_y_granularity.value_of_36,
                                     value_of_40=caps.su_y_granularity.value_of_40,
                                     value_of_48=caps.su_y_granularity.value_of_48,
                                     value_of_54=caps.su_y_granularity.value_of_54,
                                     value_of_64=caps.su_y_granularity.value_of_64)

        return flags, x_granularity, y_granularity, granularity

    def __read(self) -> SinkPanelReplayCapsStruct:
        return self.__io.get(TSI_DPRX_PR_CAPS, SinkPanelReplayCapsStruct)[1]

    def __write(self, data: list):
        self.__io.set(TSI_DPRX_PR_CAPS, data, data_type=c_uint32, data_count=len(data))


class SinkPanelSelfRefreshCaps:
    """
    Class `SinkPanelSelfRefreshCaps` contains information about Sink Panel Self Refresh capabilities.
    - Set configuration with parameters: `PSRCapsFlags`, `PrGranularityCaps`, PrGranularityCaps`. Function `set`.
    - Get configuration: Tuple[`PSRCapsFlags`, `PrGranularityCaps`, `PrGranularityCaps`]. Function `get`.
    """

    def __init__(self, port_io: PortIO):
        self.__io = port_io

    def set(self, flags: PSRCapsFlags = PSRCapsFlags(),
            x_granularity: PrGranularityCaps = PrGranularityCaps.Line_1,
            y_granularity: PrGranularityCaps = PrGranularityCaps.Line_1):
        flags_value = (flags.psr_caps.value | (flags.link_training_req_psr1 << 8) | (flags.psr_setup_time.value << 9) |
                       (flags.y_coor_psr2_su << 12) | (flags.su_coordinates_shall_adhere << 13) |
                       (flags.no_update_aux_frame_sync << 14))

        self.__write([flags_value, x_granularity.value, y_granularity.value])

    def get(self) -> Tuple[PSRCapsFlags, PrGranularityCaps, PrGranularityCaps]:
        caps = self.__read()

        flags = PSRCapsFlags(psr_caps=PSRCaps(caps.psr_caps),
                             link_training_req_psr1=caps.link_training_req_psr1,
                             psr_setup_time=PSRSetupTime(caps.psr_setup_time), y_coor_psr2_su=caps.y_coor_psr2_su,
                             su_coordinates_shall_adhere=caps.su_coordinates_shall_adhere,
                             no_update_aux_frame_sync=caps.no_update_aux_frame_sync)

        x_granularity = PrGranularityCaps(caps.pr_x_granularity if caps.pr_x_granularity != 0 else 1)
        y_granularity = PrGranularityCaps(caps.pr_y_granularity if caps.pr_y_granularity != 0 else 1)

        return flags, x_granularity, y_granularity

    def __read(self) -> SinkPanelSelfRefreshCapsStruct:
        return self.__io.get(TSI_DPRX_PSR_CAPS, SinkPanelSelfRefreshCapsStruct)[1]

    def __write(self, data: list):
        self.__io.set(TSI_DPRX_PSR_CAPS, data, data_type=c_uint32, data_count=len(data))