//[skeleton1.
import java.util.*;

/**
 * An event queue with event bubbling
 *
 * Note: This implementation uses the Singleton pattern to ensure
 * that there is at most one ListenerEventQueue
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class BubblingEventQueue extends EventQueue<BubblingEvent>
{
//]skeleton1.
//[singleton1.

    // The instance used in the Singleton pattern
    private static BubblingEventQueue instance;
//]singleton1.
//[constructor.

    private   Hashtable<String, Boolean>   handlers;

    // "Constants"
    private static final Boolean F = new Boolean(false);
    private static final Boolean T = new Boolean(true);
    

    /**
     * Default Constructor
     */
    private BubblingEventQueue()
    {
       super();
       handlers = new Hashtable<String, Boolean>();        
    }
//]constructor.

//[fireEvent.

    /**
     * Fire an event
     *
     * Note: The code in this method does not need to be
     * synchronized because it is protected and is only
     * called by firePendingEvents() which is called by
     * a synchronized block in run()
     *
     * @param event   The event to fire
     */
    protected void fireEvent(BubblingEvent event)
    {
       boolean                 bubbleHandledEvents;       
       Boolean                 b;       
       EventHandler            source;

       source = event.getSource();
       b      = handlers.get(event.getName());
       
       bubbleHandledEvents = false;
       if (b != null) bubbleHandledEvents = b.booleanValue();
       
       source.handleEvent(event, bubbleHandledEvents);
    }
//]fireEvent.

//[singleton2.

    /**
     * Get the (Singleton) instance 
     *
     * @return  The BubblingEventQueue
     */
    public static synchronized BubblingEventQueue getEventQueue()
    {
       if (instance == null) instance = new BubblingEventQueue();
       
       return instance;       
    }
//]singleton2.

//[setBubbleIfHandled.

    /**
     * Set whether a particular Event should be bubbled
     * if it was already handled
     *
     * @param name             The name of the Event
     * @param bubbleIfHandled  true to make this name bubble if handled
     */
    public void setBubbleIfHandled(String  name, 
                                   boolean bubbleIfHandled)
    {
       if   (bubbleIfHandled) handlers.put(name, T);
       else                   handlers.put(name, F);       
    }
//]setBubbleIfHandled.

//[skeleton2.

}
//]skeleton2.
