package sale;

import java.io.Serializable;

import javax.swing.*;

/**
  * A generic menu element.
  *
  * @see MenuSheet
  * @see MenuSheetItem
  * @see MenuSheetSeparator
  *
  * @author Steffen Zschaler
  * @version 2.0 20/05/1999
  * @since v2.0
  */
public abstract class MenuSheetObject extends Object implements Serializable {

  /**
    * The caption of the menu element.
    *
    * @serial
    */
  private String m_sCaption;

  /**
    * Immutable tag, that can be used to identify the menu element. Never
    * <code>null</code>!
    *
    * @serial
    */
  private String m_sTag;

  /**
    * Is this MenuSheetObject currently on display?
    *
    * @serial
    */
  private boolean m_fVisible = false;

  /**
    * The MenuSheet that contains this menu element.
    *
    * @serial
    */
  protected MenuSheet m_msParent;

  /**
    * The SalesPoint attached to this MenuSheetObject, if any.
    *
    * @serial
    */
  protected SalesPoint m_spAttached;

  /**
    * The SaleProcess attached to this MenuSheetObject, if any.
    *
    * @serial
    */
  protected SaleProcess m_pAttached;
  
  /**
    * Create a new MenuSheetObject with a caption and a tag.
    *
    * @param sCaption the caption of this MenuObject
    * @param sTag the tag of this MenuObject. If <code>null</code>, a default, unique tag
    * will be given.
    */
  public MenuSheetObject (String sCaption,
                          String sTag) {
    super();

    m_sCaption = sCaption;

    if (sTag != null) {
      m_sTag = sTag;
    }
    else {
      m_sTag = STD_TAG_PREFIX + (s_nLastTagID ++);
    }
  }

  /**
    * Create a new MenuSheetObject with a caption and a default tag.
    *
    * <p>You can find out about the tag by calling {@link #getTag}.</p>
    *
    * @param sCaption the caption of the MenuSheetObject.
    */
  public MenuSheetObject (String sCaption) {
    this (sCaption, null);
  }

  /**
    * Get the MenuSheetObject's caption.
    *
    * @override Never
    */
  public String getCaption() {
    return m_sCaption;
  }

  /**
    * Set the MenuSheetObject's caption.
    *
    * @override Always Override to make sure, the peer's captions gets properly updated.
    *
    * @param sCaption the new caption.
    */
  public void setCaption (String sCaption) {
    m_sCaption = sCaption;
  }

  /**
    * Get the MenuSheetObject's tag. The tag of a MenuSheetObject can be used to
    * identify a MenuSheetObject in a MenuSheet. It is immutable, never <code>null</code>
    * and should be unique in the containing MenuSheet.
    *
    * @override Never
    *
    * @see MenuSheet
    * @see #getTaggedItem
    */
  public String getTag() {
    return m_sTag;
  }

  /**
    * Get the first MenuSheetObject with the given tag which is managed by this one.
    *
    * <p>The default implementation returns this MenuSheetObject if it has the given tag,
    * and <code>null</code> otherwise.</p>
    *
    * @override Never
    *
    * @param sTag the tag that is searched for.
    * @param fTopLevelOnly if true, only the top level items are searched.
    */
  public MenuSheetObject getTaggedItem (String sTag, boolean fTopLevelOnly) {
    return ((getTag().equals (sTag))?
            (this):
            (null));
  }

  /**
    * Convenience method for in-depth search for a tagged item.
    *
    * <p>Equivalent to:
    *
    * <pre>
    * getTaggedItem (sTag, false);
    * </pre>
    *
    * @override Never
    *
    * @param sTag the tag to be searched for.
    */
  public MenuSheetObject getTaggedItem (String sTag) {
    return getTaggedItem (sTag, false);
  }


  /**
    * Attach a SalesPoint to this MenuSheetObject.
    *
    * @override Never
    *
    * @param sp the SalesPoint to be attached.
    *
    * @return the previously attached SalesPoint, if any.
    */
  public SalesPoint attach (SalesPoint sp) {
    SalesPoint spOld = m_spAttached;

    m_spAttached = sp;

    return spOld;
  }

  /**
    * Detach the currently attached SalesPoint.
    *
    * @override Never
    *
    * @return the SalesPoint just detached, if any.
    */
  public SalesPoint detachSalesPoint() {
    return attach ((SalesPoint) null);
  }

  /**
    * Attach a SaleProcess to this MenuSheetObject.
    *
    * @override Never
    *
    * @param p the process to be attached.
    *
    * @return the previously attached process, if any.
    */
  public SaleProcess attach (SaleProcess p) {
    SaleProcess pOld = m_pAttached;

    m_pAttached = p;

    return pOld;
  }

  /**
    * Detach the currently attached SaleProcess.
    *
    * @override Never
    *
    * @return the SaleProcess just detached, if any.
    */
  public SaleProcess detachSaleProcess() {
    return attach ((SaleProcess) null);
  }

  /**
    * Set the parent of the MenuSheetObject. This method is used internally only.
    *
    * @override Never
    */
  void setParent (MenuSheet msParent) {
    m_msParent = msParent;
  }

  /**
    * Get the parent MenuSheet of this MenuSheetObject.
    *
    * @override Never
    *
    * @return the MenuSheet containing this MenuSheetObject.
    */
  public MenuSheet getParent() {
    return m_msParent;
  }

  /**
    * Mark this MenuSheetObject visible or invisible. This does not actually show or hide
    * the MenuSheetObject's peer, but rather helps the MenuSheetObject manage resources.
    *
    * <p>This method is usually not called directly.</p>
    *
    * @override Sometimes Override if you have some additional ressources that need visibility dependent
    * management.
    *
    * @param fVisible the visibility state of the MenuSheetObject.
    */
  public void setVisible (boolean fVisible) {
    m_fVisible = fVisible;
  }

  /**
    * Get the visibility state of this MenuSheetObject.
    *
    * @override Never
    */
  public boolean isVisible() {
    return m_fVisible;
  }

  /**
    * Return true if this is a separator. Separators need not have peers.
    *
    * @override Never The default implementation returns false.
    *
    * @see #getPeer
    * @see #getMenuPeer
    */
  public boolean isSeparator() {
    return false;
  }

  /**
    * Compare this MenuSheetObject to the given object and return true if they are equal.
    *
    * <p>For MenuSheetObjects equality of references is measured, i.e.
    * <code>equals()</code> will only return true if <code>this == o</code>.</p>
    *
    * @override Never You should only override this method when there is an absolute need for a different
    * equality measurement.
    *
    * @param o the object to compare to.
    */
  public boolean equals (Object o) {
    return (this == o);
  }

  /**
    * Return the JMenuItem peer for this MenuSheetObject. This can be a JMenuItem or a
    * JMenu, just as is appropriate. You can always return the same peer.
    *
    * @override Always
    */
  public abstract JMenuItem getPeer();

  /**
    * Return the JMenu peer for this MenuSheetObject. Independently of the actual type of
    * the MenuSheetObject this must return a JMenu object.
    *
    * <p>For MenuSheetItems and similar MenuSheetObjects it is recommended that you create
    * a JMenu with the same caption and only one item, the MenuElement peer of the
    * MenuSheetObject. Make sure, however, to create all these objects afresh for the
    * JMenu peer, lest there should result inpredictably behaving menus. This does, of
    * course not apply, if the MenuElement peer and the JMenu peer are entirely equal as
    * is the case for MenuSheets.</p>
    *
    * <p>Although JMenuItem peer and JMenu peer should be different objects, subsequent
    * calls to <code>getMenuPeer()</code> can still return the same object.</p>
    *
    * @override Always
    */
  public abstract JMenu getMenuPeer();

  /**
    * The default tag prefix, if no tag was given.
    */
  private static final String STD_TAG_PREFIX = "__TAG_";

  /**
    * The last tag id that was given to a default tag.
    */
  private static int s_nLastTagID = 0;
}