from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
from UniTAP.dev.modules.dut_tests.test_utils import update_default_value
from UniTAP.common import AudioFormat
from typing import TypeVar

_dict_sample_rate = {
    1: 32000,
    2: 44100,
    3: 48000,
    4: 88200,
    5: 96000,
    6: 176400,
    7: 192000
}

_rev_dict_sample_rate = {
    32000: 1,
    44100: 2,
    48000: 3,
    88200: 4,
    96000: 5,
    176400: 6,
    192000: 7
}

_dict_sample_size = {
    1: 16,
    2: 20,
    3: 24
}

_rev_dict_sample_size = {
    16: 1,
    20: 2,
    24: 3
}

_dict_audio_type = {
    1: AudioFormat.L_PCM
}

_rev_dict_audio_type = {
    AudioFormat.L_PCM: 1
}


class AudioMode:
    """
    Class `AudioMode` describes audio mode for Display ID tests. Allows working with audio mode parameters.
    - Set and get channel count `channel_count`.
    - Set and get sample size `sample_size`.
    - Set and get sample rate `sample_rate`.
    - Set and get audio type `audio_type`.
    """

    def __init__(self, json_obj):
        self.__value = Param(json_obj)

    def clear(self):
        """
        Disable audio mode.
        """
        self.__value.clear()

    @property
    def channel_count(self) -> int:
        """
        Set and get channels count.

        Returns:
            object of int type
        """
        return (self.__value.default_value & 0x7) + 1

    @channel_count.setter
    def channel_count(self, channel_count: int):
        if channel_count >= 9 or channel_count <= 1:
            raise ValueError(f"Channel count must be between 2-8")
        self.__value.default_value &= ~0x7
        self.__value.default_value |= ((channel_count - 1) & 0x7)

    @property
    def sample_size(self) -> int:
        """
        Set and get sample size.

        Returns:
            object of int type
        """
        return _dict_sample_size.get((self.__value.default_value >> 8) & 0x3, 0)

    @sample_size.setter
    def sample_size(self, sample_size: int):
        if sample_size not in [16, 20, 24]:
            raise ValueError(f"Value {sample_size} not in available variants:\n16\n20\n24\n")
        self.__value.default_value &= ~(0x3 << 8)
        self.__value.default_value |= _rev_dict_sample_size.get(sample_size, 0) << 8

    @property
    def sample_rate(self) -> int:
        """
        Set and get sample rate.

        Returns:
            object of int type
        """
        return _dict_sample_rate.get(self.__value.default_value >> 10 & 0x7, 0)

    @sample_rate.setter
    def sample_rate(self, sample_rate: int):
        if _rev_dict_sample_rate.get(sample_rate) is None:
            available_variants = '\n'.join(map(str, _rev_dict_sample_rate.keys()))
            raise ValueError(f"Value {sample_rate} not in available variants:\n{available_variants}")
        self.__value.default_value &= ~(0x7 << 10)
        self.__value.default_value |= _rev_dict_sample_rate.get(sample_rate, 0) << 10

    @property
    def audio_type(self) -> AudioFormat:
        """
        Get audio type.

        Returns:
            object of audio type
        """
        return _dict_audio_type.get(self.__value.default_value >> 4, AudioFormat.Unknown)

    @audio_type.setter
    def audio_type(self, value: AudioFormat):
        """
        Get audio type.

        Returns:
            object of audio type
        """
        if isinstance(value, AudioFormat):
            self.__value.default_value &= ~(0xF << 4)
            self.__value.default_value |= _rev_dict_audio_type.get(value, 0) << 4
        else:
            raise TypeError(f"Incorrect value type {type(value)}. "
                            f"It must be UniTAP.AudioFormat.")


class DisplayIdDpAudioBase:
    def __init__(self, audio_mode_list):
        self._audio_mode_1 = AudioMode(audio_mode_list[0])
        self._audio_mode_2 = AudioMode(audio_mode_list[1])
        self._audio_mode_3 = AudioMode(audio_mode_list[2])
        self._audio_mode_4 = AudioMode(audio_mode_list[3])
        self._audio_mode_5 = AudioMode(audio_mode_list[4])
        self._audio_mode_6 = AudioMode(audio_mode_list[5])
        self._audio_mode_7 = AudioMode(audio_mode_list[6])
        self._audio_mode_8 = AudioMode(audio_mode_list[7])

    @property
    def audio_mode_1(self) -> AudioMode:
        """
        Set and get audio mode 1.

        Returns:
            object of `AudioMode` type
        """
        return self._audio_mode_1

    @audio_mode_1.setter
    def audio_mode_1(self, audio_mode: AudioMode):
        self._audio_mode_1 = audio_mode

    @property
    def audio_mode_2(self) -> AudioMode:
        """
        Set and get audio mode 2.

        Returns:
            object of `AudioMode` type
        """
        return self._audio_mode_2

    @audio_mode_2.setter
    def audio_mode_2(self, audio_mode: AudioMode):
        self._audio_mode_2 = audio_mode

    @property
    def audio_mode_3(self) -> AudioMode:
        """
        Set and get audio mode 3.

        Returns:
            object of `AudioMode` type
        """
        return self._audio_mode_3

    @audio_mode_3.setter
    def audio_mode_3(self, audio_mode: AudioMode):
        self._audio_mode_3 = audio_mode

    @property
    def audio_mode_4(self) -> AudioMode:
        """
        Set and get audio mode 4.

        Returns:
            object of `AudioMode` type
        """
        return self._audio_mode_4

    @audio_mode_4.setter
    def audio_mode_4(self, audio_mode: AudioMode):
        self._audio_mode_4 = audio_mode

    @property
    def audio_mode_5(self) -> AudioMode:
        """
        Set and get audio mode 5.

        Returns:
            object of `AudioMode` type
        """
        return self._audio_mode_5

    @audio_mode_5.setter
    def audio_mode_5(self, audio_mode: AudioMode):
        self._audio_mode_5 = audio_mode

    @property
    def audio_mode_6(self) -> AudioMode:
        """
        Set and get audio mode 6.

        Returns:
            object of `AudioMode` type
        """
        return self._audio_mode_6

    @audio_mode_6.setter
    def audio_mode_6(self, audio_mode: AudioMode):
        self._audio_mode_6 = audio_mode

    @property
    def audio_mode_7(self) -> AudioMode:
        """
        Set and get audio mode 7.

        Returns:
            object of `AudioMode` type
        """
        return self._audio_mode_7

    @audio_mode_7.setter
    def audio_mode_7(self, audio_mode: AudioMode):
        self._audio_mode_7 = audio_mode

    @property
    def audio_mode_8(self) -> AudioMode:
        """
        Set and get audio mode 8.

        Returns:
            object of `AudioMode` type
        """
        return self._audio_mode_8

    @audio_mode_8.setter
    def audio_mode_8(self, audio_mode: AudioMode):
        self._audio_mode_8 = audio_mode

    def clear_all(self):
        """
        Clear all settings.
        """
        self._audio_mode_1.clear()
        self._audio_mode_2.clear()
        self._audio_mode_3.clear()
        self._audio_mode_4.clear()
        self._audio_mode_5.clear()
        self._audio_mode_6.clear()
        self._audio_mode_7.clear()
        self._audio_mode_8.clear()


class DisplayIdDp14Audio(DisplayIdDpAudioBase):
    """
    Class `DisplayIdDp14Audio` contains 8 available audio modes for Display ID tests. Allows settings each mode.
    - Audio mode 1 `audio_mode_1`.
    - Audio mode 2 `audio_mode_2`.
    - Audio mode 3 `audio_mode_3`.
    - Audio mode 4 `audio_mode_4`.
    - Audio mode 5 `audio_mode_5`.
    - Audio mode 6 `audio_mode_6`.
    - Audio mode 7 `audio_mode_7`.
    - Audio mode 8 `audio_mode_8`.
    """

    def __init__(self, json_obj):
        super().__init__([
            json_obj["TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_0"],
            json_obj["TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_1"],
            json_obj["TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_2"],
            json_obj["TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_3"],
            json_obj["TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_4"],
            json_obj["TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_5"],
            json_obj["TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_6"],
            json_obj["TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_7"]
        ])


class DisplayIdDp21Audio(DisplayIdDpAudioBase):
    """
    Class `DisplayIdDp21Audio` inherited of class`DisplayIdDp14Audio` allows working with parameters for Display ID
    LLCTS tests.
    Class `DisplayIdDp21Audio` has all the `DisplayIdDp14Audio` functionality.
    """

    def __init__(self, json_obj):
        super().__init__([
            json_obj["TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_0"],
            json_obj["TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_1"],
            json_obj["TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_2"],
            json_obj["TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_3"],
            json_obj["TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_4"],
            json_obj["TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_5"],
            json_obj["TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_6"],
            json_obj["TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_7"]
        ])


class DmtTiming:
    """
    Class `DmtTiming` describes all available DMT timings for Display ID LLCTS tests. Allows enabling and disable
    timings.
    - 800x600 60Hz `T_800x600_60Hz`.
    - 1024x768 60Hz `T_1024x768_60Hz`.
    - 1280x768 60Hz `T_1280x768_60Hz`.
    - 1280x800 60Hz `T_1280x800_60Hz`.
    - 1280x960 60Hz `T_1280x960_60Hz`.
    - 1280x1024 60Hz `T_1280x1024_60Hz`.
    - 1360x768 60Hz `T_1360x768_60Hz`.
    - 1400x1050 60Hz `T_1400x1050_60Hz`.
    - 1600x1200 60Hz `T_1600x1200_60Hz`.
    - 1680x1050 60Hz `T_1680x1050_60Hz`.
    - 1856x1392 60Hz `T_1856x1392_60Hz`.
    - 1920x1080 60Hz `T_1920x1080_60Hz`.
    - 1920x1200 60Hz `T_1920x1200_60Hz`.
    - 1920x1440 60Hz `T_1920x1440_60Hz`.
    - Disable all timings `clear_all`.
    """

    def __init__(self, json_obj):
        self.__param = Param(json_obj)

    @property
    def T_800x600_60Hz(self) -> bool:
        """
        Set and get 800x600 60Hz timing flag support.

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

    @T_800x600_60Hz.setter
    def T_800x600_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 0)

    @property
    def T_1024x768_60Hz(self) -> bool:
        """
        Set and get 1024x768 60Hz timing flag support.

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

    @T_1024x768_60Hz.setter
    def T_1024x768_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 1)

    @property
    def T_1280x768_60Hz(self) -> bool:
        """
        Set and get 1280x768 60Hz timing flag support.

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

    @T_1280x768_60Hz.setter
    def T_1280x768_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 2)

    @property
    def T_1280x800_60Hz(self) -> bool:
        """
        Set and get 1280x800 60Hz timing flag support.

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

    @T_1280x800_60Hz.setter
    def T_1280x800_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 3)

    @property
    def T_1280x960_60Hz(self) -> bool:
        """
        Set and get 1280x960 60Hz timing flag support.

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

    @T_1280x960_60Hz.setter
    def T_1280x960_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 4)

    @property
    def T_1280x1024_60Hz(self) -> bool:
        """
        Set and get 1280x1024 60Hz timing flag support.

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

    @T_1280x1024_60Hz.setter
    def T_1280x1024_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 5)

    @property
    def T_1360x768_60Hz(self) -> bool:
        """
        Set and get 1360x768 60Hz timing flag support.

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

    @T_1360x768_60Hz.setter
    def T_1360x768_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 6)

    @property
    def T_1400x1050_60Hz(self) -> bool:
        """
        Set and get 1400x1050 60Hz timing flag support.

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

    @T_1400x1050_60Hz.setter
    def T_1400x1050_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 7)

    @property
    def T_1600x1200_60Hz(self) -> bool:
        """
        Set and get 1600x1200 60Hz timing flag support.

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

    @T_1600x1200_60Hz.setter
    def T_1600x1200_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 8)

    @property
    def T_1680x1050_60Hz(self) -> bool:
        """
        Set and get 1680x1050 60Hz timing flag support.

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

    @T_1680x1050_60Hz.setter
    def T_1680x1050_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 9)

    @property
    def T_1856x1392_60Hz(self) -> bool:
        """
        Set and get 1856x1392 60Hz timing flag support.

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

    @T_1856x1392_60Hz.setter
    def T_1856x1392_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 10)

    @property
    def T_1920x1080_60Hz(self) -> bool:
        """
        Set and get 1920x1080 60Hz timing flag support.

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

    @T_1920x1080_60Hz.setter
    def T_1920x1080_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 11)

    @property
    def T_1920x1200_60Hz(self) -> bool:
        """
        Set and get 1920x1200 60Hz timing flag support.

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

    @T_1920x1200_60Hz.setter
    def T_1920x1200_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 12)

    @property
    def T_1920x1440_60Hz(self) -> bool:
        """
        Set and get 1920x1440 60Hz timing flag support.

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

    @T_1920x1440_60Hz.setter
    def T_1920x1440_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 13)

    def clear_all(self):
        """
        Disable all timings.
        """
        self.T_800x600_60Hz = False
        self.T_1024x768_60Hz = False
        self.T_1280x768_60Hz = False
        self.T_1280x800_60Hz = False
        self.T_1280x960_60Hz = False
        self.T_1280x1024_60Hz = False
        self.T_1360x768_60Hz = False
        self.T_1400x1050_60Hz = False
        self.T_1600x1200_60Hz = False
        self.T_1680x1050_60Hz = False
        self.T_1856x1392_60Hz = False
        self.T_1920x1080_60Hz = False
        self.T_1920x1200_60Hz = False
        self.T_1920x1440_60Hz = False


class CtaTiming:
    """
    Class `CtaTiming` describes all available DMT timings for Display ID LLCTS tests. Allows enabling and disable
    timings.
    - 720x480 60Hz `T_720x480_60Hz`
    - 1280x720 60Hz `T_1280x720_60Hz`
    - 1920x1080 60Hz `T_1920x1080_60Hz`
    - 1280x720 120Hz `T_1280x720_120Hz`
    - 720x480 120Hz `T_720x480_120Hz`
    - 1920x1080 120Hz `T_1920x1080_120Hz`
    - 1680x720 60Hz `T_1680x720_60Hz`
    - 1680x720 120Hz `T_1680x720_120Hz`
    - 2560x1080 60Hz `T_2560x1080_60Hz`
    - 2560x1080 120Hz `T_2560x1080_120Hz`
    - 3840x2160 60Hz `T_3840x2160_60Hz`
    - 4096x2160 60H `T_4096x2160_60Hz`
    - 3840x2160 120Hz `T_3840x2160_120Hz`
    - 5120x2160 60Hz `T_5120x2160_60Hz`
    - 7680x4320 24Hz `T_7680x4320_24Hz`
    - 7680x4320 30Hz `T_7680x4320_30Hz`
    - Disable all timings `clear_all`.
    """

    def __init__(self, json_obj):
        self.__param = Param(json_obj)

    @property
    def T_720x480_60Hz(self) -> bool:
        """
        Set and get 720x480 60Hz timing flag support.

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

    @T_720x480_60Hz.setter
    def T_720x480_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 0)

    @property
    def T_1280x720_60Hz(self) -> bool:
        """
        Set and get 1280x720 60Hz timing flag support.

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

    @T_1280x720_60Hz.setter
    def T_1280x720_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 1)

    @property
    def T_1920x1080_60Hz(self) -> bool:
        """
        Set and get 1920x1080 60Hz timing flag support.

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

    @T_1920x1080_60Hz.setter
    def T_1920x1080_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 2)

    @property
    def T_1280x720_120Hz(self) -> bool:
        """
        Set and get 1280x720 120Hz timing flag support.

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

    @T_1280x720_120Hz.setter
    def T_1280x720_120Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 3)

    @property
    def T_720x480_120Hz(self) -> bool:
        """
        Set and get 720x480 120Hz timing flag support.

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

    @T_720x480_120Hz.setter
    def T_720x480_120Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 4)

    @property
    def T_1920x1080_120Hz(self) -> bool:
        """
        Set and get 1920x1080 120Hz timing flag support.

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

    @T_1920x1080_120Hz.setter
    def T_1920x1080_120Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 5)

    @property
    def T_1680x720_60Hz(self) -> bool:
        """
        Set and get 1680x720 60Hz timing flag support.

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

    @T_1680x720_60Hz.setter
    def T_1680x720_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 6)

    @property
    def T_1680x720_120Hz(self) -> bool:
        """
        Set and get 1680x720 120Hz timing flag support.

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

    @T_1680x720_120Hz.setter
    def T_1680x720_120Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 7)

    @property
    def T_2560x1080_60Hz(self) -> bool:
        """
        Set and get 2560x1080 60Hz timing flag support.

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

    @T_2560x1080_60Hz.setter
    def T_2560x1080_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 8)

    @property
    def T_2560x1080_120Hz(self) -> bool:
        """
        Set and get 2560x1080 120Hz timing flag support.

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

    @T_2560x1080_120Hz.setter
    def T_2560x1080_120Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 9)

    @property
    def T_3840x2160_60Hz(self) -> bool:
        """
        Set and get 3840x2160 60Hz timing flag support.

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

    @T_3840x2160_60Hz.setter
    def T_3840x2160_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 10)

    @property
    def T_4096x2160_60Hz(self) -> bool:
        """
        Set and get 4096x2160 60Hz timing flag support.

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

    @T_4096x2160_60Hz.setter
    def T_4096x2160_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 11)

    @property
    def T_3840x2160_120Hz(self) -> bool:
        """
        Set and get 3840x2160 120Hz timing flag support.

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

    @T_3840x2160_120Hz.setter
    def T_3840x2160_120Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 12)

    @property
    def T_5120x2160_60Hz(self) -> bool:
        """
        Set and get 5120x2160 60Hz timing flag support.

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

    @T_5120x2160_60Hz.setter
    def T_5120x2160_60Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 13)

    @property
    def T_7680x4320_24Hz(self) -> bool:
        """
        Set and get 7680x4320 24Hz timing flag support.

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

    @T_7680x4320_24Hz.setter
    def T_7680x4320_24Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 14)

    @property
    def T_7680x4320_30Hz(self) -> bool:
        """
        Set and get 7680x4320 30Hz timing flag support.

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

    @T_7680x4320_30Hz.setter
    def T_7680x4320_30Hz(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 15)

    def clear_all(self):
        """
        Disable all timings.
        """
        self.T_720x480_60Hz = False
        self.T_1280x720_60Hz = False
        self.T_1920x1080_60Hz = False
        self.T_1280x720_120Hz = False
        self.T_720x480_120Hz = False
        self.T_1920x1080_120Hz = False
        self.T_1680x720_60Hz = False
        self.T_1680x720_120Hz = False
        self.T_2560x1080_60Hz = False
        self.T_2560x1080_120Hz = False
        self.T_3840x2160_60Hz = False
        self.T_4096x2160_60Hz = False
        self.T_3840x2160_120Hz = False
        self.T_5120x2160_60Hz = False
        self.T_7680x4320_24Hz = False
        self.T_7680x4320_30Hz = False


class CvtTiming:
    """
    Class `CvtTiming` describes all available DMT timings for Display ID LLCTS tests. Allows enabling and disable
    timings.
    - 1920x1080 60Hz RB1 `T_1920x1080_60Hz_RB1`.
    - 2048x1536 60Hz RB1 `T_2048x1536_60Hz_RB1`.
    - 2560x1080 60Hz RB1 `T_2560x1080_60Hz_RB1`.
    - 2560x1440 60Hz RB1 `T_2560x1440_60Hz_RB1`.
    - 2560x1440 60Hz RB2 `T_2560x1440_60Hz_RB2`.
    - 3840x2160 60Hz RB1 `T_3840x2160_60Hz_RB1`.
    - 3840x2160 60Hz RB2 `T_3840x2160_60Hz_RB2`.
    - 3840x2160 60Hz RB3 `T_3840x2160_60Hz_RB3`.
    - 4096x2160 60Hz RB1 `T_4096x2160_60Hz_RB1`.
    - 4096x2160 60Hz RB2 `T_4096x2160_60Hz_RB2`.
    - 4096x2160 60Hz RB3 `T_4096x2160_60Hz_RB3`.
    - 5120x2880 60Hz RB1 `T_5120x2880_60Hz_RB1`.
    - 5120x2880 60Hz RB2 `T_5120x2880_60Hz_RB2`.
    - 5120x2880 60Hz RB3 `T_5120x2880_60Hz_RB3`.
    - Disable all timings `clear_all`.
    """

    def __init__(self, json_obj):
        self.__param = Param(json_obj)

    @property
    def T_1920x1080_60Hz_RB1(self) -> bool:
        """
        Set and get 1920x1080 60Hz RB1 timing flag support.

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

    @T_1920x1080_60Hz_RB1.setter
    def T_1920x1080_60Hz_RB1(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 0)

    @property
    def T_2048x1536_60Hz_RB1(self) -> bool:
        """
        Set and get 2048x1536 60Hz RB1 timing flag support.

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

    @T_2048x1536_60Hz_RB1.setter
    def T_2048x1536_60Hz_RB1(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 1)

    @property
    def T_2560x1080_60Hz_RB1(self) -> bool:
        """
        Set and get 2560x1080 60Hz RB1 timing flag support.

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

    @T_2560x1080_60Hz_RB1.setter
    def T_2560x1080_60Hz_RB1(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 2)

    @property
    def T_2560x1440_60Hz_RB1(self) -> bool:
        """
        Set and get 2560x1440 60Hz RB1 timing flag support.

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

    @T_2560x1440_60Hz_RB1.setter
    def T_2560x1440_60Hz_RB1(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 3)

    @property
    def T_2560x1440_60Hz_RB2(self) -> bool:
        """
        Set and get 2560x1440 60Hz RB2 timing flag support.

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

    @T_2560x1440_60Hz_RB2.setter
    def T_2560x1440_60Hz_RB2(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 4)

    @property
    def T_3840x2160_60Hz_RB1(self) -> bool:
        """
        Set and get 3840x2160 60Hz RB1 timing flag support.

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

    @T_3840x2160_60Hz_RB1.setter
    def T_3840x2160_60Hz_RB1(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 5)

    @property
    def T_3840x2160_60Hz_RB2(self) -> bool:
        """
        Set and get 3840x2160 60Hz RB2 timing flag support.

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

    @T_3840x2160_60Hz_RB2.setter
    def T_3840x2160_60Hz_RB2(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 6)

    @property
    def T_3840x2160_60Hz_RB3(self) -> bool:
        """
        Set and get 3840x2160 60Hz RB3 timing flag support.

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

    @T_3840x2160_60Hz_RB3.setter
    def T_3840x2160_60Hz_RB3(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 7)

    @property
    def T_4096x2160_60Hz_RB1(self) -> bool:
        """
        Set and get 4096x2160 60Hz RB1 timing flag support.

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

    @T_4096x2160_60Hz_RB1.setter
    def T_4096x2160_60Hz_RB1(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 8)

    @property
    def T_4096x2160_60Hz_RB2(self) -> bool:
        """
        Set and get 4096x2160 60Hz RB2 timing flag support.

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

    @T_4096x2160_60Hz_RB2.setter
    def T_4096x2160_60Hz_RB2(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 9)

    @property
    def T_4096x2160_60Hz_RB3(self) -> bool:
        """
        Set and get 4096x2160 60Hz RB3 timing flag support.

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

    @T_4096x2160_60Hz_RB3.setter
    def T_4096x2160_60Hz_RB3(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 10)

    @property
    def T_5120x2880_60Hz_RB1(self) -> bool:
        """
        Set and get 5120x2880 60Hz RB1 timing flag support.

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

    @T_5120x2880_60Hz_RB1.setter
    def T_5120x2880_60Hz_RB1(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 11)

    @property
    def T_5120x2880_60Hz_RB2(self) -> bool:
        """
         Set and get 5120x2880 60Hz RB2 timing flag support.

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

    @T_5120x2880_60Hz_RB2.setter
    def T_5120x2880_60Hz_RB2(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 12)

    @property
    def T_5120x2880_60Hz_RB3(self) -> bool:
        """
         Set and get 5120x2880 60Hz RB3 timing flag support.

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

    @T_5120x2880_60Hz_RB3.setter
    def T_5120x2880_60Hz_RB3(self, enable: bool):
        self.__param._set_by_bitmask(int(enable), 13)

    def clear_all(self):
        """
        Disable all timings.
        """
        self.T_1920x1080_60Hz_RB1 = False
        self.T_2048x1536_60Hz_RB1 = False
        self.T_2560x1080_60Hz_RB1 = False
        self.T_2560x1440_60Hz_RB1 = False
        self.T_2560x1440_60Hz_RB2 = False
        self.T_3840x2160_60Hz_RB1 = False
        self.T_3840x2160_60Hz_RB2 = False
        self.T_3840x2160_60Hz_RB3 = False
        self.T_4096x2160_60Hz_RB1 = False
        self.T_4096x2160_60Hz_RB2 = False
        self.T_4096x2160_60Hz_RB3 = False
        self.T_5120x2880_60Hz_RB1 = False
        self.T_5120x2880_60Hz_RB2 = False
        self.T_5120x2880_60Hz_RB3 = False


class DisplayIdDpVideoTimingsBase:
    def __init__(self, dmt_timings, cta_timings, cvt_timings):
        self._dmt_timings = dmt_timings
        self._cta_timings = cta_timings
        self._cvt_timings = cvt_timings

    @property
    def dmt_timings(self) -> DmtTiming:
        """
        Set and get DMT timings.

        Returns:
            object of `DmtTiming` type
        """
        return self._dmt_timings

    @dmt_timings.setter
    def dmt_timings(self, timings: DmtTiming):
        self._dmt_timings = timings

    @property
    def cta_timings(self) -> CtaTiming:
        """
        Set and get CTA timings.

        Returns:
            object of `CtaTiming` type
        """
        return self._cta_timings

    @cta_timings.setter
    def cta_timings(self, timings: CtaTiming):
        self._cta_timings = timings

    @property
    def cvt_timings(self) -> CvtTiming:
        """
        Set and get CVT timings.

        Returns:
            object of `CvtTiming` type
        """
        return self._cvt_timings

    @cvt_timings.setter
    def cvt_timings(self, timings: CvtTiming):
        self._cvt_timings = timings

    def clear_all(self):
        """
        Disable all timings.
        """
        self.cta_timings.clear_all()
        self.cvt_timings.clear_all()
        self.dmt_timings.clear_all()


class DisplayIdDp14VideoTimings(DisplayIdDpVideoTimingsBase):
    """
    Class `DisplayIdDp14VideoTimings` allows working with all timings for Display ID LLCTS tests.
    - Configure DMT timings `dmt_timings`.
    - Configure CTA timings `cta_timings`.
    - Configure CVT timings `cvt_timings`.
    - Disable all timings `clear_all`.
    """

    def __init__(self, json_obj):
        super().__init__(
            DmtTiming(json_obj["TSI_DP14_SRCCTS_DMT_TIMING"]),
            CtaTiming(json_obj["TSI_DP14_SRCCTS_CTA_TIMING"]),
            CvtTiming(json_obj["TSI_DP14_SRCCTS_CVT_TIMING"])
        )


class DisplayIdDp21VideoTimings(DisplayIdDpVideoTimingsBase):
    """
    Class `DisplayIdDp21VideoTimings` inherited of class`DisplayIdDp14VideoTimings` allows working with timings for
    Display ID LLCTS tests.
    Class `DisplayIdDp21VideoTimings` has all the `DisplayIdDp14VideoTimings` functionality.
    """

    def __init__(self, json_obj):
        super().__init__(
            DmtTiming(json_obj["TSI_DP20_SRCCTS_DMT_TIMING"]),
            CtaTiming(json_obj["TSI_DP20_SRCCTS_CTA_TIMING"]),
            CvtTiming(json_obj["TSI_DP20_SRCCTS_CVT_TIMING"])
        )


GeneralDisplayIdParameters = TypeVar("GeneralDisplayIdParameters",
                                     DisplayIdDp14VideoTimings,
                                     DisplayIdDp21VideoTimings)


AudioDisplayIdParameters = TypeVar("AudioDisplayIdParameters",
                                   DisplayIdDp14Audio,
                                   DisplayIdDp21Audio)


class DisplayIdDpConfigTabBase:
    def __init__(self, max_stream_h_active, max_stream_v_active, max_stream_pixel_clock,
                 display_id_audio, display_id_timings):
        self.__max_stream_h_active = max_stream_h_active
        self.__max_stream_v_active = max_stream_v_active
        self.__max_stream_pixel_clock = max_stream_pixel_clock
        self.__display_id_audio = display_id_audio
        self.__display_id_timings = display_id_timings

    @property
    def max_stream_h_active(self) -> int:
        """
        Set and get maximum stream resolution H Active.

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

    @max_stream_h_active.setter
    def max_stream_h_active(self, max_stream_h_active: int):
        if not (
                self.__max_stream_h_active.min_value < max_stream_h_active < self.__max_stream_h_active.max_value):
            raise ValueError(f"Max stream H Active cannot be less than "
                             f"{self.__max_stream_h_active.min_value} and more than "
                             f"{self.__max_stream_h_active.max_value}.")
        self.__max_stream_h_active.default_value = max_stream_h_active

    @property
    def max_stream_v_active(self) -> int:
        """
        Set and get maximum stream resolution V Active.

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

    @max_stream_v_active.setter
    def max_stream_v_active(self, max_stream_v_active: int):
        if not (
                self.__max_stream_v_active.min_value < max_stream_v_active < self.__max_stream_v_active.max_value):
            raise ValueError(f"Max stream V Active cannot be less than "
                             f"{self.__max_stream_v_active.min_value} and more than "
                             f"{self.__max_stream_v_active.max_value}.")
        self.__max_stream_v_active.default_value = max_stream_v_active

    @property
    def max_stream_pixel_clock(self) -> int:
        """
        Set and get maximum stream pixel clock.

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

    @max_stream_pixel_clock.setter
    def max_stream_pixel_clock(self, max_stream_pixel_clock: int):
        if not (self.__max_stream_pixel_clock.min_value < max_stream_pixel_clock <
                self.__max_stream_pixel_clock.max_value):
            raise ValueError(f"Max stream pixel clock cannot be less than "
                             f"{self.__max_stream_pixel_clock.min_value} and more than "
                             f"{self.__max_stream_pixel_clock.max_value}.")
        self.__max_stream_pixel_clock.default_value = max_stream_pixel_clock

    @property
    def audio(self) -> AudioDisplayIdParameters:
        """
        Set and get audio settings.

        Returns:
            object of `DisplayIdDp14Audio` type
        """
        return self.__display_id_audio

    @audio.setter
    def audio(self, display_id_audio: DisplayIdDp14Audio):
        self.__display_id_audio = display_id_audio

    @property
    def general(self) -> GeneralDisplayIdParameters:
        """
        Set and get timings settings.

        Returns:
            object of `DisplayIdDp14VideoTimings` type
        """
        return self.__display_id_timings

    @general.setter
    def general(self, display_id_timings: DisplayIdDp14VideoTimings):
        self.__display_id_timings = display_id_timings

    def clear_all(self):
        self.__max_stream_h_active.default_value = 0
        self.__max_stream_v_active.default_value = 0
        self.__max_stream_pixel_clock.default_value = 0
        self.__display_id_timings.clear_all()
        self.__display_id_audio.clear_all()


class DisplayIdDp14ConfigTab(DisplayIdDpConfigTabBase):
    """
    Class `DisplayIdDp14ConfigTab` allows setting parameters for Display ID tests.
    - Maximum stream resolution H Active `max_stream_h_active`.
    - Maximum stream resolution V Active `max_stream_v_active`.
    - Maximum stream pixel clock `max_stream_pixel_clock`.
    - Audio modes `display_id_audio` type `DisplayIdDp14Audio`.
    - Timings `display_id_timings` type `DisplayIdDp14VideoTimings`.
    - Clear all settings `clear_all`.
    """

    def __init__(self, json_obj):
        super().__init__(Param(json_obj["TSI_DP14_SRCCTS_MAX_STREAM_HACTIVE"]),
                         Param(json_obj["TSI_DP14_SRCCTS_MAX_STREAM_VACTIVE"]),
                         Param(json_obj["TSI_DP14_SRCCTS_MAX_STREAM_PIXEL_CLOCK"]),
                         DisplayIdDp14Audio(json_obj),
                         DisplayIdDp14VideoTimings(json_obj))


class DisplayIdDp21ConfigTab(DisplayIdDpConfigTabBase):
    """
    Class `DisplayIdDp21ConfigTab` inherited of class`DisplayIdDp14ConfigTab` allows working with parameters for
    Display ID LLCTS tests.
    Class `DisplayIdDp21ConfigTab` has all the `DisplayIdDp14ConfigTab` functionality.
    """

    def __init__(self, json_obj):
        super().__init__(Param(json_obj["TSI_DP20_SRCCTS_MAX_STREAM_HACTIVE"]),
                         Param(json_obj["TSI_DP20_SRCCTS_MAX_STREAM_VACTIVE"]),
                         Param(json_obj["TSI_DP20_SRCCTS_MAX_STREAM_PIXEL_CLOCK"]),
                         DisplayIdDp21Audio(json_obj),
                         DisplayIdDp21VideoTimings(json_obj))

        self.__dynamic_refresh_rate_h_active = Param(json_obj["TSI_DP20_SRCCTS_DRR_HACTIVE"])
        self.__dynamic_refresh_rate_v_active = Param(json_obj["TSI_DP20_SRCCTS_DRR_VACTIVE"])
        self.__dynamic_refresh_rate_pixel_clock = Param(json_obj["TSI_DP20_SRCCTS_DRR_PIXEL_CLOCK"])
        self.__dynamic_refresh_rate_min_vertical = Param(json_obj["TSI_DP20_SRCCTS_DRR_MIN_VRR"])
        self.__dynamic_refresh_rate_max_vertical = Param(json_obj["TSI_DP20_SRCCTS_DRR_MAX_VRR"])

    @property
    def dynamic_refresh_rate_h_active(self) -> int:
        """
        Set and get Dynamic Refresh Rate h active.

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

    @dynamic_refresh_rate_h_active.setter
    def dynamic_refresh_rate_h_active(self, dynamic_refresh_rate_h_active: int):
        if not (
                self.__dynamic_refresh_rate_h_active.min_value < dynamic_refresh_rate_h_active < self.__dynamic_refresh_rate_h_active.max_value):
            raise ValueError(f"Dynamic refresh rate h active be less than "
                             f"{self.__dynamic_refresh_rate_h_active.min_value} and more than "
                             f"{self.__dynamic_refresh_rate_h_active.max_value}.")
        self.__dynamic_refresh_rate_h_active.default_value = dynamic_refresh_rate_h_active

    @property
    def dynamic_refresh_rate_v_active(self) -> int:
        """
        Set and get Dynamic Refresh Rate v active.

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

    @dynamic_refresh_rate_v_active.setter
    def dynamic_refresh_rate_v_active(self, dynamic_refresh_rate_v_active: int):
        if not (
                self.__dynamic_refresh_rate_v_active.min_value < dynamic_refresh_rate_v_active < self.__dynamic_refresh_rate_v_active.max_value):
            raise ValueError(f"Dynamic refresh rate v active be less than "
                             f"{self.__dynamic_refresh_rate_v_active.min_value} and more than "
                             f"{self.__dynamic_refresh_rate_v_active.max_value}.")
        self.__dynamic_refresh_rate_v_active.default_value = dynamic_refresh_rate_v_active

    @property
    def dynamic_refresh_rate_pixel_clock(self) -> int:
        """
        Set and get Dynamic Refresh Rate Pixel Clock.

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

    @dynamic_refresh_rate_pixel_clock.setter
    def dynamic_refresh_rate_pixel_clock(self, dynamic_refresh_rate_pixel_clock: int):
        if not (
                self.__dynamic_refresh_rate_pixel_clock.min_value < dynamic_refresh_rate_pixel_clock < self.__dynamic_refresh_rate_pixel_clock.max_value):
            raise ValueError(f"Dynamic refresh rate h active be less than "
                             f"{self.__dynamic_refresh_rate_pixel_clock.min_value} and more than "
                             f"{self.__dynamic_refresh_rate_pixel_clock.max_value}.")
        self.__dynamic_refresh_rate_pixel_clock.default_value = dynamic_refresh_rate_pixel_clock

    @property
    def dynamic_refresh_rate_min_vertical(self) -> int:
        """
        Set and get Dynamic Refresh Rate minimum vertical.

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

    @dynamic_refresh_rate_min_vertical.setter
    def dynamic_refresh_rate_min_vertical(self, dynamic_refresh_rate_min_vertical: int):
        if not (
                self.__dynamic_refresh_rate_min_vertical.min_value < dynamic_refresh_rate_min_vertical < self.__dynamic_refresh_rate_min_vertical.max_value):
            raise ValueError(f"Dynamic refresh rate h active be less than "
                             f"{self.__dynamic_refresh_rate_min_vertical.min_value} and more than "
                             f"{self.__dynamic_refresh_rate_min_vertical.max_value}.")
        self.__dynamic_refresh_rate_min_vertical.default_value = dynamic_refresh_rate_min_vertical

    @property
    def dynamic_refresh_rate_max_vertical(self) -> int:
        """
        Set and get Dynamic Refresh Rate maximum vertical.

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

    @dynamic_refresh_rate_max_vertical.setter
    def dynamic_refresh_rate_max_vertical(self, dynamic_refresh_rate_max_vertical: int):
        if not (
                self.__dynamic_refresh_rate_max_vertical.min_value < dynamic_refresh_rate_max_vertical < self.__dynamic_refresh_rate_max_vertical.max_value):
            raise ValueError(f"Dynamic refresh rate h active be less than "
                             f"{self.__dynamic_refresh_rate_max_vertical.min_value} and more than "
                             f"{self.__dynamic_refresh_rate_max_vertical.max_value}.")
        self.__dynamic_refresh_rate_max_vertical.default_value = dynamic_refresh_rate_max_vertical