# Copyright (c) 2004 DoCoMo Euro-Labs GmbH (Munich, Germany).
# Copyright (c) 2001-2004 LOGILAB S.A. (Paris, FRANCE).
#
# http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
"""interfaces used in the narval interpreter and narval clients


:version: $Revision:$  
:author: Logilab

:copyright:
  2001-2004 LOGILAB S.A. (Paris, FRANCE)
  
  2004 DoCoMo Euro-Labs GmbH (Munich, Germany)
  
:contact:
  http://www.logilab.fr/ -- mailto:contact@logilab.fr
  
  http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com
"""

__revision__ = '$Id: interfaces.py 20 2004-04-15 14:43:51Z syt $'
__docformat__ = "restructuredtext en"


from narval.public import Interface


# listeners ####################################################################

class IMemoryChangeListener(Interface):
    """memory change listener interface"""

    def memory_change(self, action, element, old_element=None):
        """memory change hook, called when an element has been added, removed
        or replaced in memory

        :type action: str
        :param action:
          one of 'add', 'remove', 'replace' according to the change's type
        
        :type element: `narval.public.ALElement`
        :param element: the element which has changed in the memory

        :type old_element: `narval.public.ALElement`
        :param old_element:
          the element being replaced in case of a 'replace' action, None for
          all other actions
        """

class IElementChangeListener(Interface):
    """element change listener interface"""

    def element_change(self, element):
        """an element has been modified in memory

        :type element: `narval.public.ALElement`
        :param element: the modified element
        """

class IPlanChangeListener(Interface):
    """plan change listener interface"""

    def plan_change(self, plan, action='state', element=None):
        """plan change hook, called when plan's status has changed or when an
        element has been added or removed in the plan's memory
        
        :type plan: `narval.plan.PlanElement`
        :param plan: the changing plan

        :type action: str
        :param action:
          one of 'state', 'add' or 'remove' according to the change's type
        
        :type element: `narval.public.ALElement`
        :param element:
          the element which has been added or removed in the plan's memory,
          implying action in ('add', 'remove')
        """

class IStepChangeListener(Interface):
    """step change listener interface"""

    def step_change(self, step):
        """step change hook, called when a step's status has changed

        :type step: `narval.plan.PlanStep`
        :param step: the step who's status changed
        """

class ITransitionChangeListener(Interface):
    """transition change listener interface"""

    def transition_change(self, transition):
        """transition change hook, called when a transition's status has
        changed

        :type transition: `narval.plan.PlanTransition`
        :param transition: the transition who's status changed
        """

class IMemoryListener(Interface):
    """memory listener interface"""

    def add_element(self, eid):
        """a new element has been added to the memory

        :type eid: int
        :param eid: the eid of the newly added element
        """

    def remove_element(self, eid):
        """an element has been removed from the memory

        :type eid: int
        :param eid: the eid of the removed element
        """

    def replace_element(self, eid):
        """an element has been replaced from the memory

        :type eid: int
        :param eid: the eid of the replaced element
        """

class IPlanListener(Interface):
    """plan listener Interface"""
    
    def fire_transition(self, plan_eid, transition_eid):
        """a transition has been fired

        :type plan_eid: int
        :param plan_eid: the eid of the plan where the transition has been fired

        :type transition_eid: int
        :param transition_eid: the eid of the transition which has been fired
        """

    def transition_status_changed(self, plan_eid, transition_eid, status):
        """a transition's status changed

        :type plan_eid: int
        :param plan_eid: the eid of the plan where the transition has changed

        :type transition_eid: int
        :param transition_eid: the eid of the transition which has changed

        :type status: str
        :param status: the new transition's status
        """

    def step_status_changed(self, plan_eid, step_eid, status):
        """a step's status changed

        :type plan_eid: int
        :param plan_eid: the eid of the plan where the step has changed

        :type step_eid: int
        :param step_eid: the eid of the step which has changed

        :type status: str
        :param status: the new step's status
        """

    def plan_status_changed(self, plan_eid, status):
        """a plan's status changed

        :type plan_eid: int
        :param plan_eid: the eid of the plan which has changed

        :type status: str
        :param status: the new step's status
        """

    def instanciate_recipe(self, plan_eid, recipe_name):
        """a recipe has been instantiated

        :type plan_eid: int
        :param plan_eid: the eid of the plan which has been instantiated
        
        :type recipe_name: str
        :param recipe_name:
          the name of the recipe instantiated (<cookbook>.<recipe>)
        """

    def plan_add_element(self, plan_eid, eid):
        """an element has been added from the plan

        :type plan_eid: int
        :param plan_eid: the eid of the plan where the element has been added
        
        :type eid: int
        :param eid: the eid of the element which has been added
        """
        
    def plan_remove_element(self, plan_eid, eid):
        """an element has been removed from the plan

        :type plan_eid: int
        :param plan_eid: the eid of the plan where the element has been removed
        
        :type eid: int
        :param eid: the eid of the element which has been removed
        """

class IEngineListener(Interface):
    """engine listener interface"""

    def post_scheduler_event(self, event, text):
        """an event has been scheduled
        
        :type event: str
        :param event: the event identifier
        
        :type text: str
        :param text: the event as a string
        """

    def post_queue_event(self, event, text):
        """an event has been added to the event queue
        
        :type event: str
        :param event: the event identifier
        
        :type text: str
        :param text: the event as a string
        """

    def pop_queue_event(self, event):
        """an event has been poped from the queue
        
        :type event: str
        :param event: the event identifier
        """


# Narval interpreter's interfaces ##############################################

class IThreadMgmt(Interface):
    """interface defining engine methods used to manipulate EngineThreads
    """

    def create_thread(self, *args, **kwargs):
        """add a thread to the thread queue and return immediatly, even if there
        is already the maximum number of threads running so that the newly
        created (well, futur) has to wait another to finish
        
        :param args: arguments list given to the thead constructor
        :param kwargs: named arguments dictionary given to the thead constructor
        """

    def end_of_thread(self):
        """notify a thread end"""

class IMessage(Interface):
    """interface defining Engine methods used for inter-agent communication
    """

    def post_message(self, message_xml):
        """post a message from another agent
        
        :type message_xml: str
        :param message_xml: the xml string describing the message
        """        
    
class IDebug(Interface):
    """interface defining engine methods used for to control debugging
    """

    def debug_suspend(self):
        """suspend execution"""
        
    def debug_continue(self):
        """resume execution"""

    def debug_step_one_step(self):
        """run one execution's step

        :rtype: bool
        :return: the value of the flag indicating if we are in debug mode
        """

class IInteraction(Interface):
    """interface defining engine methods used to interact with the main memory
    """

    def get_memory(self):
        """return the narval's main memory as an xml string

        :rtype: str
        :return: the main memory's content as XML
        """

    def get_element(self, eid):
        """return the element with the given identifier as an xml string, or
        None if no element with the given eid exists in memory

        :type eid: int
        :param eid: the identifier of the element to retreive

        :rtype: str or None
        :return: the element with the given identifier as XML if found 
        """

    def add_element(self, element_xml):
        """add a new element as an xml string to the memory

        :type element_xml: str
        :param element_xml: an XML string representing the element to add
        """

    def remove_element(self, eid):
        """remove the element with the given eid from the memory
        
        :type eid: int
        :param eid: the identifier of the element to remove
        """

    def replace_element(self, eid, new_element_xml):
        """replace the element with the given eid by the given new element (as
        an xml string)

        :type eid: int
        :param eid: the identifier of the element to replace

        :type new_element_xml: str
        :param new_element_xml:
          an XML string representing the element that will replace the old one
        """

    def start_plan(self, recipe_name, elements=()):
        """build a plan from the given recipe

        :type recipe_name: str
        :param recipe_name:
          the name of the recipe to instantiate (cookbook.recipe)

        :type elements: list or tuple or None
        :param elements: list of elements constituing the initial plan's memory
        """

    def save_recipes(self):
        """save all recipes (cookbooks) in memory"""

    def shutdown(self):
        """shutdown the narval interpreted"""

##     def get_elementsList(self):
##         raise NotImplementedError()

##     def get_element_list(self, eid):
##         raise NotImplementedError()

# narval'service interface ####################################################

class IService(Interface):
    """service interface"""

    def start(self) :
        """start the service"""

    def stop(self) :
        """stop the service"""

# narval's protocol handler interface #########################################

class IProtocolHandler(Interface):
    """interface of a protocol handler"""
    
    def get_prototype(self):
        """returns an XML string defining the prototype for the handler
        
        The string is a valid XML document, according to the protocol
        handler's prototype DTD

        :rtype: str
        :return: the XML snippet defining the protocol handler's prototype
        """
        
    def activate(self, activator):
        """activates the handler with the given element.
        
        A handler can be activated more than once, and should behave
        accordingly. For instance an HTTP handler can be activated on
        different ports. The handler should use the eid of the element
        to be able to deactivate the proper service.

        :type activator: `narval.public.ALElement`
        :param activator: the element activating the handler
        
        :raise HandlerAlreadyActivated:
          if the activate method already has been called with a semantically
          identical activator
        """
        
    def deactivate(self, eid):
        """deactivates the handler.
        
        :type eid: int
        :param eid: the eid of the element deactivating the handler
        
        :raise HandlerNotActivated:
          if the handler had not been activated with the element
        """

    def handle_outgoing(self, element):
        """passes an element matching one of the inputs of the handler.
        
        :raise `HandlerNotActivated`:
          if the handler has not been activated, or has not been activated to
          handle the input, or is not expecting any input.

        :type element: `narval.public.ALElement`
        :param element: the outgoing element
        """

    def stop(self):
        """stops the handler: stops all threads launched by the handler, if any
        """

    def register(self, registry):
        """register specific stuff for this protocol handler

        :type registry: `narval.reader.Registry`
        :param registry: the interpreter's registry
        """

