package net.sf.fmj.ejmf.toolkit.media;

import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.media.ControllerEvent;
import javax.media.ControllerListener;

import net.sf.fmj.utility.LoggerSingleton;
import com.lti.utils.synchronization.CloseableThread;

/**
 * This class provides a dispatching mechanism for
 * ControllerEvents.  All events posted to this queue are
 * dispatched to a Vector of ControllerListeners given when the
 * queue is constructed.  Note that ControllerListeners may be
 * added or removed from this Vector from outside of this class,
 * and these changes will be reflected in the dispatching
 * mechanism.
 * 
 * From the book: Essential JMF, Gordon, Talley (ISBN 0130801046).  Used with permission.
 * 
 * @author     Steve Talley & Rob Gordon
 */
public class ControllerEventQueue extends CloseableThread {
	
	private static final Logger logger = LoggerSingleton.logger;

    Vector eventQueue = new Vector();
    Vector listeners;

    /**
     * Construct a ControllerEventQueue for the given list of
     * ControllerListeners.
     *
     * @param      listeners
     *             The list of ControllerListeners to notify
     *             whenever a ControllerEvents is posted.
     */
    public ControllerEventQueue(Vector listeners, String threadName) {
        super();
        setName(threadName);
        this.listeners = listeners;
        setDaemon(true);
    }

    /**
     * Post a ControllerEvent to the queue.  All listeners will be
     * notified ASAP.
     */
    public synchronized void postEvent(ControllerEvent event) {
        eventQueue.addElement(event);
        notify();
    }
    
    /**
     * Monitor the event queue.  When an event is added, dispatch
     * to all listeners.
     */
    private void monitorEvents() throws InterruptedException
    {
        Vector v;

        while ( !isClosing() )
        {
            synchronized(this)
            {
                while( eventQueue.size() == 0 )
                {
                    wait();
                }
                v = (Vector)eventQueue.clone();
                eventQueue.removeAllElements();
            }

            for(int i = 0; i < v.size(); i++ )
            {
                ControllerEvent event =
                    (ControllerEvent)v.elementAt(i);
                dispatchEvent(event);
            }
        }
    }
    
    /**
     * Dispatches an event on the current thread to all
     * ControllerListeners of this Conroller.  Exceptions are
     * caught during the notification so that event processing can
     * continue.
     */
    private void dispatchEvent(ControllerEvent event) {
        Vector l;

        //  Synchronize so that the listeners vector will not
        //  change while we are copying it
        synchronized(listeners) {
            l = (Vector)listeners.clone();
        }

        for(int i = 0; i < l.size(); i++ ) {
            Object o = l.elementAt(i);

            //  Make sure this is a ControllerListener
            if( o instanceof ControllerListener ) {
                ControllerListener listener =
                    (ControllerListener)o;

                try {
                    listener.controllerUpdate(event);
                } catch(Exception e) {
                	logger.log(Level.WARNING, "Exception occurred during event dispatching:" + e, e);
                   
                }
            }
        }
    }

    /**
     * Endlessly monitor the event queue.  This method should not
     * be called directly.
     */
    @Override
    public void run()
    {
        try
        {
            monitorEvents();
        }
        catch ( InterruptedException dontcare )
        {
        }
        
        setClosed();
    }
}
