package vcb.vt.app;


import vcb.engine.part.Receiver;
import vcb.engine.tron.Datatron;
import vcb.gen.io.DatatronStore;
import vcb.gen.util.ListOne;
import java.util.HashMap;

/**
* This provides nodes with standard services, using the Context
* Pattern. Not all nodes will use all services.
*
* Creation using the constructor creates a new instance with 
* an event registry. Creating a new instance with the create 
* method copies the registry and other properties to the new 
* instance. This allows many nodes to share the same properties 
* and event registry. 
*
* This allows the system designer to design a tree of subsystems. 
* Each subsystem has a NodeContext. They all share certain 
* services, the most powerful being the event registry, which 
* allows a node anywhere in the system to send an event to any 
* other node(s) in the system. 
* 
* @author Jack Harich 
*/ // import vcb.vt.app.NodeContext;
 
public class NodeContext {
 
//---------- Internal Fields ------------------------------------- 
//----- These are all one per system 
protected DatatronStore userConfig; 
protected WindowMgr windowMgr = new WindowMgr(); 
protected PartStore partStore = new PartStore(); 

// Key = String event name, Object = ListOne of Receivers 
protected HashMap listeners = new HashMap();
 
//----- These vary per node protected Receiver receiver; 
//---------- Initialization -------------------------------------- 
/** 
* Creates a new instance. All aguments are required. Note that 
* create(...) must be used to set the receiver property. 
*/ 
public NodeContext(DatatronStore userConfig) { 
    this.userConfig = userConfig; 
}
/** 
* Creates a new context from this one, replacing the old receiver 
* (if any) with the new one provided, which may be null. 
*/
public NodeContext create(Receiver receiver) {
    NodeContext context = new NodeContext(userConfig); 
    context.receiver = receiver; 
    context.windowMgr = windowMgr; 
    context.partStore = partStore; 
    context.listeners = listeners; 
    return context; 
} 
//---------- Public Methods -------------------------------------- 
//----- Getters 
/** 
* Returns the user config store. 
*/ 
public DatatronStore getUserConfig() { 
    return userConfig; 
} 
/** 
* Returns the window manager. 
*/ 
public WindowMgr getWindowMgr() { 
    return windowMgr; 
} 
/** 
* Returns the part store. 
*/ 
public PartStore getPartStore() { 
    return partStore; 
} 
/** 
* Returns the receiver, which is null if none. 
*/ 
public Receiver getReceiver() {
    return receiver; 
} 
//----- Events 
/** 
* Registers the listener for the eventName. 
*/ 
public void addContextListener(String eventName, Receiver listener) { 
//print(".addListener() - eventName = " + eventName + ", " + this); 
    ListOne list = (ListOne)listeners.get(eventName); 
    if (list == null) { 
        list = new ListOne(); 
        listeners.put(eventName, list); 
    } 
    list.add(listener); 
} 
/** 
* Unregisters the listener for the eventName. 
*/ 
public void removeContextListener(String eventName, Receiver listener) { 
    ListOne list = (ListOne)listeners.get(eventName); 
    if (list != null) { 
        list.remove(listener); 
        if (list.isEmpty()) listeners.remove(eventName); 
    } 
} 
/** 
* Sends the event to all registered listeners for the eventName. 
* The receive(String inpin, Datatron datatron) method is called
* on all listeners, since they implement Receiver. 
*
* For safety the list of receivers is cloned before the multicast, 
* allowing receivers to be safely added or removed during the multicast. 
*/ 
public void fireContextEvent(String eventName, Datatron datatron) { 
    //print(".fireEvent() - Entered, eventName = " + eventName + ", " + this);
    ListOne list = (ListOne)listeners.get(eventName); 
    if (list == null) return; 
    synchronized(this) {
        list = (ListOne)list.clone(); 
    } 
    //print(".fireEvent() - Multicasting to " + list.size() + " listeners"); 
    Receiver receiver;
    for (int i = list.size(); i >= 1; i--) {
        receiver = (Receiver)list.get(i);
        receiver.receive(eventName, datatron); 
    } 
} 
//---------- Standard -------------------------------------------- 
private static void print(String text) { 
    System.out.println("NodeContext" + text); 
} 

} // End class