from selve.device import Device

from selve.protocol import CommandTypeIveo, CommunicationType, DeviceClass, MethodCall, RepeaterState
from selve.protocol import ParameterType
from selve.protocol import DeviceType
from selve.commands import IveoCommand
from selve.communication import Command, CommandMask, CommandSingle
from selve.utils import true_in_list
from selve.utils import b64bytes_to_bitlist
import logging


_LOGGER = logging.getLogger(__name__)
_LOGGER.setLevel(logging.DEBUG)

    
class IveoCommandSetRepeater(Command):
    def __init__(self, repeaterState):
        super().__init__(IveoCommand.SETREPEATER, [(ParameterType.INT, repeaterState)])

class IveoCommandGetRepeater(Command):
    def __init__(self):
        super().__init__(IveoCommand.GETREPEATER)

    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.repeaterState = RepeaterState(int(methodResponse.parameters[0][1]))

class IveoCommandFactory(CommandSingle):

    def __init__(self, iveoID):
        super().__init__(IveoCommand.FACTORY, iveoID)

class IveoCommandTeach(CommandSingle):
    def __init__(self, iveoID):
        super().__init__(IveoCommand.TEACH, iveoID)

    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.executed = bool(methodResponse.parameters[0][1])   

class IveoCommandLearn(CommandSingle):
    def __init__(self, iveoID):
        super().__init__(IveoCommand.LEARN, iveoID)
    
    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.executed = bool(methodResponse.parameters[0][1]) 
         
class IveoCommandManual(CommandMask):
    def  __init__(self, mask, command):
        super().__init__(IveoCommand.MANUAL, mask, command)
    
    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.executed = bool(methodResponse.parameters[0][1]) 

class IveoCommandAutomatic(CommandMask):
    def  __init__(self, mask, command):
        super().__init__(IveoCommand.AUTOMATIC, mask, command)
    
    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.executed = bool(methodResponse.parameters[0][1])

class IveoCommandResult(MethodCall):
    def __init__(self, command, mask, state):
        super().__init__(IveoCommand.RESULT, [(ParameterType.INT, command), (ParameterType.BASE64, mask), (ParameterType.INT, state)])

class IveoCommandSetLabel(Command):
    def __init__(self, iveoId, label):
        super().__init__(IveoCommand.SETLABEL, [(ParameterType.INT, iveoId), (ParameterType.STRING, label)])

    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.executed = bool(methodResponse.parameters[0][1])

class IveoCommandSetConfig(Command):
    def __init__(self, iveoId, activity, device_type):
        super().__init__(IveoCommand.SETCONFIG, [(ParameterType.INT, iveoId), (ParameterType.INT, activity), (ParameterType.INT, device_type)])
    
    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.executed = bool(methodResponse.parameters[0][1])

class IveoCommandGetConfig(CommandSingle):
    def __init__(self, iveoId):
        super().__init__(IveoCommand.GETCONFIG, iveoId)
    
    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.name = methodResponse.parameters[0][1]
        self.activity = methodResponse.parameters[2][1]
        self.deviceType = DeviceType(int(methodResponse.parameters[3][1]))

class IveoCommandGetIds(Command):
    def __init__(self):
        super().__init__(IveoCommand.GETIDS)
    
    def process_response(self, methodResponse):
        super().process_response(methodResponse)
        self.ids = [ b for b in true_in_list(b64bytes_to_bitlist(methodResponse.parameters[0][1]))]
        _LOGGER.debug(self.ids)

class IveoDevice(Device):

    def __init__(self, gateway, iveoID, discover = False):
        super().__init__(gateway, iveoID, discover)
        self.communicationType = CommunicationType.IVEO
        self.deviceClass = DeviceClass.IVEO
        if discover:
            self.discover_properties()
    
    def executeCommand(self, commandType, automatic = False):
        if automatic:
            command = IveoCommandAutomatic(self.mask, commandType)
        else:
            command = IveoCommandManual(self.mask, commandType)
        command.execute(self.gateway)
        return command

    def discover_properties(self):
        try:
            command = IveoCommandGetConfig(self.ID)
            command.execute(self.gateway)
            self.device_type = command.deviceType
            self.name = command.name
            self.activity = command.activity
        except Exception as e1:
            _LOGGER.exception ("not : " + str(e1))

    def setRepeaterState(self, state):
        command = IveoCommandSetRepeater(state)
        command.execute(self.gateway)

    def getRepeaterState(self):
        command = IveoCommandGetRepeater()
        command.execute(self.gateway)
        return command

    def setIveoLabel(self):
        command = IveoCommandSetLabel(self.ID, self.name)
        command.execute(self.gateway)

    def setIveoConfig(self):
        command = IveoCommandSetConfig(self.ID, self.activity, self.device_type)
        command.execute(self.gateway)

    def getIveoConfig(self):
        command = IveoCommandGetConfig(self.ID)
        command.execute(self.gateway)
        self.device_type = command.deviceType
        self.name = command.name
        self.activity = command.activity

    def resetIveoChannel(self):
        command = IveoCommandFactory(self.ID)
        command.execute(self.gateway)
        self.gateway.deleteDevice(self.ID)

    def learnIveoChannel(self):
        command = IveoCommandLearn(self.ID)
        command.execute(self.gateway)

    def setToLearnMode(self):
        self.learnIveoChannel()        

    def teachIveoChannel(self, channel):
        command = IveoCommandTeach(channel)
        _LOGGER.info("Trying to teach channel " + str(channel))
        command.execute(self.gateway)
        if command.hasError:
            _LOGGER.info("Teaching failed for channel " + str(channel))
            return
        if command.executed:
            _LOGGER.info("Channel " + str(channel) + "successfully taught" )

    def manualIveoCommand(self, command):
        command = IveoCommandManual(self.mask, command)
        command.execute(self.gateway)
        return command

    def automaticIveoCommand(self, command):
        command = IveoCommandAutomatic(self.mask, command)
        command.execute(self.gateway)
        return command


    def stop(self):
        self.automaticIveoCommand(CommandTypeIveo.STOP)

    def moveDown(self):
        self.automaticIveoCommand(CommandTypeIveo.DRIVEDOWN)
    
    def moveUp(self):
        self.automaticIveoCommand(CommandTypeIveo.DRIVEUP)
    
    def moveIntermediatePosition1(self):
        self.manualIveoCommand(CommandTypeIveo.POSITION_1)

    def moveIntermediatePosition2(self):
        self.manualIveoCommand(CommandTypeIveo.POSITION_2)
    
    def deleteDevice(self):
        self.resetIveoChannel()

    def saveDevice(self):
        self.teachIveoChannel(self.ID)