R"""An automata component class

   Author          : Anders Andersen
\\ Created On      : Mon Mar  8 11:02:17 1999
\\ Last Modified By: 
\\ Last Modified On: Mon Jul 05 23:31:58 1999
\\ Status          : Unknown, Use with caution!

Copyright {\copyright} 1999 Lancaster University, UK and NORUT
Information Technology Ltd., Norway.  See COPYING for details.

This module implements a class that can be used to create automata
components.  The {\aacodefont AmComp} class is implemented with the
{\aacodefont Automata} and the {\aacodefont Component} class (and it
inherits the API of both these classes).  An object of the
{\aacodefont AmComp} class provides three sets of interfaces: (i)
control interfacess contains only one interface {\aacodefont a\_ctrl}
that exports the methods {\aacodefont print\_state}, {\aacodefont run}
and {\aacodefont stop}, (ii) input interfacess that contain all the
input (signal) interfaces of the automaton, and (iii) output
interfacess that contain all the output (signal) interfaces of the
automaton.  The prefix {\aacodefont a\_in\_} is added to the name of
all the input interfaces and the prefix {\aacodefont a\_out\_} is
added to the name of all the output interfaces.

An automata component can be created like this ({\aacodefont ex.fc2}
is an FC2 description of the automaton):

\begin{quote}
{\aacodefont from fc2 import FC2} \\
{\aacodefont from amcomp import AmComp}\\
{\aacodefont a = AmComp(FC2(open("ex.fc2")).fc2py)}
\end{quote}

If the automaton described in {\aacodefont ex.fc2} accepts the input
signals {\aacodefont in} and {\aacodefont out} and can produce the
output signal {\aacodefont overflow}, the following interfaces are
available (in the {\aacodefont a.interfaces} dictionary):

\begin{quote}
{\aacodefont "a\_ctrl"}: The control interface\\
{\aacodefont "a\_in\_on"}: The {\aacodefont on} input signal \\
{\aacodefont "a\_in\_off"}: The {\aacodefont off} input signal \\
{\aacodefont "a\_out\_overflow"}: The {\aacodefont overflow} output signal 
\end{quote}

The control interface exports the {\aacodefont print\_state},
{\aacodefont run} and {\aacodefont stop} methods, and the input and
output signal interfaces respectively export and import the
{\aacodefont event} method.

"""


# We need to create interfaces for the automata components
from lbind import *
from sigbind import *

# The automata component is a combination of an automata and a component
from component import Component
from automata import Automata


class EventObj:
    R"""Forwarding input events

    Each input interface use an instance of this class to forward
    input events with the right argument to the automaton.

    """
    
    def __init__(self, amc, msg):
        R"""Save automaton and event

        Save a reference to the automaton and the name of the event of
        this interface.

        """
        self.amc = amc
        self.msg = msg
        
    def event(self):
        R"""Forward input event

        Forwards the input event to the automaton.

        """
        self.amc.new_event(self.msg)

class AmComp(Automata, Component):
    R"""Automata component

    A class for automata components implemented with the {\aacodefont
    Automata} and the {\aacodefont Component} class.
    
    """

    def __init__(self, fc2py):
        R"""Initialise the automata component.

        Install the automaton description and create all interfaces
        (including the control interface and one interface for each
        input and output event).

        """
        Automata.__init__(self, self.__event__, fc2py)
        interfaces = self._make_ifaces()
        interfaces["a_ctrl"] = IRef(self, ["print_state", "run", "stop"], [])
        Component.__init__(self, interfaces, self)

    def _make_ifaces(self):
        R"""Create input and output interfaces

        Use the information about the edges from all vertice to create
        the set of input and output interfaces.  Each input interface
        is mapped to a specific input event, and each output event is
        mapped to a specific output interface.  The name of an input
        interface is the name of its event with the {\aacodefont
        a\_in\_} prefix, and the name of an output interface is the
        name of its event with the {\aacodefont a\_out\_} prefix.

        """
        interfaces = {}
        for (name, vertex) in self.vertice.items():
            if vertex.has_key("edges"):
                for (label, events) in vertex["edges"].items():
                    if label:
                        iname = "a_in_" + label
                        eobj = EventObj(self, label)
                        interfaces[iname] = SigSinkIRef(eobj)
                    for event in events:
                        if event.has_key("mesg"):
                            for msg in event["mesg"]:
                                iname= "a_out_" + msg
                                interfaces[iname] = SigSrcIRef()
        return interfaces

    def __event__(self, msg):
        R"""Forward output events

        Forward output events to the appropriate output (signal) interface.

        """
        self.interfaces["a_out_" + msg].event()
