"""Exports Dispatcher and Collective, the fundamental container classes
for group behavior in the game. The idea is that whenever Agents need 
to cooperate, they should be organized as members of a Dispatcher or 
Collective and let this higher level orchestrate all its members 
interaction and cooperation. Dispatchers/Collectives can form a hierarchy
themselves, depending on the particular task. For example, a Collective 
can own and control other collectives, or be a member of some Dispatcher. 

-- Dispatcher is an Agent that has a number of Agents (members) reporting 
to it. Dispatcher does not own its Agents  but can send commands to them 
and listens to their reports.

Example 1. In the SmallGame 'attack' messages passed from the attacker 
are processed by Fight Dispatcher rather than sending them directly to the 
target. When player attacks, it is not immediately obvious who is the target. 
Dispatcher decides who is attacked. Such Dispatcher also can be used to 
break destructable objects from Agent's attacks.

Example 2. Agents that belong to different groups can have conversation 
if they are members of Conversation Dispatcher. This Dispatcher can be 
either active all the time or can be created dynamically.

-- Collective owns its members so it is responsible for spawning them and
updating them. 

Example 3. Groups are a typical example of a Collective. A group spawns
enemies, keeps their count and spawns more when some get killed. Also
the group sends Agents to attack or do other coordinated tasks.

Example 4. Many other objects can be implemented as a Collective. 
An Actor owns subsystems (Visual, animPlayer and Movement) that are Agents. 
Actor controls them by listening to their reports and sending commands to 
them.
"""

import agent

class Dispatcher(agent.ScriptableAgent):
    """Dispatcher is a ScriptabelAgent (FSM with messaging) that sends 
    commands to the reporting Agents, listens to the input messages (reports) 
    from its members and can run a script on itself. 
    
    Unlike its derivative class Collective, Dispatcher does not own its 
    members, meaning that it is not responsible for creating them. 
    Also on update it does not update them nor clears their queues."""

    def __init__(self, name="",script=None):
        self.dispatcher_debug = 0
        agent.ScriptableAgent.__init__(self, name, script)
        self.members = []

    def trace(self, args):
        if (self.dispatcher_debug):
            print self.name+": "+str(args)

    def addMember(self,member):
        """Appends a new member to the members list. 
        Members on the Dispatcher's list are NOT updated 
        when Dispatcher is updated."""
        self.members.append(member)

class Collective(Dispatcher):
    """Collective is a Dispatcher that owns its members, other agents. 
    It runs update on them and manages their in/out message queues. Also it
    is responsible for creating its members."""
    def __init__(self, name="",script=None):
        self.collective_debug = 0
        Dispatcher.__init__(self, name, script)

    def trace(self, args):
        if (self.collective_debug):
            print self.name+": "+str(args)

    def update(self, timeInc = 1):
        """Updates members, clears their in-queue to prepare it for the new commands,
        runs update for itself, clears out-queue for the members."""
        for m in self.members:
            m.update(timeInc)
            m.clearInQueue(timeInc)
        agent.Agent.update(self,timeInc)
        for m in self.members:
            m.clearOutQueue(timeInc)