import time
import pprint
import uuid
import json
from collections import OrderedDict
from director.thirdparty import numpyjsoncoder
from director import callbacks
from director.utime import getUtime
from director.uuidutil import newUUID
try:
    import bot_core as lcmbotcore
    USE_LCM = True
except ImportError:
    USE_LCM = False
if USE_LCM:
    from director import lcmUtils
[docs]class LCMObjectCollection(object):
    DESCRIPTION_UPDATED_SIGNAL = 'DESCRIPTION_UPDATED_SIGNAL'
    DESCRIPTION_REMOVED_SIGNAL = 'DESCRIPTION_REMOVED_SIGNAL'
    def __init__(self, channel):
        self.collection = OrderedDict()
        self.collectionId = newUUID()
        self.sentCommands = set()
        self.sentRequest = None
        self.channel = channel
        self.callbacks = callbacks.CallbackRegistry([self.DESCRIPTION_UPDATED_SIGNAL,
                                                     self.DESCRIPTION_REMOVED_SIGNAL])
        self.sub = None
        self._modified()
        if USE_LCM:
            self.sub = lcmUtils.addSubscriber(self.channel, messageClass=lcmbotcore.system_status_t, callback=self._onCommandMessage)
            self.sub.setNotifyAllMessagesEnabled(True)
    def __del__(self):
        if self.sub:
            lcmUtils.removeSubscriber(self.sub)
[docs]    def connectDescriptionUpdated(self, func):
        return self.callbacks.connect(self.DESCRIPTION_UPDATED_SIGNAL, func) 
[docs]    def disconnectDescriptionUpdated(self, callbackId):
        self.callbacks.disconnect(callbackId) 
[docs]    def connectDescriptionRemoved(self, func):
        return self.callbacks.connect(self.DESCRIPTION_REMOVED_SIGNAL, func) 
[docs]    def disconnectDescriptionRemoved(self, callbackId):
        self.callbacks.disconnect(callbackId) 
[docs]    def getDescriptionId(self, desc):
        return desc['uuid'] 
[docs]    def prettyPrintCollection(self):
        print json.dumps(json.loads(numpyjsoncoder.encode(self.collection)), indent=2) 
[docs]    def getDescription(self, descriptionId):
        return self.collection[descriptionId] 
[docs]    def updateDescription(self, desc, publish=True, notify=True):
        self.collection[self.getDescriptionId(desc)] = desc
        self._modified()
        if publish and USE_LCM:
            msg = self._newCommandMessage('update', description=desc)
            lcmUtils.publish(self.channel, msg)
        if notify:
            self.callbacks.process(self.DESCRIPTION_UPDATED_SIGNAL, self, self.getDescriptionId(desc)) 
[docs]    def removeDescription(self, descriptionId, publish=True, notify=True):
        try:
            del self.collection[descriptionId]
            self._modified()
        except KeyError:
            pass
        if publish and USE_LCM:
            msg = self._newCommandMessage('remove', descriptionId=descriptionId,)
            lcmUtils.publish(self.channel, msg)
        if notify:
            self.callbacks.process(self.DESCRIPTION_REMOVED_SIGNAL, self, descriptionId) 
[docs]    def sendEchoRequest(self):
        self.sentRequest = newUUID()
        msg = self._newCommandMessage('echo_request', requestId=self.sentRequest)
        lcmUtils.publish(self.channel, msg) 
[docs]    def sendEchoResponse(self, requestId=None):
        if requestId is None:
            requestId = newUUID()
        msg = self._newCommandMessage('echo_response', requestId=requestId, descriptions=self.collection)
        lcmUtils.publish(self.channel, msg) 
[docs]    def handleEchoResponse(self, data):
        #if data['requestId'] != self.sentRequest:
        #    return
        self.sentRequest = None
        for desc in data['descriptions'].values():
            self.updateDescription(desc, publish=False) 
    def _modified(self):
        self.mtime = getUtime()
    def _newCommandMessage(self, commandName, **commandArgs):
        commandId = newUUID()
        self.sentCommands.add(commandId)
        commandArgs['commandId'] = commandId
        commandArgs['collectionId'] = self.collectionId
        commandArgs['command'] = commandName
        msg = lcmbotcore.system_status_t()
        msg.value = numpyjsoncoder.encode(commandArgs)
        msg.utime = getUtime()
        return msg
    def _onCommandMessage(self, msg):
        data = numpyjsoncoder.decode(msg.value)
        commandId = data['commandId']
        if commandId in self.sentCommands:
            self.sentCommands.remove(commandId)
            return
        command = data['command']
        if command == 'update':
            desc = data['description']
            self.updateDescription(desc, publish=False)
        elif command == 'remove':
            self.removeDescription(data['descriptionId'], publish=False)
        elif command == 'echo_request':
            self.sendEchoResponse(data['requestId'])
        elif command == 'echo_response':
            self.handleEchoResponse(data)