package org.jcon.ba.system.router;

// import org.jcon.util.GenLib;
import java.util.Hashtable;
import java.util.Vector;

/**
 * A generic event router that relies on an event listener
 * proxy and event dispatcher. These must be provided in
 * the form of an EventListenerProxy subclass.
 *
 * This router is completely decoupled from knowing the
 * event type or listener interface. This allows it to
 * route any event that has an EventListenerProxy. There is
 * no requirement for the event to extend EventObject, since
 * the event can be any object.
 *
 * This class is more powerful and reusable than
 * MessageRouter, which can handle only one event type.
 *
 * @author Jack Harich
 */
public class EventRouter {

//---------- Private Fields ------------------------------
// Key = className, Object = Vector of Object listeners
private Hashtable eventListeners = new Hashtable();

private Vector routerListeners = new Vector();

//---------- Events --------------------------------------
public void addEventRouterListener(EventRouterListener listener) {
    routerListeners.addElement(listener);
}
public void removeEventRouterListener(EventRouterListener listener) {
    routerListeners.removeElement(listener);
}
//---------- Public Methods ------------------------------
/**
 * Adds the @param listener for events whose class is
 * @param eventClassName, which must be fully qualified.
 * For example @param eventClassName might be
 * "java.awt.ActionEvent".
 */
public void addListener(String eventClassName, Object listener) {
    //print(" - added listener for eventClassName " + eventClassName);
    Vector listeners = (Vector)eventListeners.get(eventClassName);
    if (listeners == null) {
        listeners = new Vector();
        eventListeners.put(eventClassName, listeners);
    }
    listeners.addElement(listener);
}
/**
 * Removes the @param listener for events whose class is
 * @param eventClassName.
 */
public void removeListener(String eventClassName, Object listener) {
    Vector listeners = (Vector)eventListeners.get(eventClassName);
    if (listeners != null) {
        listeners.removeElement(listener);
        if (listeners.isEmpty()) {
            eventListeners.remove(eventClassName);
        }
    }
}
/**
 * Multicasts an event to EventRouter listeners using the
 * @param proxy. This method is the heart of the EventRouter.
 *
 * Note that if the listener is an EventRouter, then
 * multicast(proxy) is called on that listener. This allows
 * event notification between routers.
 */
public void multicast(EventListenerProxy proxy) {

    Object event = proxy.getEvent();
    fireBeforeMulticastEvent(event);
    String className = event.getClass().getName();
    Vector listeners = (Vector)eventListeners.get(className);

    if (listeners != null) {
        // Fire event
        Vector list;
        synchronized(this) {
            list = (Vector)listeners.clone();
        }
        for (int i = 0; i < list.size(); i++) {
            Object listener = list.elementAt(i);
            if (listener instanceof EventRouter) {
                ((EventRouter)listener).multicast(proxy);
            } else {
                proxy.notifyListener(listener);
            }
        }
    }
}
//---------- Private Methods -----------------------------
private void fireBeforeMulticastEvent(Object anEvent) {
    // Prepare event
    EventRouterEvent event = new EventRouterEvent(anEvent, this);
    // Clone listeners
    Vector list;
    synchronized(this) {
        list = (Vector)routerListeners.clone();
    }
    // Multicast
    for (int i = 0; i < list.size(); i++) {
        EventRouterListener listener = (EventRouterListener)list.elementAt(i);
        listener.beforeEventRouterMulticast(event);
    }
}
//--- Std
private static void print(String text) {
    System.out.println("EventRouter" + text);
}

} // End class
