# Copyright (c) 2000-2001 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

"""ComService"""

__revision__ = "$Id: ComService.py,v 1.18 2001/11/26 11:05:33 syt Exp $"

import Queue
from narval.services.BaseService import BaseService
from narval.communication import RPCFactory

# interfaces ##################################################################

class EngineListenerRegisterInterface :
    """EngineListener register interface"""

    def addEngineListener(self) :
        raise Exception("interface method not implemented")

    def removeEngineListener(self):
        raise Exception("interface method not implemented")

    def addRemoteEngineListener(self) :
        raise Exception("interface method not implemented")

    def removeRemoteEngineListener(self):
        raise Exception("interface method not implemented")

class PlanListenerRegisterInterface :
    """PlanListener register interface"""

    def addPlanListener(self) :
        raise Exception("interface method not implemented")

    def removePlanListener(self):
        raise Exception("interface method not implemented")

    def addRemotePlanListener(self) :
        raise Exception("interface method not implemented")

    def removeRemotePlanListener(self):
        raise Exception("interface method not implemented")

class MemoryListenerRegisterInterface :
    """MemoryListener register interface"""

    def addMemoryListener(self) :
        raise Exception("interface method not implemented")

    def removeMemoryListener(self):
        raise Exception("interface method not implemented")

    def addRemoteMemoryListener(self) :
        raise Exception("interface method not implemented")

    def removeRemoteMemoryListener(self):
        raise Exception("interface method not implemented")


# ComService ###################################################################

class ComService(BaseService, EngineListenerRegisterInterface,
                 PlanListenerRegisterInterface, MemoryListenerRegisterInterface) :
    """ComService XXX"""

    def __init__(self,name=None) :
        BaseService.__init__(self,name or 'ComService')
        self.queue = Queue.Queue(100)
        self.listeners={'plan':[],'memory':[],'engine':[]}

    def stop(self) :
        self.loop = 0
        self.add_event( None,None,None ) # thread blocks on self.queue.get()
        self.thread.join()
        print 'Service',self.threadName,'stopped'

    # Engine, Plan and Memory Listeners ########################################
    
    def addPlanListener(self,listener):
        self.listeners['plan'].append(listener)

    def removePlanListener(self,listener):
        planList = self.listeners['plan']
        i = 0
        for element in planList:
            if element is listener:
                planList.pop(i)
            i = i+1
            
    def addMemoryListener(self,listener):
        self.listeners['memory'].append(listener)

    def removeMemoryListener(self,listener):
        memList = self.listeners['memory']
        i = 0
        for element in memList:
            if element is listener:
                memList.pop(i)
            i = i+1        

    def addEngineListener(self,listener):
        self.listeners['engine'].append(listener)

    def removeEngineListener(self,listener):
        engineList = self.listeners['engine']
        i = 0
        for element in engineList:
            if element is listener:
                engineList.pop(i)
            i = i+1

    def addRemotePlanListener(self, uri):
        if not self.listeners.has_key(('remoteplan', uri)):
            listener = RPCFactory.create_proxy(uri)
            listener.__dict__['_narval_uri_'] = uri
            self.listeners[('remoteplan',uri)]=listener
            self.addPlanListener(listener)

    def removeRemotePlanListener(self, uri):
        listener = self.listeners.get(('remoteplan', uri))
        if listener is not None:
            del self.listeners[('remoteplan',uri)]
            self.removePlanListener(listener)
    
    def addRemoteMemoryListener(self, uri):
        if not self.listeners.has_key(('remotememory', uri)):
            listener = RPCFactory.create_proxy(uri)
            listener.__dict__['_narval_uri_'] = uri
            self.listeners[('remotememory',uri)]=listener
            self.addMemoryListener(listener)

    def removeRemoteMemoryListener(self, uri):
        listener = self.listeners.get(('remotememory', uri))
        if listener is not None:
            del self.listeners[('remotememory',uri)]
            self.removeMemoryListener(listener)

    def addRemoteEngineListener(self, uri):
        if not self.listeners.has_key(('remoteengine', uri)):
            listener = RPCFactory.create_proxy(uri)
            listener.__dict__['_narval_uri_'] = uri
            self.listeners[('remoteengine',uri)]=listener
            self.addEngineListener(listener)

    def removeRemoteEngineListener(self, uri):
        listener = self.listeners.get(('remoteengine',uri))
        if listener is not None:
            del self.listeners[('remoteengine',uri)]
            self.removeEngineListener(listener)

    def add_event(self,target,method,args) :
        self.queue.put( (target, method, args) )


    # private ##################################################################
    def _fire_event(self,target,method,args):
        for listener in self.listeners[target]:
            try:
                apply(getattr(listener, method), args)
            except Exception, e:
                print 'comService error'
                import traceback
                traceback.print_exc()
                try:
                    uri = listener.__dict__['_narval_uri_']
                    if target == 'plan':
                        self.removeRemotePlanListener(uri)
                        print 'remove remote plan listener %s'% (uri)
                    elif target == 'memory':
                        self.removeRemoteMemoryListener(uri)
                        print 'remove remote memory listener %s'% (uri)
                    elif target == 'engine':        
                        self.removeRemoteEngineListener(uri) 
                        print 'remove remote engine listener %s'% (uri)
                except AttributeError:
                    pass
                except Exception, e:
                    print 'error calling %s(%s) on listener %s' % (method, args,
                                                                   listener)
                    import traceback
                    traceback.print_exc()
    
    def _run(self) :
        while self.loop :
            target, method, args = self.queue.get()
            if target and method :
                self._fire_event(target, method, args)

