from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
from UniTAP.dev.modules.dut_tests.test_utils import update_default_value


class DpDutTaCaps(Param):
    """
    Class `DpDutTaCaps` describes DUT Test automation capabilities flags and allows settings values.
    - DUT is capable for test link training `dut_capable_link_training`.
    - DUT is capable for test video pattern `dut_capable_video_pattern`
    - DUT is capable for test EDID read `dut_capable_edid_read`.
    """
    def __init__(self, json_obj):
        super().__init__(json_obj)

    @property
    def dut_capable_link_training(self) -> bool:
        """
        Set and get DUT is capable for test link training flag support.

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

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

    @property
    def dut_capable_video_pattern(self) -> bool:
        """
        Set and get DUT is capable for test video pattern flag support.

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

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

    @property
    def dut_capable_edid_read(self) -> bool:
        """
        Set and get DUT is capable for test EDID read flag support.

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

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


class DpElectricalTestParam:
    """
    Class `DpElectricalTestParam` describes parameters for DP electrical tests.
    - Test timeout, in milliseconds `timeout`.
    - Main link low voltage limit, mV `links_low_voltage`.
    - Main link high voltage limit, mV `links_high_voltage`.
    - HPD line logical zero low voltage level limit, mV `hpd_zero_low_voltage`.
    - HPD line logical zero high voltage level limit, mV `hpd_zero_high_voltage`.
    - HPD line logical one low voltage level limit, mV `hpd_one_low_voltage`.
    - HPD line logical one high voltage level limit, mV `hpd_one_high_voltage`.
    - AUX + line idle low voltage level limit, mV `aux_positive_idle_low_voltage`.
    - AUX + line idle high voltage level limit, mV `aux_positive_idle_high_voltage`.
    - AUX - line idle low voltage level limit, mV `aux_negative_idle_low_voltage`.
    - AUX - line idle high voltage level limit, mV `aux_negative_idle_high_voltage`.
    - AUX + line signal trigger level, mV `aux_positive_trig_voltage`.
    - AUX - line signal trigger level, mV `aux_negative_trig_voltage`.
    - AUX signal capture timeout, milliseconds `aux_signal_capture_timeout`.
    - AUX signal capture attempts, times `aux_signal_capture_count`.
    - Maximum lanes count supported by DUT `dut_max_lanes`.
    - Maximum data rate supported by DUT in 0.27Gbps `dut_max_link_rate`.
    - DUT Test automation capabilities flags `dut_ta_caps` type `DpDutTaCaps`.
    """
    def __init__(self, json_obj):
        self.__timeout = Param(json_obj["TSI_DP_RX_TEST_TIMEOUT"])
        self.__links_low_voltage = Param(json_obj["TSI_DP_RX_LINKS_LOW_VOLTAGE"])
        self.__links_high_voltage = Param(json_obj["TSI_DP_RX_LINKS_HI_VOLTAGE"])
        self.__hpd_zero_low_voltage = Param(json_obj["TSI_DP_RX_HPD_ZERO_LOW_VOLTAGE"])
        self.__hpd_zero_high_voltage = Param(json_obj["TSI_DP_RX_HPD_ZERO_HI_VOLTAGE"])
        self.__hpd_one_low_voltage = Param(json_obj["TSI_DP_RX_HPD_ONE_LOW_VOLTAGE"])
        self.__hpd_one_high_voltage = Param(json_obj["TSI_DP_RX_HPD_ONE_HI_VOLTAGE"])
        self.__aux_positive_idle_low_voltage = Param(json_obj["TSI_DP_RX_AUX_P_IDLE_LOW_VOLTAGE"])
        self.__aux_positive_idle_high_voltage = Param(json_obj["TSI_DP_RX_AUX_P_IDLE_HI_VOLTAGE"])
        self.__aux_negative_idle_low_voltage = Param(json_obj["TSI_DP_RX_AUX_N_IDLE_LOW_VOLTAGE"])
        self.__aux_negative_idle_high_voltage = Param(json_obj["TSI_DP_RX_AUX_N_IDLE_HI_VOLTAGE"])
        self.__aux_positive_trig_voltage = Param(json_obj["TSI_DP_RX_AUX_P_TRIG_VOLTAGE"])
        self.__aux_negative_trig_voltage = Param(json_obj["TSI_DP_RX_AUX_N_TRIG_VOLTAGE"])
        self.__aux_signal_capture_timeout = Param(json_obj["TSI_DP_RX_AUX_SIGNAL_CAPT_TIMEOUT"])
        self.__aux_signal_capture_count = Param(json_obj["TSI_DP_RX_AUX_SIGNAL_CAPT_TRIES"])
        self.__dut_max_lanes = Param(json_obj["TSI_DP_RX_MAX_DUT_MAX_LANES"])
        self.__dut_max_link_rate = Param(json_obj["TSI_DP_RX_MAX_DUT_LANE_RATE"])
        self.__unused_dut_caps_flag = Param(json_obj["TSI_DP_RX_DUT_CAPS"])
        self.__dut_ta_caps = DpDutTaCaps(json_obj["TSI_DP_RX_DUT_TA_CAPS"])

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

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

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

    @property
    def links_low_voltage(self) -> int:
        """
        Set and get Main link low voltage limit.

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

    @links_low_voltage.setter
    def links_low_voltage(self, links_low_voltage: int):
        if not(self.__links_low_voltage.min_value < links_low_voltage < self.__links_low_voltage.max_value):
            raise ValueError(f"Links low voltage cannot be less than {self.__links_low_voltage.min_value} and more than"
                             f" {self.__links_low_voltage.max_value}.")
        self.__links_low_voltage.default_value = links_low_voltage

    @property
    def links_high_voltage(self) -> int:
        """
        Set and get Main link high voltage limit.

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

    @links_high_voltage.setter
    def links_high_voltage(self, links_high_voltage: int):
        if not(self.__links_high_voltage.min_value < links_high_voltage < self.__links_high_voltage.max_value):
            raise ValueError(f"Links high voltage cannot be less than {self.__links_high_voltage.min_value} "
                             f"and more than {self.__links_high_voltage.max_value}.")
        self.__links_high_voltage.default_value = links_high_voltage

    @property
    def hpd_zero_low_voltage(self) -> int:
        """
        Set and get HPD line logical zero low voltage level limit.

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

    @hpd_zero_low_voltage.setter
    def hpd_zero_low_voltage(self, hpd_zero_low_voltage: int):
        if not(self.__hpd_zero_low_voltage.min_value < hpd_zero_low_voltage < self.__hpd_zero_low_voltage.max_value):
            raise ValueError(f"HDP zero low voltage cannot be less than {self.__hpd_zero_low_voltage.min_value} "
                             f"and more than {self.__hpd_zero_low_voltage.max_value}.")
        self.__hpd_zero_low_voltage.default_value = hpd_zero_low_voltage

    @property
    def hpd_zero_high_voltage(self) -> int:
        """
        Set and get HPD line logical zero high voltage level limit.

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

    @hpd_zero_high_voltage.setter
    def hpd_zero_high_voltage(self, hpd_zero_high_voltage: int):
        if not(self.__hpd_zero_high_voltage.min_value < hpd_zero_high_voltage < self.__hpd_zero_high_voltage.max_value):
            raise ValueError(f"HDP zero high voltage cannot be less than {self.__hpd_zero_high_voltage.min_value} "
                             f"and more than {self.__hpd_zero_high_voltage.max_value}.")
        self.__hpd_zero_high_voltage.default_value = hpd_zero_high_voltage

    @property
    def hpd_one_low_voltage(self) -> int:
        """
        Set and get HPD line logical one low voltage level limit.

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

    @hpd_one_low_voltage.setter
    def hpd_one_low_voltage(self, hpd_one_low_voltage: int):
        if not(self.__hpd_one_low_voltage.min_value < hpd_one_low_voltage < self.__hpd_one_low_voltage.max_value):
            raise ValueError(f"HDP one low voltage cannot be less than {self.__hpd_one_low_voltage.min_value} "
                             f"and more than {self.__timeout.max_value}.")
        self.__hpd_one_low_voltage.default_value = hpd_one_low_voltage

    @property
    def hpd_one_high_voltage(self) -> int:
        """
        Set and get HPD line logical one high voltage level limit.

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

    @hpd_one_high_voltage.setter
    def hpd_one_high_voltage(self, hpd_one_high_voltage: int):
        if not(self.__hpd_one_high_voltage.min_value < hpd_one_high_voltage < self.__hpd_one_high_voltage.max_value):
            raise ValueError(f"HDP one high voltage cannot be less than {self.__hpd_one_high_voltage.min_value} "
                             f"and more than {self.__hpd_one_high_voltage.max_value}.")
        self.__hpd_one_high_voltage.default_value = hpd_one_high_voltage

    @property
    def aux_positive_idle_low_voltage(self) -> int:
        """
        Set and get AUX + line idle low voltage level limit.

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

    @aux_positive_idle_low_voltage.setter
    def aux_positive_idle_low_voltage(self, aux_positive_idle_low_voltage: int):
        if not(self.__aux_positive_idle_low_voltage.min_value < aux_positive_idle_low_voltage <
               self.__aux_positive_idle_low_voltage.max_value):
            raise ValueError(f"AUX positive IDLE low voltage cannot be less than "
                             f"{self.__aux_positive_idle_low_voltage.min_value} and more than "
                             f"{self.__aux_positive_idle_low_voltage.max_value}.")
        self.__aux_positive_idle_low_voltage.default_value = aux_positive_idle_low_voltage

    @property
    def aux_positive_idle_high_voltage(self) -> int:
        """
        Set and get AUX + line idle high voltage level limit.

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

    @aux_positive_idle_high_voltage.setter
    def aux_positive_idle_high_voltage(self, aux_positive_idle_high_voltage: int):
        if not(self.__aux_positive_idle_high_voltage.min_value < aux_positive_idle_high_voltage <
               self.__aux_positive_idle_high_voltage.max_value):
            raise ValueError(f"AUX positive IDLE high voltage cannot be less than "
                             f"{self.__aux_positive_idle_high_voltage.min_value} and more than "
                             f"{self.__aux_positive_idle_high_voltage.max_value}.")
        self.__aux_positive_idle_high_voltage.default_value = aux_positive_idle_high_voltage

    @property
    def aux_negative_idle_low_voltage(self) -> int:
        """
        Set and get AUX - line idle low voltage level limit.

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

    @aux_negative_idle_low_voltage.setter
    def aux_negative_idle_low_voltage(self, aux_negative_idle_low_voltage: int):
        if not(self.__aux_negative_idle_low_voltage.min_value < aux_negative_idle_low_voltage <
               self.__aux_negative_idle_low_voltage.max_value):
            raise ValueError(f"AUX negative IDLE low voltage cannot be less than "
                             f"{self.__aux_negative_idle_low_voltage.min_value} and more than "
                             f"{self.__aux_negative_idle_low_voltage.max_value}.")
        self.__aux_negative_idle_low_voltage.default_value = aux_negative_idle_low_voltage

    @property
    def aux_negative_idle_high_voltage(self) -> int:
        """
        Set and get AUX - line idle high voltage level limit.

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

    @aux_negative_idle_high_voltage.setter
    def aux_negative_idle_high_voltage(self, aux_negative_idle_high_voltage: int):
        if not(self.__aux_negative_idle_high_voltage.min_value < aux_negative_idle_high_voltage <
               self.__aux_negative_idle_high_voltage.max_value):
            raise ValueError(f"AUX negative IDLE high voltage cannot be less than "
                             f"{self.__aux_negative_idle_high_voltage.min_value} and more than "
                             f"{self.__aux_negative_idle_high_voltage.max_value}.")
        self.__aux_negative_idle_high_voltage.default_value = aux_negative_idle_high_voltage

    @property
    def aux_positive_trig_voltage(self) -> int:
        """
        Set and get AUX + line signal trigger level.

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

    @aux_positive_trig_voltage.setter
    def aux_positive_trig_voltage(self, aux_positive_trig_voltage: int):
        if not(self.__aux_positive_trig_voltage.min_value < aux_positive_trig_voltage <
               self.__aux_positive_trig_voltage.max_value):
            raise ValueError(f"AUX positive trig voltage cannot be less than "
                             f"{self.__aux_positive_trig_voltage.min_value} and more than "
                             f"{self.__aux_positive_trig_voltage.max_value}.")
        self.__aux_positive_trig_voltage.default_value = aux_positive_trig_voltage

    @property
    def aux_negative_trig_voltage(self) -> int:
        """
        Set and get AUX - line signal trigger level.

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

    @aux_negative_trig_voltage.setter
    def aux_negative_trig_voltage(self, aux_negative_trig_voltage: int):
        if not(self.__aux_negative_trig_voltage.min_value < aux_negative_trig_voltage <
               self.__aux_negative_trig_voltage.max_value):
            raise ValueError(f"AUX negative trig voltage cannot be less than "
                             f"{self.__aux_negative_trig_voltage.min_value} and more than "
                             f"{self.__aux_negative_trig_voltage.max_value}.")
        self.__aux_negative_trig_voltage.default_value = aux_negative_trig_voltage

    @property
    def aux_signal_capture_timeout(self) -> int:
        """
        Set and get AUX signal capture timeout, milliseconds.

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

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

    @property
    def aux_signal_capture_count(self) -> int:
        """
        Set and get AUX signal capture attempts.

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

    @aux_signal_capture_count.setter
    def aux_signal_capture_count(self, aux_signal_capture_count: int):
        if not(self.__aux_signal_capture_count.min_value < aux_signal_capture_count <
               self.__aux_signal_capture_count.max_value):
            raise ValueError(f"AUX signal capture count cannot be less than "
                             f"{self.__aux_signal_capture_count.min_value} and more than "
                             f"{self.__aux_signal_capture_count.max_value}.")
        self.__aux_signal_capture_count.default_value = aux_signal_capture_count

    @property
    def dut_max_lanes(self) -> int:
        """
        Set and get Maximum lanes count supported by DUT.

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

    @dut_max_lanes.setter
    def dut_max_lanes(self, dut_max_lanes: int):
        if not(self.__dut_max_lanes.min_value < dut_max_lanes < self.__dut_max_lanes.max_value):
            raise ValueError(f"DUT max lanes cannot be less than {self.__dut_max_lanes.min_value} and more than "
                             f"{self.__dut_max_lanes.max_value}.")
        self.__dut_max_lanes.default_value = dut_max_lanes

    @property
    def dut_max_link_rate(self) -> int:
        """
        Set and get Maximum data rate supported by DUT in 0.27Gbps.

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

    @dut_max_link_rate.setter
    def dut_max_link_rate(self, dut_max_link_rate: int):
        if not(self.__dut_max_link_rate.min_value < dut_max_link_rate < self.__dut_max_link_rate.max_value):
            raise ValueError(f"DUT max link rate cannot be less than {self.__dut_max_link_rate.min_value} and more than "
                             f"{self.__dut_max_link_rate.max_value}.")
        self.__dut_max_link_rate.default_value = dut_max_link_rate

    @property
    def dut_ta_caps(self):
        """
        Set and get DUT Test automation capabilities flags.

        Returns:
            object DpDutTaCaps
        """
        return self.__dut_ta_caps

    @dut_ta_caps.setter
    def dut_ta_caps(self, dut_ta_caps: DpDutTaCaps):
        self.__dut_ta_caps = dut_ta_caps
