
package uk.co.wingpath.event;

import java.util.*;
import java.awt.EventQueue;

/**
* This class provides an implementation of a value event source.
* <p>The "fire" methods of this class always call the
* {@link ValueListener#valueChanged valueChanged}
* method of registered listeners from the AWT event dispatch
* thread, using the {@link EventQueue#invokeLater
* EventQueue.invokeLater} method if necessary.
* <p>Instances of this class are thread-safe.
* @see ValueEvent
*/
public class ValueEventSource
{
    /**
    * Constructs a {@code ValueEventSource}.
    */
    public ValueEventSource ()
    {
    }

    private List<ValueListener> listeners = null;

    /**
    * Adds a listener.
    * @param l the listener to be added.
    */
    public synchronized void addListener (ValueListener l)
    {
        if (listeners == null)
            listeners = new LinkedList<ValueListener> ();
        listeners.add (l);
    }

    /**
    * Removes a listener.
    * @param l the listener to be removed.
    */
    public synchronized void removeListener (ValueListener l)
    {
        if (listeners != null)
            listeners.remove (l);
    }

    /**
    * Fires a non-changing value event with the specified source.
    * <p>A {@link ValueEvent} is constructed and passed to each registered
    * listener.
    * @param source the source to be used for the {@code ValueEvent}.
    */
    public void fireValueChanged (Object source)
    {
        fireValueChanged (source, false);
    }

    /**
    * Fires a changing value event with the specified source.
    * <p>A {@link ValueEvent} is constructed and passed to each registered
    * listener.
    * @param source the source to be used for the {@code ValueEvent}.
    */
    public void fireValueChanging (Object source)
    {
        fireValueChanged (source, true);
    }

    /**
    * Fires a value event with the specified source and changing flag.
    * <p>A {@link ValueEvent} is constructed and passed to each registered
    * listener.
    * @param source the source to be used for the {@code ValueEvent}.
    * @param changing whether the event is a "changing" event.
    */
    public synchronized void fireValueChanged (Object source, boolean changing)
    {
        if (listeners == null || listeners.size () == 0)
            return;
        final ValueEvent event = new ValueEvent (source, changing);
        fireValueChanged (event);
    }

    /**
    * Fires a value event.
    * <p>The {@link ValueListener#valueChanged valueChanged} method of each
    * registered listener is called, passing the supplied event as a parameter.
    * <p>The {@code valueChanged} method is called from the AWT event dispatch
    * thread, using the {@link EventQueue#invokeLater
    * EventQueue.invokeLater} method if necessary.
    * @param event the event to passed to each listener.
    */
    public synchronized void fireValueChanged (final ValueEvent event)
    {
        if (listeners == null || listeners.size () == 0)
            return;
        for (final ValueListener listener : listeners)
        {
            if (EventQueue.isDispatchThread ())
            {
                listener.valueChanged (event);
            }
            else
            {
                EventQueue.invokeLater (new Runnable ()
                    {
                        public void run ()
                        {
                            listener.valueChanged (event);
                        }
                    });
            }
        }
    }
}

