from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
from .hdmi_sink_tests import HdmiFrlRate
from enum import IntEnum


class CableTestMode(IntEnum):
    HighSpeed = 0
    LowSpeed = 1
    All = 2


class LowSpeedLineSelection(Param):
    """
    Class `LowSpeedLineSelection` defines variants of tests:
    - Voltage swing level 3 (1.2V) supported `voltage_swing_supported`.
    - Pre-emphasis level 3 (9.5dB) supported `pre_emphasis_supported`.

    """
    def __init__(self, json_obj):
        super().__init__(json_obj)

    @property
    def hpd(self) -> bool:
        """
        Configure if HPD line will be tested.

        Returns:
            object of bool type
        """
        return self._get_by_bitmask(0, bool)

    @hpd.setter
    def hpd(self, hpd_test: bool):
        self._set_by_bitmask(hpd_test, 0)

    @property
    def i2c(self) -> bool:
        """
        Configure if I2C line will be tested.

        Returns:
            object of bool type
        """
        return self._get_by_bitmask(1, bool)

    @i2c.setter
    def i2c(self, i2c_test: bool):
        self._set_by_bitmask(i2c_test, 1)

    @property
    def cec(self) -> bool:
        """
        Configure if CEC line will be tested.

        Returns:
            object of bool type
        """
        return self._get_by_bitmask(2, bool)

    @cec.setter
    def cec(self, cec_test: bool):
        self._set_by_bitmask(cec_test, 2)

    @property
    def voltage_5v(self) -> bool:
        """
        Configure if 5V line will be tested.

        Returns:
            object of bool type
        """
        return self._get_by_bitmask(3, bool)

    @voltage_5v.setter
    def voltage_5v(self, voltage_5v_test: bool):
        self._set_by_bitmask(voltage_5v_test, 3)

    @property
    def utility(self) -> bool:
        """
        Configure if utility line will be tested.

        Returns:
            object of bool type
        """
        return self._get_by_bitmask(4, bool)

    @utility.setter
    def utility(self, utility_test: bool):
        self._set_by_bitmask(utility_test, 4)


class HdmiSinkCableCheckTestParam:
    """
    Class `HdmiSinkDUTTestParam` allows working with parameters from HDMI DSC source part.
    - Set and get test timeout `test_timeout`.
    - Seg and get test mode `test_mode` type `CableTestMode`.
    - Set and get MIN FRL rate `min_frl_rate` type `HdmiFrlRate`.
    - Set and get MAX FRL rate `max_frl_rate` type `HdmiFrlRate`.
    - Set and get amount of allowed errors per lane `allowed_errors_per_lane`.
    - Set and get errors capture timeout `errors_capture_timeout `.
    """
    def __init__(self, json_obj):
        self.__test_timeout = Param(json_obj["TSI_HDMI_SNKCTS_CABLE_TIMEOUT"])
        self.__test_mode = Param(json_obj["TSI_HDMI_SNKCTS_CABLE_TEST_MODE"])
        self.__min_frl_rate = Param(json_obj["TSI_HDMI_SNKCTS_CABLE_MIN_FRL_RATE"])
        self.__max_frl_rate = Param(json_obj["TSI_HDMI_SNKCTS_CABLE_MAX_FRL_RATE"])
        self.__allowed_errors_per_lane = Param(json_obj["TSI_HDMI_SNKCTS_CABLE_ERROR_PER_LANE"])
        self.__errors_capture_timeout = Param(json_obj["TSI_HDMI_SNKCTS_CABLE_CAPTURE_TIMEOUT"])
        self.__low_speed_line_selection = LowSpeedLineSelection(json_obj["TSI_HDMI_SNKCTS_CABLE_LOW_SPEED_LINE"])

    @property
    def test_timeout(self) -> int:
        """
        Set and get test timeout, in seconds.

        Returns:
            object of int type
        """
        return self.__test_timeout.default_value

    @test_timeout.setter
    def test_timeout(self, test_timeout: int):
        if not(self.__test_timeout.min_value < test_timeout < self.__test_timeout.max_value):
            raise ValueError(f"Test timeout cannot be less than {self.__test_timeout.min_value} and more than "
                             f"{self.__test_timeout.max_value}.")
        self.__test_timeout.default_value = test_timeout

    @property
    def test_mode(self) -> CableTestMode:
        """
        Set and get test mode.

        Returns:
            object of `CableTestMode` type
        """
        return CableTestMode(self.__test_mode.default_value)

    @test_mode.setter
    def test_mode(self, test_mode: CableTestMode):
        self.__test_mode.default_value = test_mode.value

    @property
    def min_frl_rate(self) -> HdmiFrlRate:
        """
        Set and get the minimum FRL rate supported by the cable.

        Returns:
            object of `HdmiFrlRate` type
        """
        return HdmiFrlRate(self.__min_frl_rate.default_value)

    @min_frl_rate.setter
    def min_frl_rate(self, min_frl_rate: HdmiFrlRate):
        self.__min_frl_rate.default_value = min_frl_rate.value

    @property
    def max_frl_rate(self) -> HdmiFrlRate:
        """
        Set and get the maximum FRL rate supported by the cable.

        Returns:
            object of `HdmiFrlRate` type
        """
        return HdmiFrlRate(self.__max_frl_rate.default_value)

    @max_frl_rate.setter
    def max_frl_rate(self, max_frl_rate: HdmiFrlRate):
        self.__max_frl_rate.default_value = max_frl_rate.value

    @property
    def allowed_errors_per_lane(self) -> int:
        """
        Set and get allowed errors per lane.

        Returns:
            object of int type
        """
        return self.__allowed_errors_per_lane.default_value

    @allowed_errors_per_lane.setter
    def allowed_errors_per_lane(self, allowed_errors_per_lane: int):
        if not(self.__allowed_errors_per_lane.min_value < allowed_errors_per_lane < self.__allowed_errors_per_lane.max_value):
            raise ValueError(f"Amount of allowed errors per lane cannot be less than {self.__allowed_errors_per_lane.min_value} and more than "
                             f"{self.__allowed_errors_per_lane.max_value}.")
        self.__allowed_errors_per_lane.default_value = allowed_errors_per_lane

    @property
    def errors_capture_timeout(self) -> int:
        """
        Set and get errors capture timeout, in seconds.

        Returns:
            object of int type
        """
        return self.__errors_capture_timeout.default_value

    @errors_capture_timeout.setter
    def errors_capture_timeout(self, errors_capture_timeout: int):
        if not(self.__errors_capture_timeout.min_value < errors_capture_timeout < self.__errors_capture_timeout.max_value):
            raise ValueError(f"Errors capture timeout cannot be less than {self.__errors_capture_timeout.min_value} and more than "
                             f"{self.__errors_capture_timeout.max_value}.")
        self.__errors_capture_timeout.default_value = errors_capture_timeout

    @property
    def low_speed_line_selection(self) -> LowSpeedLineSelection:
        """
        Set and get low speed lines for testing.

        Returns:
            object `LowSpeedLineSelection`
        """
        return self.__low_speed_line_selection

    @low_speed_line_selection.setter
    def low_speed_line_selection(self, low_speed_line_selection: LowSpeedLineSelection):
        self.__low_speed_line_selection = low_speed_line_selection
