from ctypes import Structure, c_uint32, c_uint64
from enum import IntEnum
from .pdc_types import CCPullUp, ContractTypePriority, DRPTryMode, USB3Mode, PdcDeviceRole, PDMode


class HWControlCommand(IntEnum):
    DoNothing = 0x00
    ToggleCableFlip = 0x01
    SetCableFlipToOff = 0x02
    SetCableFlipToOn = 0x03
    EnableUSBDeviceCharger = 0x04
    DisableUSBDeviceCharger = 0x05
    SwitchToHostMode = 0x06
    SwitchToDeviceMode = 0x07
    Enable20PHY = 0x08
    Disable20PHY = 0x09
    Enable20PHYDeviceModeEnableCharger = 0x0A
    Enable20PHYHostModeDisableCharger = 0x0B
    Disable20PHYDisableCharger = 0x0C
    DisableIntLoad_5_5_ohm = 0x0E
    EnableIntLoad_5_5_ohm = 0x0F
    DisableIntLoad_3_5_ohm = 0x10
    EnableIntLoad_3_5_ohm = 0x11
    DisableIntLoad_10_ohm = 0x12
    EnableIntLoad_10_ohm = 0x13
    DisconnectCCLines = 0x14
    ConnectCCLines = 0x15
    RePlugCable = 0x16
    SetNewETCableMode = 0x18
    SetOldETCableMode = 0x19
    Enable30PHY = 0x1A
    Disable30PHY = 0x1B
    ResetPDController = 0x1C


class PDCControlCommand(IntEnum):
    DoNothing = 0x00
    ToggleDataRole = 0x01
    SetDataRoleUFP = 0x02
    SetDataRoleDFP = 0x03
    SwapVconn = 0x04
    TogglePowerRole = 0x05
    FastRoleSwap = 0x06
    HardReset = 0x07
    SimulateReConnect = 0x0A
    PullCCLineToDefault = 0x0C
    PullCCLineTo1_5A = 0x0D
    PullCCLineTo3_0A = 0x0E
    SetDataRoleDRP = 0x14
    SetDataRoleDRP_SNK_Support = 0x15
    SetDataRoleDRP_SRC_Support = 0x16
    DisableUSB3 = 0x18
    EnableUSB3_gen1 = 0x19
    EnableUSB3_gen2 = 0x1A
    DisableUSB2 = 0x1C
    EnableUSB2 = 0x1D
    DisableVconnSwap = 0x1E
    EnableVconnSwap = 0x1F
    DisablePRSwap = 0x20
    EnablePRSwap = 0x21
    DisableDRSwap = 0x22
    EnableDRSwap = 0x23
    DisableDebugAccessorySupport = 0x24
    EnableDebugAccessorySupport = 0x25
    DisableAudioAccessorySupport = 0x26
    EnableAudioAccessorySupport = 0x27
    DisableFRSwap = 0x28
    EnableFRSwap = 0x29
    SetFRSwapNoSupported = 0x2A
    SetFRSwapUSBPower = 0x2B
    SetFRSwap1_5A_5V = 0x2C
    SetFRSwap3A_5V = 0x2C
    EnableEPRasPowerSink = 0x2E
    DisableEPRasPowerSink = 0x2F
    EnableEPRAutoEnter = 0x30
    DisableEPRAutoEnter = 0x31
    InitiateEPRModeEnter = 0x32
    InitiateEPRModeExit = 0x33
    EnableRejectEPRModeEnter = 0x34
    DisableRejectEPRModeEnter = 0x35
    SendSourceCaps = 0x41


class HWCaps(Structure):
    _fields_ = [
        ('', c_uint32, 1),
        ('et_board', c_uint32, 1),
        ('', c_uint32, 2),
        ('pdo_count', c_uint32, 4),
        ('', c_uint32, 24)
    ]


class HWStatus(Structure):
    _fields_ = [
        ('cable_flip', c_uint32, 1),
        ('ext_power', c_uint32, 1),
        ('charger', c_uint32, 1),
        ('usb_mode', c_uint32, 1),
        ('usb_20_phy', c_uint32, 1),
        ('et_cable', c_uint32, 1),
        ('int_3_5_ohm', c_uint32, 1),
        ('int_10_ohm', c_uint32, 1),
        ('cc1_closed', c_uint32, 1),
        ('cc2_closed', c_uint32, 1),
        ('int_5_5_ohm', c_uint32, 1),
        ('et_cable_mode', c_uint32, 1),
        ('usb_30_phy', c_uint32, 1),
        ('int_3_5_ovp', c_uint32, 1),
        ('int_10_ovp', c_uint32, 1),
        ('int_5_5_ovp', c_uint32, 1),
        ('', c_uint32, 13),
        ('pdc_fault', c_uint32, 1),
        ('', c_uint32, 1),
        ('pdc_reset', c_uint32, 1)
    ]


class PDCStatus(Structure):
    _fields_ = [
        ('cable_plug', c_uint64, 1),
        ('cable_orientation', c_uint64, 1),
        ('power_role', c_uint64, 1),
        ('data_role', c_uint64, 1),
        ('rmt_snk_pdo', c_uint64, 1),
        ('rmt_src_pdo', c_uint64, 1),
        ('pwr_contract', c_uint64, 1),
        ('rmt_svid', c_uint64, 1),
        ('vconn_enabled', c_uint64, 1),
        ('emarked_cable', c_uint64, 1),
        ('dp_alt_mode', c_uint64, 1),
        ('usb_device', c_uint64, 1),
        ('usb_host', c_uint64, 1),
        ('usb_2_conn', c_uint64, 1),
        ('usb_3_conn', c_uint64, 1),
        ('sop_identity', c_uint64, 1),
        ('current', c_uint64, 2),
        ('adc_data', c_uint64, 1),
        ('am_sw_inprog', c_uint64, 1),
        ('pullup_sence', c_uint64, 2),
        ('rx_identity', c_uint64, 1),
        ('', c_uint64, 6),
        ('pdc_fault', c_uint64, 1),
        ('', c_uint64, 2),
        ('rx_sink_pdp', c_uint64, 1),
        ('rx_source_pdp', c_uint64, 1),
        ('rx_snk_epr_pdo', c_uint64, 1),
        ('rx_src_epr_pdo', c_uint64, 1),
        ('', c_uint64, 28)
    ]


class PDCState(Structure):
    _fields_ = [
        ('cc_pull_up', c_uint32, 2),
        ('dev_role', c_uint32, 2),
        ('pd_mode', c_uint32, 2),
        ('usb30_mode', c_uint32, 2),
        ('usb2_enabled', c_uint32, 1),
        ('vconn_swap_en', c_uint32, 1),
        ('pr_swap_en', c_uint32, 1),
        ('dr_swap_en', c_uint32, 1),
        ('dbg_accessory', c_uint32, 1),
        ('aud_accessory', c_uint32, 1),
        ('fr_swap_en', c_uint32, 1),
        ('', c_uint32, 1),
        ('drp_try_mode', c_uint32, 2),
        ('', c_uint32, 2),
        ('epr_snk_en', c_uint32, 1),
        ('epr_auto_enter_en', c_uint32, 1),
        ('epr_mode', c_uint32, 1),
        ('epr_enter_en', c_uint32, 1),
    ]

    @property
    def cc_pull_up(self) -> CCPullUp:
        return CCPullUp(self.cc_pull_up)

    @property
    def dev_role(self) -> PdcDeviceRole:
        return PdcDeviceRole(self.dev_role)

    @property
    def pd_mode(self) -> PDMode:
        return PDMode(self.pd_mode)

    @property
    def usb30_mode(self) -> USB3Mode:
        return USB3Mode(self.usb30_mode)

    @property
    def drp_try_mode(self) -> DRPTryMode:
        return DRPTryMode(self.drp_try_mode)


class PDCCaps(Structure):
    _fields_ = [
        ('try_snk', c_uint32, 1),
        ('try_src', c_uint32, 1),
        ('fr_swap', c_uint32, 1),
        ('cable_sim', c_uint32, 1),
        ('ext_sink_pc', c_uint32, 1),
        ('align_dp_usb', c_uint32, 1),
        ('', c_uint32, 16)
    ]


class PDCContractInfo(Structure):
    _fields_ = [
        ('auto_negotate', c_uint32, 1),
        ('use_battery_pdo', c_uint32, 1),
        ('use_variable_pdo', c_uint32, 1),
        ('comm_capable', c_uint32, 1),
        ('type_priority', c_uint32, 2),
        ('no_usb_suspend', c_uint32, 1),
        ('give_back_flag', c_uint32, 1),
        ('auto_min_power', c_uint32, 1),
        ('', c_uint32, 6),
        ('min_power', c_uint32, 10),
        ('', c_uint32, 5),
        ('manual', c_uint32, 1),
    ]

    def value(self) -> int:
        return self.auto_negotate | self.use_battery_pdo << 1 | self.use_variable_pdo << 2 | self.comm_capable << 3 | \
               self.type_priority << 4 | self.no_usb_suspend << 6 | self.give_back_flag << 7 | \
               self.auto_min_power << 8 | self.min_power << 15 | self.manual << 31
