package data;

import java.beans.*;

/**
  * Convenience class implementing the Nameable interface.
  *
  * <p>You should derive all your Nameable classes from this class, as it provides a
  * complete implementation of the {@link Nameable} interface. However, there is no
  * obligation to derive from this class, as long as your class implements Nameable and
  * sticks to the contract defined in that interface.</p>
  *
  * @author Steffen Zschaler
  * @version 2.0 25/05/1999
  * @since v2.0
  */
public abstract class AbstractNameable extends Object implements Nameable {

  /**
    * Used to fire {@link java.beans.PropertyChangeEvent PropertyChangeEvents}.
    *
    * @serial
    */
  protected PropertyChangeSupport m_pcsPropertyListeners = new PropertyChangeSupport (this);

  /**
    * The name of this object.
    *
    * @serial
    */
  private String m_sName;

  /**
    * The current name context.
    *
    * @serial
    */
  protected NameContext m_ncContext;
  /**
    * The monitor synchronizing access to the NameContext.
    */
  private transient Object m_oNCLock;
  /**
    * Return the monitor synchronizing access to the NameContext.
    *
    * @override Never
    */
  private final Object getNCLock() {
    if (m_oNCLock == null) {
      m_oNCLock = new Object();
    }

    return m_oNCLock;
  }

  /**
    * Initialize a new AbstractNameable object with a <code>null</code> name.
    */
  public AbstractNameable() {
    this (null);
  }

  /**
    * Initialize a new AbstractNameable object with the given name. The name context will initially be
    * <code>null</code>.
    *
    * @param sName the AbstractNameable's name.
    */
  public AbstractNameable (String sName) {
    super();

    m_sName = sName;
    m_ncContext = null;
  }

  /**
    * Attach a NameContext to this Nameable.
    *
    * <p>No naming conventions are checked neither in the old nor in the new NameContext.</p>
    *
    * <p>All access to the NameContext is synchronized for thread-safety.</p>
    *
    * @param nc the new NameContext of this Nameable object.
    *
    * @return the previous NameContext, if any.
    *
    * @override Never
    */
  public NameContext attach (NameContext nc) {
    synchronized (getNCLock()) {
      NameContext ncOld = m_ncContext;

      m_ncContext = nc;

      return ncOld;
    }
  }

  /**
    * Detach the current NameContext from this Nameable.
    *
    * <p>All access to the NameContext is synchronized for thread-safety.</p>
    *
    * @return the previously attached NameContext, if any.
    *
    * @override Never
    */
  public NameContext detachNC() {
    return attach ((NameContext) null);
  }

  /**
    * Set the Nameable's name, using help by the NameContext.
    *
    * <p>All access to the NameContext is synchronized for thread-safety.</p>
    *
    * @param sName the new name of the object
    * @param db the DataBasket relative to which the name change is to take place.
    *
    * @exception NameContextException if the name change was not approved of by the
    * NameContext.
    *
    * @override Never
    */
  public void setName (String sName, DataBasket db)
    throws NameContextException {
    synchronized (getNCLock()) {
      String sOld = m_sName;

      if (m_ncContext != null) {
        synchronized (m_ncContext.getNCMonitor()) {

          m_ncContext.checkNameChange (db, sOld, sName);

          m_sName = sName;

          m_ncContext.nameHasChanged (db, sOld, sName);
        }
      }
      else {
        m_sName = sName;
      }

      m_pcsPropertyListeners.firePropertyChange (NAME_PROPERTY, sOld, sName);
    }
  }

  /**
    * Get the name of the object.
    *
    * override Never
    */
  public String getName() {
    return m_sName;
  }

  /**
    * Add a PropertyChangeListener that will receive events whenever a bound property changes.
    *
    * @override Never
    */
  public void addPropertyChangeListener (PropertyChangeListener pcl) {
    m_pcsPropertyListeners.addPropertyChangeListener (pcl);
  }

  /**
    * Remove a PropertyChangeListener.
    *
    * @override Never
    */
  public void removePropertyChangeListener (PropertyChangeListener pcl) {
    m_pcsPropertyListeners.addPropertyChangeListener (pcl);
  }

  /**
    * Add a PropertyChangeListener that will receive events whenever the &quot;name&quot; property changes.
    *
    * @override Never
    */
  public void addNameListener (PropertyChangeListener pcl) {
    m_pcsPropertyListeners.addPropertyChangeListener (NAME_PROPERTY, pcl);
  }

  /**
    * Remove a PropertyChangeListener for the &quot;name&quot; property.
    *
    * @override Never
    */
  public void removeNameListener (PropertyChangeListener pcl) {
    m_pcsPropertyListeners.removePropertyChangeListener (NAME_PROPERTY, pcl);
  }
}