from .link_rx_caps import LinkDisplayPortCaps
from .link_rx_status import *
from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .dp_cable_info import DpCableInfo, CableCapabilitiesEnum
from .link_rx_aux_controller import DisplayPortAUXController
from UniTAP.dev.ports.modules.dpcd import DPCDRegisters


class LinkDisplayPortRx:
    """
    Class `LinkDisplayPortRx` contains information about DP link.
    - Read link status `status`.
    - Configure and read link capabilities `capabilities`.
    - Make `hpd_pulse`.
    - Assert/Deassert HPD state `set_assert_state`.
    - Read and write scrambler seed value `scrambler_seed`.
    """
    def __init__(self, port_io: PortIO, hw_caps: DPRXHWCaps, dpcd: DPCDRegisters):
        self.__io = port_io
        self.__HW_CAPS = hw_caps
        self.__status = LinkDisplayPortStatusSink(port_io, self.__HW_CAPS)
        self.__capabilities = LinkDisplayPortCaps(port_io, self.__HW_CAPS)
        self.__cable_info = DpCableInfo(port_io, TSI_DPRX_CABLE_ATTRIBUTES_R)
        self.__aux_controller = DisplayPortAUXController(port_io, dpcd)

    @property
    def status(self) -> LinkDisplayPortStatusSink:
        """
        Returns object of class `LinkDisplayPortStatusSink` for working with link status.

        Returns:
            object of `LinkDisplayPortStatusSink` type
        """
        return self.__status

    @property
    def capabilities(self) -> LinkDisplayPortCaps:
        """
        Returns object of class `LinkDisplayPortCaps` for working with link capabilities.

        Returns:
            object of `LinkDisplayPortStatusSink` type
        """
        return self.__capabilities

    @property
    def aux_controller(self) -> DisplayPortAUXController:
        """
        Returns object of class `DisplayPortAUXController` for working with DP AUX Controller.

        Returns:
            object of `DisplayPortAUXController` type
        """
        return self.__aux_controller

    def hpd_pulse(self, duration_us: int = 500000):
        """
        Start HPD pulse.

        Args:
            duration_us (int)
        """
        self.__io.set(TSI_DPRX_HPD_PULSE_W, duration_us, c_int)

    def set_assert_state(self, state: bool):
        """
        Assert/Deassert HPD state.

        Args:
            state (bool)
        """
        val = 0x1 if state else 0x0
        self.__io.set(TSI_FORCE_HOT_PLUG_STATE_W, val)

    @property
    def scrambler_seed(self) -> int:
        """
        Returns scrambler seed value.

        Returns:
            object of `int` type
        """
        if not self.__HW_CAPS.scrambler_seed:
            warnings.warn("Scrambler Seed is not supported.")
            return 0

        return self.__io.get(TSI_DPRX_SCR_SEED, c_uint32)[1]

    @scrambler_seed.setter
    def scrambler_seed(self, value: int = 0):
        """
        Write new value to scrambler seed

        Args:
            value (int) - new scrambler seed value
        """
        if value < 0 or value > 65535:
            raise ValueError(f"Scrambler seed {value} is not available.")

        if self.__HW_CAPS.scrambler_seed:
            self.__io.set(TSI_DPRX_SCR_SEED, value)
        else:
            warnings.warn("Scrambler Seed is not supported.")

    def cable_rx_type(self) -> CableCapabilitiesEnum:
        """
        Get cable type from the RX side.

        Returns:
            object of `CableCapabilitiesEnum` type
        """
        return self.__cable_info.get_current_port_cable_type()

    def cable_tx_type(self) -> CableCapabilitiesEnum:
        """
        Get cable type from the TX side.

        Returns:
            object of `CableCapabilitiesEnum` type
        """
        return self.__cable_info.get_another_port_cable_type()
