from UniTAP.dev.ports import DPRX5xx, DPTX5xx, PDC500
from .modules import MemoryManager, Capturer, DUTTests
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO, PortProtocol


class UCD500:
    """
    Class `UCD500` describes of device UCD-500. Device has one possible role:
    - 'DisplayPort Source and Sink' `DPSourceDPSink`.
    - 'DisplayPort Source and USB-C, DP Alt Mode Sink' `DPSourceUSBCSink`.
    - 'DisplayPort Sink and USB-C, DP Alt Mode Source' `USBCSourceDPSink`.
    - 'USB-C, DP Alt Mode Source and Sink' `USBCSourceUSBCSink`.
    """
    class DPSourceDPSink:
        """
        Class `DPSourceDPSink` contains information of available functionality modules for role DP Sink
        (RX - receiver) and DP Source (TX - transmitter) roles:
        - `DPRX5xx`.
        - `DPTX5xx`.
        - `DUTTests`.
        """
        def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
            self.__dprx = DPRX5xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
            self.__dptx = DPTX5xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer)
            self.__dut_tests = DUTTests(dev_io)

        @property
        def dprx(self) -> DPRX5xx:
            """
            Returns DP Sink (RX - receiver) role.

            Returns:
                object of DPRX5xx type.
            """
            return self.__dprx

        @property
        def dptx(self) -> DPTX5xx:
            """
            Returns DP Source (TX - transmitter) role.

            Returns:
                object of DPTX5xx type.
            """
            return self.__dptx

        @property
        def dut_tests(self) -> DUTTests:
            """
            Returns DUT Test module.

            Returns:
                object of DUTTests type.
            """
            return self.__dut_tests

        @property
        def name(self) -> str:
            """
            Returns name of role.

            Returns:
                object of str type.
            """
            return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))]

    class DPSourceUSBCSink:
        def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
            self.__port_rx = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC)
            self.__dptx = DPTX5xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer)
            self.__dprx = DPRX5xx(self.__port_rx, memory_manager, capturer)
            self.__pdcrx = PDC500(self.__port_rx)
            self.__dut_tests = DUTTests(dev_io)

        @property
        def dprx(self) -> DPRX5xx:
            """
            Returns DP Sink (RX - receiver) role.

            Returns:
                object of DPRX5xx type.
            """
            return self.__dprx

        @property
        def dptx(self) -> DPTX5xx:
            """
            Returns DP Source (TX - transmitter) role.

            Returns:
                object of DPTX5xx type.
            """
            return self.__dptx

        @property
        def pdcrx(self) -> PDC500:
            """
            Returns PDC Sink (RX - receiver) role.

            Returns:
                object of `PDC500` type.
            """
            return self.__pdcrx

        @property
        def dut_tests(self) -> DUTTests:
            """
            Returns DUT Test module.

            Returns:
                object of DUTTests type.
            """
            return self.__dut_tests

        @property
        def name(self) -> str:
            """
            Returns name of role.

            Returns:
                object of str type.
            """
            return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))]

    class USBCSourceDPSink:
        def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
            self.__port_tx = dev_io.create_port_io(1, PortProtocol.DisplayPortThrowUSBC)
            self.__dptx = DPTX5xx(self.__port_tx, memory_manager, capturer)
            self.__dprx = DPRX5xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
            self.__pdctx = PDC500(self.__port_tx)
            self.__dut_tests = DUTTests(dev_io)

        @property
        def dprx(self) -> DPRX5xx:
            """
            Returns DP Sink (RX - receiver) role.

            Returns:
                object of DPRX5xx type.
            """
            return self.__dprx

        @property
        def dptx(self) -> DPTX5xx:
            """
            Returns DP Source (TX - transmitter) role.

            Returns:
                object of DPTX5xx type.
            """
            return self.__dptx

        @property
        def pdctx(self) -> PDC500:
            """
            Returns PDC source (TX - transmitter) role.

            Returns:
                object of `PDC500` type.
            """
            return self.__pdctx

        @property
        def dut_tests(self) -> DUTTests:
            """
            Returns DUT Test module.

            Returns:
                object of DUTTests type.
            """
            return self.__dut_tests

        @property
        def name(self) -> str:
            """
            Returns name of role.

            Returns:
                object of str type.
            """
            return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))]

    class USBCSourceUSBCSink:
        def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
            self.__port_rx = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC)
            self.__port_tx = dev_io.create_port_io(1, PortProtocol.DisplayPortThrowUSBC)
            self.__dprx = DPRX5xx(self.__port_rx, memory_manager, capturer)
            self.__dptx = DPTX5xx(self.__port_tx, memory_manager, capturer)
            self.__pdcrx = PDC500(self.__port_rx)
            self.__pdctx = PDC500(self.__port_tx)
            self.__dut_tests = DUTTests(dev_io)

        @property
        def dprx(self) -> DPRX5xx:
            """
            Returns DP Sink (RX - receiver) role.

            Returns:
                object of DPRX5xx type.
            """
            return self.__dprx

        @property
        def dptx(self) -> DPTX5xx:
            """
            Returns DP Source (TX - transmitter) role.

            Returns:
                object of DPTX5xx type.
            """
            return self.__dptx

        @property
        def pdcrx(self) -> PDC500:
            """
            Returns PDC Sink (RX - receiver) role.

            Returns:
                object of `PDC500` type.
            """
            return self.__pdcrx

        @property
        def pdctx(self) -> PDC500:
            """
            Returns PDC source (TX - transmitter) role.

            Returns:
                object of `PDC500` type.
            """
            return self.__pdctx

        @property
        def dut_tests(self) -> DUTTests:
            """
            Returns DUT Test module.

            Returns:
                object of DUTTests type.
            """
            return self.__dut_tests

        @property
        def name(self) -> str:
            """
            Returns name of role.

            Returns:
                object of str type.
            """
            return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))]

    ROLE_DICT = {
        "DisplayPort Source and Sink": DPSourceDPSink,
        "DisplayPort Source and USB-C, DP Alt Mode Sink": DPSourceUSBCSink,
        "DisplayPort Sink and USB-C, DP Alt Mode Source": USBCSourceDPSink,
        "USB-C, DP Alt Mode Source and Sink": USBCSourceUSBCSink
    }
