from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .types import FrlMode, LtpLanesPattern, FrlCaps, LtpPattern, _update_frl_values, _update_ltp_pattern_values
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDRX_FRL_CAPABILITY, TSI_HDRX_FRL_PATTERN, TSI_HDRX_LINK_STATUS_R
from ctypes import c_uint32


class FrlControlRx:
    """
    Class `FrlControlRx` contains information about FRL on Sink (RX - receiver) side.
    allows working with:
    - Set and get FRL mode `frl_mode`.
    - Set and get FRL capabilities `frl_caps`.
    - Set and get LTP requested `ltp_request` and additional `ltp_additional`.
    """
    def __init__(self, port_io: PortIO):
        self.__io = port_io
        self.__frl_caps = FrlCaps()
        self.__ltp_request = LtpLanesPattern()
        self.__ltp_additional = LtpLanesPattern()

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

    def __write_caps(self, value: int):
        self.__io.set(TSI_HDRX_FRL_CAPABILITY, value, c_uint32)

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

    def __write_frl_pattern(self, value: int):
        self.__io.set(TSI_HDRX_FRL_PATTERN, value, c_uint32)

    @property
    def frl_mode(self) -> FrlMode:
        """
        Returns current FRL mode.

        Returns:
            object of `FrlMode` type
        """
        return FrlMode(self.__read_caps() & 0xF)

    @frl_mode.setter
    def frl_mode(self, frl_mode: FrlMode):
        """
        Set new FRL mode.

        Args:
            frl_mode (`FrlMode`)
        """
        new_value = frl_mode.value
        new_value |= self.__read_caps() & ~0xF
        self.__write_caps(new_value)

    @property
    def frl_caps(self) -> FrlCaps:
        """
        Returns current FRL capabilities.

        Returns:
            object of `FrlCaps` type
        """
        _update_frl_values(self.__frl_caps, self.__read_caps())
        return self.__frl_caps

    @frl_caps.setter
    def frl_caps(self, frl_caps: FrlCaps):
        """
        Set new FRL capabilities.

        Args:
            frl_caps (`FrlCaps`)
        """
        new_value = frl_caps.value()
        new_value |= self.__read_caps() & ~0xF
        self.__write_caps(new_value)
        self.__frl_caps = frl_caps

    @property
    def ltp_request(self) -> LtpLanesPattern:
        """
        Returns current LTP lanes pattern. Current Pattern that is being checking during Link Training.
        Each lane can request different pattern.

        Returns:
            object of `LtpLanesPattern` type
        """
        _update_ltp_pattern_values(self.__ltp_request, self.__read_frl_pattern())
        return self.__ltp_request

    @ltp_request.setter
    def ltp_request(self, ltp_request: LtpLanesPattern):
        """
        Set new LTP lanes pattern.

        Args:
            ltp_request (`LtpLanesPattern`)
        """
        new_value = ltp_request.value()
        new_value |= self.__read_frl_pattern()
        self.__write_frl_pattern(new_value)
        self.__ltp_request = ltp_request

    @property
    def ltp_additional(self) -> LtpLanesPattern:
        """
        Returns current additional LTP lanes pattern. Current Pattern that is being checking during Link Training.
        Each lane can request different pattern.

        Returns:
            object of `LtpLanesPattern` type
        """
        _update_ltp_pattern_values(self.__ltp_additional, self.__read_frl_pattern() >> 0xFF)
        return self.__ltp_additional

    @ltp_additional.setter
    def ltp_additional(self, ltp_request: LtpLanesPattern):
        """
        Set new additional LTP lanes pattern.

        Args:
            ltp_request (`LtpLanesPattern`)
        """
        new_value = ltp_request.value() << 0xFF
        new_value |= self.__read_frl_pattern()
        self.__write_frl_pattern(new_value)
        self.__ltp_additional = ltp_request

    def re_train(self):
        """
        DO re train.
        """
        self.__io.set(TSI_HDRX_LINK_STATUS_R, 0x1c0000, c_uint32)

    def __str__(self):
        return f"FRL Mode: {self.frl_mode.name}\n" \
               f"FRL Caps:\n{self.frl_caps.__str__()}" \
               f"LTP Lanes Pattern:\n{self.ltp_request.__str__()}" \
               f"LTP Lanes Pattern Additional:\n{self.ltp_additional.__str__()}\n"
