
import asyncore, asynchat, socket


class LircChat(asynchat.async_chat):

    def __init__(self, host = "127.0.0.1", port = 8765, ButtonCallBack= None):
        asynchat.async_chat.__init__(self)
        self.set_terminator("\n")
        self.host = host
        self.port = port
        self.ButtonCallBack = ButtonCallBack

        self.Connected = False
        self.CodeList = list()
        self.CommandResponse = list()

        self.BusyFlag = False
        try:
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
            self.connect((host, port))
        except socket.error, (value,message): 
            print "Could not open socket: " + message 
            self.close()          
        if not self.Connected:
            asyncore.poll()


    def handle_close(self):
        print "Handle_close:"
        self.close()
        self.Connected = False

    def handle_connect(self):
##        print "Handle_connect:"
        self.Connected = True

    def handle_expt(self):
        self.close()

    def collect_incoming_data(self, data):
        self.data = self.data + data
##        print self.data

    def found_terminator(self):
        self.InString = self.data.rstrip()
        self.data = ""
##        print "found terminator"
##        print self.InString
##        print self.BusyFlag

        if self.BusyFlag:
            self.packet.append(self.InString)
            if self.InString == "END":
                self.CommandResponse = self.packet
                self.packet = []
                self.BusyFlag = False

        else:
            self.CodeList.append(self.InString)
            self.packet = []
            if self.ButtonCallBack:
##                print "Calling ButtonCallBack"
                self.ButtonCallBack()

    def GetNextCode(self):
##        print "getting next code"
        if len(self.CodeList) >= 1:
            nextCode = self.CodeList.pop(0)
            codelist = nextCode.split()
            if len(codelist) == 4:
                code = tuple([codelist[1],codelist[2],codelist[3]])
            return code
        else:
            return None

    def GetCodeCount(self):
        return len(self.CodeList)

    def SendDirective(self, CallBack= None, directive = None):
        print "send directive",directive
        if self.Connected:
            if not directive == None:
                self.directive = directive + "\n"
                print "Pushing :",directive
                self.BusyFlag = True
                self.data = ""
                self.packet = []
                self.push(str(self.directive))
                while self.BusyFlag == True:
                    asyncore.poll()

    def SendOnce(self, remote = "", key = "", count = 0):
        self.SendDirective("SEND_ONCE %s %s %d" % (remote, key, count))

    def GetList(self):
        RemoteList = []
        Remotes = ()
        Commands = []
        self.SendDirective(directive = "LIST")
        while self.BusyFlag == True:
            asyncore.poll()

        if "SUCCESS" in self.CommandResponse:
            Remotes = self.CommandResponse[5:-1]

        index = -1
        for remote in Remotes:
            self.SendDirective(directive = "LIST " + remote)
            while self.BusyFlag == True:
                asyncore.poll()

            if "SUCCESS" in self.CommandResponse:
                Commands=[]
                for command in self.CommandResponse[5:-1]:
                    templist = command.split()
                    Commands.append(templist[-1])

                RemoteList.append((remote,Commands))

        if RemoteList : return RemoteList
        else: return None

    def GetVersion(self):
        """Query the Lirc Server for its Version.

        Returns None on error, The Version String on Success"""

        Version = None
        self.SendDirective(directive = "VERSION")
        while self.BusyFlag == True:
            asyncore.poll()

        if "SUCCESS" in self.CommandResponse:
            Version = self.CommandResponse[5]
            return Version
        else:
            return None

Logging = True
def Log(Data = 'Log Entry'):
    if Logging :
        print Data
    else:
        pass


ExitFlag = False

def main():
    print "testing main"
    Chat = LircChat(host="192.168.2.1", port = 8765, ButtonCallBack = PrintCode)
    while not Chat.Connected:
        print "waiting to connect"
        asyncore.poll()
        
    Log(Chat.GetVersion())
    print Chat.GetList()

def PrintCode(MyChat):
    while MyChat.GetCodeCount():
        code = MyChat.GetNextCode()
        print code
        print "Remote:%s, Button:%s, Repeat:%s" % (code[2],code[1],code[0])


if __name__ == '__main__':
    main()
