from .pdc_io import PDCPortIO, PDCControlCommand, HWControlCommand
from .pdc_types import PdcDeviceRole, CCPullUp, DRPTryMode, USB3Mode, PowerRole
from .pdc_utils import support_or_not


class PcdCapsStatus:

    """
    Class `PcdCapsStatus` contains information about PDC capabilities.
    - Get initial device role `initial_role`, type `PdcDeviceRole`.
    - Get data device role `data_role`, type `PdcDeviceRole`.
    - Get power device role `power_role`, type `PowerRole`.
    - Get Cable Control Pull Up `cc_pull_up`, type `CCPullUp`.
    - Get current behavior, DRP try mode `behavior`, type `DRPTryMode`.
    - Get state of PR Swap `pr_swap`, type `bool`.
    - Get state of DR Swap `dr_swap`, type `bool`.
    - Get state of FR Swap `fr_swap`, type `bool`.
    - Get state of VCONN Swap `vconn_swap`, type `bool`.
    - Get state of Debug accessory `debug_accessory`, type `bool`.
    - Get state of Audio accessory `audio_accessory`, type `bool`.
    """

    def __init__(self, pdc_io: PDCPortIO):
        self.__io = pdc_io

    def initial_role(self) -> PdcDeviceRole:
        """
        Returns current initial role.

        Returns:
            object of `PdcDeviceRole` type
        """
        return PdcDeviceRole(self.__io.read_pdc_state().dev_role)

    def data_role(self) -> PdcDeviceRole:
        """
        Returns current data role.

        Returns:
            object of `PdcDeviceRole` type
        """
        return PdcDeviceRole(self.__io.read_pdc_status().data_role)

    def power_role(self) -> PowerRole:
        """
        Returns current power role.

        Returns:
            object of `PowerRole` type
        """
        return PowerRole(self.__io.read_pdc_status().power_role)

    def cc_pull_up(self) -> CCPullUp:
        """
        Returns current cable control pull up.

        Returns:
            object of `CCPullUp` type
        """
        return CCPullUp(self.__io.read_pdc_state().cc_pull_up)

    def behavior(self) -> DRPTryMode:
        """
        Returns current behavior of DPR mode.

        Returns:
            object of `DRPTryMode` type
        """
        return DRPTryMode(self.__io.read_pdc_state().drp_try_mode)

    def pr_swap(self) -> bool:
        """
        Returns current state of PR Swap.

        Returns:
            object of `bool` type
        """
        return bool(self.__io.read_pdc_state().pr_swap_en)

    def dr_swap(self) -> bool:
        """
        Returns current state of DR Swap.

        Returns:
            object of `bool` type
        """
        return bool(self.__io.read_pdc_state().dr_swap_en)

    def fr_swap(self) -> bool:
        """
        Returns current state of FR Swap.

        Returns:
            object of `bool` type
        """
        return bool(self.__io.read_pdc_state().fr_swap_en)

    def vconn_swap(self) -> bool:
        """
        Returns current state of VCONN Swap.

        Returns:
            object of `bool` type
        """
        return bool(self.__io.read_pdc_state().vconn_swap_en)

    def debug_accessory(self) -> bool:
        """
        Returns current state of Debug accessory.

        Returns:
            object of `bool` type
        """
        return bool(self.__io.read_pdc_state().dbg_accessory)

    def audio_accessory(self) -> bool:
        """
        Returns current state of Audio accessory.

        Returns:
            object of `bool` type
        """
        return bool(self.__io.read_pdc_state().aud_accessory)

    def __str__(self):
        status = self.__io.read_pdc_state()
        return f"PDC Capabilities:\n" \
               f"Initial role: {PdcDeviceRole(status.dev_role).name}\n" \
               f"Power role: {self.power_role().name}\n" \
               f"Data role: {self.data_role().name}\n" \
               f"CC Pull-Up: {CCPullUp(status.cc_pull_up).name}\n" \
               f"Try behavior: {DRPTryMode(status.drp_try_mode).name}\n" \
               f"PR Swap enabled: {support_or_not(status.pr_swap_en)}\n" \
               f"DR Swap enabled: {support_or_not(status.dr_swap_en)}\n" \
               f"FR Swap enabled: {support_or_not(status.fr_swap_en)}\n" \
               f"VCONN Swap enabled: {support_or_not(status.vconn_swap_en)}\n" \
               f"Debug accessory enabled: {support_or_not(status.dbg_accessory)}\n" \
               f"Audio accessory enabled: {support_or_not(status.aud_accessory)}\n"


class PcdCapsStatus340(PcdCapsStatus):

    """
    Class `PcdCapsStatus340` inherited of class`PcdCapsStatus` allows working with PDC.
    Class `PcdCapsStatus340` has all the `PcdCapsStatus` functionality.
    - Get state of USB 2.0 mode `usb20_mode`, type `bool`.
    - Get state of UCd 3.0 mode `usb30_mode`, type `USB3Mode`.
    """

    def __init__(self, pdc_io: PDCPortIO):
        super().__init__(pdc_io)

    def usb20_mode(self) -> bool:
        """
        Returns current state of USB 2.0 mode.

        Returns:
            object of `bool` type
        """
        return bool(self.__io.read_pdc_state().usb2_enabled)

    def usb30_mode(self) -> USB3Mode:
        """
        Returns current state of USB 3.0 mode.

        Returns:
            object of `USB3Mode` type
        """
        return USB3Mode(self.__io.read_pdc_state().usb30_mode)

    def __str__(self):
        status = self.__io.read_pdc_state()
        return f"PDC Capabilities:" \
               f"Initial role: {PdcDeviceRole(status.dev_role).name}\n" \
               f"CC Pull-Up: {CCPullUp(status.cc_pull_up).name}\n" \
               f"Try behavior: {DRPTryMode(status.drp_try_mode).name}\n" \
               f"USB 2 enabled: {support_or_not(status.usb2_enabled)}\n" \
               f"USB 3: {USB3Mode(status.usb30_mode).name}\n" \
               f"PR Swap enabled: {support_or_not(status.pr_swap_en)}\n" \
               f"DR Swap enabled: {support_or_not(status.dr_swap_en)}\n" \
               f"FR Swap enabled: {support_or_not(status.fr_swap_en)}\n" \
               f"VCONN Swap enabled: {support_or_not(status.vconn_swap_en)}\n" \
               f"Debug accessory enabled: {support_or_not(status.dbg_accessory)}\n" \
               f"Audio accessory enabled: {support_or_not(status.aud_accessory)}\n"


class PdcCapabilities:

    """
    Class `PdcCapabilities` allows controlling PDC capabilities.
    - Set device initial role `set_initial_role`.
    - Enable/Disable PR Swap `enable_pr_swap`.
    - Enable/Disable DR Swap `enable_dr_swap`.
    - Enable/Disable FR Swap `enable_fr_swap`.
    - Enable/Disable VCONN Swap `enable_vconn_swap`.
    - Set CC Pull Up `cc_pull_up`.
    - Set DPR try mode behavior `try_behavior`.
    - Enable/Disable Debug accessory `enable_debug_accessory`.
    - Enable/Disable Audio accessory `enable_audio_accessory`.
    """

    __device_role = {PdcDeviceRole.DFP: PDCControlCommand.SetDataRoleDFP,
                     PdcDeviceRole.UFP: PDCControlCommand.SetDataRoleUFP,
                     PdcDeviceRole.DRP: PDCControlCommand.SetDataRoleDRP}

    __cc_pull_up = {CCPullUp.Current_05_09A: PDCControlCommand.PullCCLineToDefault,
                    CCPullUp.Current_1_5A: PDCControlCommand.PullCCLineTo1_5A,
                    CCPullUp.Current_3A: PDCControlCommand.PullCCLineTo3_0A}

    __behavior = {DRPTryMode.PureDRP: PDCControlCommand.SetDataRoleDRP,
                  DRPTryMode.DRP_try_SNK: PDCControlCommand.SetDataRoleDRP_SNK_Support,
                  DRPTryMode.DRP_try_SRC: PDCControlCommand.SetDataRoleDRP_SRC_Support}

    def __init__(self, pdc_io: PDCPortIO):
        self.__io = pdc_io
        self.__status = PcdCapsStatus(self.__io)

    @property
    def status(self) -> PcdCapsStatus:
        """
        Returns current PDC Capabilities status.

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

    def set_initial_role(self, role: PdcDeviceRole):
        """
        Set device initial role.

        Args:
            role (`PdcDeviceRole`)
        """
        self.__io.write_pdc_command(self.__device_role.get(role))

    def enable_pr_swap(self, enable: bool):
        """
        Enable/Disable PR Swap.

        Args:
            enable (`bool`)
        """
        self.__io.write_pdc_command(PDCControlCommand.EnablePRSwap if enable else PDCControlCommand.DisablePRSwap)

    def enable_dr_swap(self, enable: bool):
        """
        Enable/Disable DR Swap.

        Args:
            enable (`bool`)
        """
        self.__io.write_pdc_command(PDCControlCommand.EnableDRSwap if enable else PDCControlCommand.DisableDRSwap)

    def enable_fr_swap(self, enable: bool):
        """
        Enable/Disable FR Swap.

        Args:
            enable (`bool`)
        """
        self.__io.write_pdc_command(PDCControlCommand.EnableFRSwap if enable else PDCControlCommand.DisableFRSwap)

    def enable_vconn_swap(self, enable: bool):
        """
        Enable/Disable VCONN Swap.

        Args:
            enable (`bool`)
        """
        self.__io.write_pdc_command(PDCControlCommand.EnableVconnSwap if enable else PDCControlCommand.DisableVconnSwap)

    def cc_pull_up(self, cc_pull_up: CCPullUp):
        """
        Set Cable Control Pull Up.

        Args:
            cc_pull_up (`CCPullUp`)
        """
        self.__io.write_pdc_command(self.__cc_pull_up.get(cc_pull_up))

    def try_behavior(self, behavior: DRPTryMode):
        """
        Set DRP try mode behavior.

        Args:
            behavior (`DRPTryMode`)
        """
        self.__io.write_pdc_command(self.__behavior.get(behavior))

    def enable_debug_accessory(self, enable: bool):
        """
        Enable/Disable Debug Accessory.

        Args:
            enable (`bool`)
        """
        self.__io.write_pdc_command(PDCControlCommand.EnableDebugAccessorySupport if enable else
                                    PDCControlCommand.EnableDebugAccessorySupport)

    def enable_audio_accessory(self, enable: bool):
        """
        Enable/Disable Audio Accessory.

        Args:
            enable (`bool`)
        """
        self.__io.write_pdc_command(PDCControlCommand.EnableAudioAccessorySupport if enable else
                                    PDCControlCommand.DisableAudioAccessorySupport)


class PdcCapabilities340(PdcCapabilities):

    """
    Class `PdcCapabilities340` inherited of class`PdcCapabilities` allows working with PDC.
    Class `PdcCapabilities340` has all the `PdcCapabilities` functionality.
    - Enable/Disable USB 2.0 bypass `usb_2_bypass_function`.
    - Enable/Disable USB 3.0 bypass `usb_3_bypass_function`.
    """

    def __init__(self, pdc_io: PDCPortIO):
        super().__init__(pdc_io)

    def usb_2_bypass_function(self, enable: bool):
        """
        Enable/Disable USB 2.0 bypass.

        Args:
            enable (`bool`)
        """
        self.__io.write_hw_command(HWControlCommand.Enable20PHY if enable else HWControlCommand.Disable20PHY)

    def usb_3_bypass_function(self, enable: bool):
        """
        Enable/Disable USB 3.0 bypass.

        Args:
            enable (`bool`)
        """
        self.__io.write_hw_command(HWControlCommand.Enable30PHY if enable else HWControlCommand.Disable30PHY)