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 UsbcElTestDutCaps(Param):
    """
    Class `UsbcElTestDutCaps` describes DUT capabilities flags and allows settings values.
    - DUT Support DisplayPort Alternate mode `support_dp_alt_mode`.
    - DUT can act as a power source `can_act_power_source`
    - DUT can act as a power sink `cab_act_power_sink`.
    - DUT does not support PD Contract `not_support_pd_contract`.
    """
    def __init__(self, json_obj):
        super().__init__(json_obj)

    @property
    def support_dp_alt_mode(self):
        """
        Set and get DUT Support DisplayPort Alternate mode flag support.

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

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

    @property
    def can_act_power_source(self):
        """
        Set and get DUT can act as a power source flag support.

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

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

    @property
    def cab_act_power_sink(self):
        """
        Set and get DUT can act as a power sink flag support.

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

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

    @property
    def not_support_pd_contract(self):
        """
        Set and get DUT does not support PD Contract flag support.

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

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


class UsbcElectricalTestParam:
    """
    Class `DpElectricalTestParam` describes parameters for DP electrical tests.
    - Test timeout, in milliseconds `timeout`.
    - Defines DUT capabilities `dut_caps` type `UsbcElTestDutCaps`.
    - Defines the time period for USB Type-C re-plug simulation 'disconnected' state `re_plug_time`.
    - Defines the time period that the TE will wait for DUT to complete power contract negotiation `attach_timeout`.
    - Defines Power Contract timeout, in milliseconds `pwr_contract_timeout`.
    - Defines the low limit for the voltage window when power sink current is 0.5A or 0.9A `cc_low_voltage_1 `.
    - Defines the high limit for the voltage window when power sink current is 0.5A or 0.9A `cc_high_voltage_1`.
    - Defines the low limit for the voltage window when power sink current is 1.5A `cc_low_voltage_2`.
    - Defines the high limit for the voltage window when power sink current is 1.5A `cc_high_voltage_2`.
    - Defines the low limit for the voltage window when power sink current is 3.0A `cc_low_voltage_3`.
    - Defines the high limit for the voltage window when power sink current is 3.0A `cc_high_voltage_3`.
    - Defines the low limit for the Vcon voltage window `vconn_low_voltage`.
    - Defines the high limit for the Vcon voltage window `vconn_high_voltage`.
    - Defines the timeout the TE will wait for the DUT to enter into DisplayPort alternate mode `dp_alt_mode_timeout`.
    - Defines the low voltage limit for the positive DP AUX line when idle `aux_positive_idle_low_voltage`.
    - Defines the high voltage limit for the positive DP AUX line when idle `aux_positive_idle_high_voltage`.
    - Defines the low voltage limit for the negative DP AUX line when idle `aux_negative_idle_low_voltage`.
    - Defines the high voltage limit for the negative DP AUX line when idle `aux_negative_idle_high_voltage`.
    - Defines the low limit for Vbus voltage window. The limit is defined in millivolts (mV) `vbus_low_voltage`.
    - Defines the high limit for Vbus voltage window. The limit is defined in millivolts (mV) `vbus_high_voltage`.
    - Defines the highest allowed deviation between maximum and minimum currents measured from the individual Vbus
    pins as per-mill (‰) of total measured current. This means that if the total measured current is 3000mA, and the
    setting 100, the maximum difference that is allowed between maximum and minimum currents is 300mA
    `vbus_current_max`.
    - Defines the highest allowed deviation between maximum and minimum currents measured from the individual GND pins
    as per-mill (‰) of total measured current `gnd_current_max`.
    - Defines delay from end of power contract negotiation to voltage / current measurements `power_measure_delay`.
    - Defines the minimum current, in mA, that a Power Sink DUT must use in order to pass the test `min_dut_current`.
    - Delay after load resistor on, milliseconds. This helps to skip transient processes `resistor_on_delay`.
    - Delay for measure CC lines voltage after DUT plug detection, milliseconds `cc_measure_delay`.
    """
    def __init__(self, json_obj):
        self.__timeout = Param(json_obj["TSI_USBC_EL_TIMEOUT"])
        self.__dut_caps = UsbcElTestDutCaps(json_obj["TSI_USBC_EL_DUT_CAPS"])
        self.__re_plug_time = Param(json_obj["TSI_USBC_EL_REPLUG_TIME"])
        self.__attach_timeout = Param(json_obj["TSI_USBC_EL_DUT_ATTACH_TIMEOUT"])
        self.__pwr_contract_timeout = Param(json_obj["TSI_USBC_EL_PWR_CONTRACT_TIMEOUT"])
        self.__cc_low_voltage_1 = Param(json_obj["TSI_USBC_EL_CC_LOW_VOLTAGE_1"])
        self.__cc_high_voltage_1 = Param(json_obj["TSI_USBC_EL_CC_HI_VOLTAGE_1"])
        self.__cc_low_voltage_2 = Param(json_obj["TSI_USBC_EL_CC_LOW_VOLTAGE_2"])
        self.__cc_high_voltage_2 = Param(json_obj["TSI_USBC_EL_CC_HI_VOLTAGE_2"])
        self.__cc_low_voltage_3 = Param(json_obj["TSI_USBC_EL_CC_LOW_VOLTAGE_3"])
        self.__cc_high_voltage_3 = Param(json_obj["TSI_USBC_EL_CC_HI_VOLTAGE_3"])
        self.__vconn_low_voltage = Param(json_obj["TSI_USBC_EL_VCON_LOW_VOLTAGE"])
        self.__vconn_high_voltage = Param(json_obj["TSI_USBC_EL_VCON_HI_VOLTAGE"])
        self.__dp_alt_mode_timeout = Param(json_obj["TSI_USBC_EL_DP_ALT_TIMEOUT"])
        self.__aux_positive_idle_low_voltage = Param(json_obj["TSI_USBC_EL_AUX_P_IDLE_LOW_VOLTAGE"])
        self.__aux_positive_idle_high_voltage = Param(json_obj["TSI_USBC_EL_AUX_P_IDLE_HI_VOLTAGE"])
        self.__aux_negative_idle_low_voltage = Param(json_obj["TSI_USBC_EL_AUX_N_IDLE_LOW_VOLTAGE"])
        self.__aux_negative_idle_high_voltage = Param(json_obj["TSI_USBC_EL_AUX_N_IDLE_HI_VOLTAGE"])
        self.__vbus_low_voltage = Param(json_obj["TSI_USBC_EL_VBUS_LOW_VOLTAGE"])
        self.__vbus_high_voltage = Param(json_obj["TSI_USBC_EL_VBUS_HI_VOLTAGE"])
        self.__vbus_current_max = Param(json_obj["TSI_USBC_EL_VBUS_CURRENT_MAX_DEV"])
        self.__gnd_current_max = Param(json_obj["TSI_USBC_EL_GND_CURRENT_MAX_DEV"])
        self.__power_measure_delay = Param(json_obj["TSI_USBC_EL_PWR_MEASURE_DELAY"])
        self.__min_dut_current = Param(json_obj["TSI_USBC_EL_MIN_DUT_CURRENT"])
        self.__resistor_on_delay = Param(json_obj["TSI_USBC_EL_RES_ON_DELAY"])
        self.__cc_measure_delay = Param(json_obj["TSI_USBC_EL_CC_MEASURE_DELAY"])

    @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 dut_caps(self) -> UsbcElTestDutCaps:
        """
        Set and get USB-C DUT caps.

        Returns:
            object of `UsbcElTestDutCaps` type
        """
        return self.__dut_caps

    @dut_caps.setter
    def dut_caps(self, dut_caps: UsbcElTestDutCaps):
        self.__dut_caps = dut_caps

    @property
    def pwr_contract_timeout(self) -> int:
        """
        Set and get power contract timeout.

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

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

    @property
    def cc_low_voltage_1(self) -> int:
        """
        Set and get low limit for the voltage window when power sink current is 0.5A or 0.9A.

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

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

    @property
    def cc_high_voltage_1(self) -> int:
        """
        Set and get high limit for the voltage window when power sink current is 0.5A or 0.9A.

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

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

    @property
    def cc_low_voltage_2(self) -> int:
        """
        Set and get low limit for the voltage window when power sink current is 1.5A.

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

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

    @property
    def cc_high_voltage_2(self) -> int:
        """
        Set and get high limit for the voltage window when power sink current is 1.5A.

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

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

    @property
    def cc_low_voltage_3(self) -> int:
        """
        Set and get low limit for the voltage window when power sink current is 3.0A.

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

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

    @property
    def cc_high_voltage_3(self):
        """
        Set and get high limit for the voltage window when power sink current is 3.0A.

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

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

    @property
    def vconn_low_voltage(self) -> int:
        """
        Set and get low limit for the Vcon voltage window.

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

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

    @property
    def vconn_high_voltage(self) -> int:
        """
        Set and get high limit for the Vcon voltage window.

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

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

    @property
    def dp_alt_mode_timeout(self) -> int:
        """
        Set and get DP alt mode timeout.

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

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

    @property
    def aux_positive_idle_low_voltage(self) -> int:
        """
        Set and get low voltage limit for the positive DP AUX.

        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 high voltage limit for the positive DP AUX.

        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 low voltage limit for the negative DP AUX.

        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 high voltage limit for the negative DP AUX.

        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 vbus_low_voltage(self) -> int:
        """
        Set and get low limit for Vbus voltage window.

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

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

    @property
    def vbus_high_voltage(self) -> int:
        """
        Set and get high limit for Vbus voltage window.

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

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

    @property
    def vbus_current_max(self) -> int:
        """
        Set and get the highest allowed deviation of current VBUS.

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

    @vbus_current_max.setter
    def vbus_current_max(self, vbus_current_max: int):
        if not(self.__vbus_current_max.min_value < vbus_current_max < self.__vbus_current_max.max_value):
            raise ValueError(f"VBUS current max cannot be less than {self.__vbus_current_max.min_value} "
                             f"and more than {self.__vbus_current_max.max_value}")
        self.__vbus_current_max.default_value = vbus_current_max

    @property
    def gnd_current_max(self) -> int:
        """
        Set and get the highest allowed deviation of current GND.

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

    @gnd_current_max.setter
    def gnd_current_max(self, gnd_current_max: int):
        if not(self.__gnd_current_max.min_value < gnd_current_max < self.__gnd_current_max.max_value):
            raise ValueError(f"GND current max cannot be less than {self.__gnd_current_max.min_value} "
                             f"and more than {self.__gnd_current_max.max_value}")
        self.__gnd_current_max.default_value = gnd_current_max

    @property
    def power_measure_delay(self) -> int:
        """
        Set and get delay from end of power contract negotiation to voltage / current measurements.

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

    @power_measure_delay.setter
    def power_measure_delay(self, power_measure_delay: int):
        if not(self.__power_measure_delay.min_value < power_measure_delay < self.__power_measure_delay.max_value):
            raise ValueError(f"Power measure delay cannot be less than {self.__power_measure_delay.min_value} "
                             f"and more than {self.__power_measure_delay.max_value}")
        self.__power_measure_delay.default_value = power_measure_delay

    @property
    def min_dut_current(self) -> int:
        """
        Set and get the minimum current.

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

    @min_dut_current.setter
    def min_dut_current(self, min_dut_current: int):
        if not(self.__min_dut_current.min_value < min_dut_current < self.__min_dut_current.max_value):
            raise ValueError(f"Minimum current on DUT cannot be less than {self.__min_dut_current.min_value} "
                             f"and more than {self.__min_dut_current.max_value}")
        self.__min_dut_current.default_value = min_dut_current

    @property
    def resistor_on_delay(self) -> int:
        """
        Set and get delay after load resistor.

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

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

    @property
    def cc_measure_delay(self) -> int:
        """
        Set and get delay for measure CC lines voltage after DUT plug detection.

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

    @cc_measure_delay.setter
    def cc_measure_delay(self, cc_measure_delay: int):
        if not(self.__cc_measure_delay.min_value < cc_measure_delay < self.__cc_measure_delay.max_value):
            raise ValueError(f"CC measure delay cannot be less than {self.__cc_measure_delay.min_value} "
                             f"and more than {self.__cc_measure_delay.max_value}")
        self.__cc_measure_delay.default_value = cc_measure_delay
