package org.mbari.vdm.knowledgebase;


//~--- JDK imports ------------------------------------------------------------

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
* Provides a dispatcher to notify listeners when an object has been changed. Use as:
* <pre>
* Dispatcher d = Dispatcher.getDispather("someKey");
* d.addPropertyChangeListener(new PropertyChangeListener() {
*     public void propertyChange(PropertyChangeEvent evt) {
*           // Get the old value of the property
*          Object oldValue = evt.getOldValue();
*
*          // Get the new value of the property
*          Object newValue = evt.getNewValue();
*          System.out.println("Old value = " + old + "; New value = " + new");
*      }
* });
* d.setValueObject(object);
* d.setValueObject(anotherObject);
* Object refToAnotherObject = d.getValueObject();
* </pre>
*
* Note: When Java 5.0 is more prevailent we can change this to use templates to
* constrain the type of object that can be set.
*
* @author brian
* @version $Id: Dispatcher.java,v 1.2 2005/12/14 03:24:33 achase Exp $
*/
public class Dispatcher {

  //~--- static fields ------------------------------------------------------

  protected static final Map map = new HashMap();
  private static final String PROP_VALUE_OBJECT = "valueObject";

  //~--- fields -------------------------------------------------------------

  private final Object key;
  private final PropertyChangeSupport propSupport =
      new PropertyChangeSupport(this);
  private Object valueObject;

  //~--- constructors -------------------------------------------------------

  /**
   *
   *
   * @param key
   */
  protected Dispatcher(Object key) {
      super();

      this.key = key;
  }

  //~--- methods ------------------------------------------------------------

  /**
   * <p><!-- Method description --></p>
   *
   *
   * @param listener
   */
  public void addPropertyChangeListener(PropertyChangeListener listener) {
      propSupport.addPropertyChangeListener(PROP_VALUE_OBJECT, listener);
  }

  //~--- get methods --------------------------------------------------------

  /**
   * Returns an instance of a dispatcher for a particular class
   *
   * @param key
   * @return
   */
  public static Dispatcher getDispatcher(Object key) {
      Dispatcher dispatcher = null;

      synchronized (map) {
          if (map.containsKey(key)) {
              dispatcher = (Dispatcher) map.get(key);
          } else {
              dispatcher = new Dispatcher(key);

              map.put(key, dispatcher);
          }
      }

      return dispatcher;
  }

  /**
   * @return Returns the observedClass.
   */
  public Object getKey() {
      return key;
  }

  /**
   *
   * @return All the keys registered for the different dispatchers.
   */
  public static Collection getKeys() {
      Collection keys;

      synchronized (map) {
          keys = map.keySet();
      }

      return keys;
  }

  /**
   * @return Returns the valueObject.
   */
  public Object getValueObject() {
      return valueObject;
  }

  //~--- methods ------------------------------------------------------------

  /**
   * <p><!-- Method description --></p>
   *
   *
   * @param listener
   */
  public void removePropertyChangeListener(PropertyChangeListener listener) {
      propSupport.removePropertyChangeListener(PROP_VALUE_OBJECT, listener);
  }

  //~--- set methods --------------------------------------------------------

  /**
   *
   * @param observedObject
   */
  public synchronized void setValueObject(Object observedObject) {
      Object oldObject = this.valueObject;

      this.valueObject = observedObject;

      propSupport.firePropertyChange(PROP_VALUE_OBJECT, oldObject,
                                     observedObject);
  }

}
