import warnings

from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .types import ClockRate, LinkMode, ScramblerState
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDTX_SINK_FEATURE_W, TSI_HDTX_STATUS_R, TSI_HDTX_SINK_STATUS_R, \
    TSI_HDTX_CONTROL_W
from ctypes import c_uint32


class TmdsTx:
    """
    CLass `TmdsRx` allows working with TMDS on Source (TX - transmitter) side.
    - Get link mode `link_mode`.
    - Set and get clock rate `clock_rate`.
    - Set and get scrambler `scrambler`.
    """
    def __init__(self, port_io: PortIO):
        self.__io = port_io
        self.__clock_rate = ClockRate.Unknown
        self.__link_mode = LinkMode.Unknown
        self.__scrambler = ScramblerState.Unknown

    def __read_sink_status(self) -> int:
        return self.__io.get(TSI_HDTX_SINK_STATUS_R, c_uint32)[1]

    def __read_hdtx_status(self) -> int:
        return self.__io.get(TSI_HDTX_STATUS_R, c_uint32)[1]

    def __write_sink_feature(self, value: int):
        self.__io.set(TSI_HDTX_SINK_FEATURE_W, value, c_uint32)

    @property
    def clock_rate(self) -> int:
        """
        Returns current clock rate.

        Returns:
            object of int type
        """
        return 6 if self.__read_sink_status() & 0x2 else 3

    @clock_rate.setter
    def clock_rate(self, clock_rate: int):
        """
        Set new clock rate value. Available variants: 3, 6.

        Args:
            clock_rate (int)
        """
        if clock_rate not in [3, 6]:
            warnings.warn("Incorrect value. Must be from available values: 3, 6")
            return
        self.__write_sink_feature(3 if clock_rate == 3 else 4)

    @property
    def link_mode(self) -> LinkMode:
        """
        Returns current link mode.

        Returns:
            object of `LinkMode` type
        """
        self.__link_mode = LinkMode(self.__read_hdtx_status() & 0x1)
        return self.__link_mode

    @link_mode.setter
    def link_mode(self, link_mode: LinkMode):
        """
        Set new link mode.

        Args:
            link_mode (LinkMode)
        """
        self.__io.set(TSI_HDTX_CONTROL_W, link_mode.value, c_uint32)

    @property
    def scrambler(self) -> bool:
        """
        Returns current scrambler state.

        Returns:
            object of bool type
        """
        return self.__read_sink_status() & 0x1 != 0

    @scrambler.setter
    def scrambler(self, scrambler: bool):
        """
        Enable/disable scrambler.

        Args:
            scrambler (bool)
        """
        self.__write_sink_feature(1 if scrambler else 2)

    def __str__(self):
        return f"Clock rate: {self.clock_rate}G\n" \
               f"Link mode: {self.link_mode.name}\n" \
               f"Scrambler: {'Enable' if self.scrambler else 'Disable'}\n"
