import netscape_beta.application.*;
import netscape_beta.util.*;

/**
 * A class that contains methods common to Visitor and
 * TreeNode classes.  Displays itself as a node with 
 * the provided node label.  Provides property lists that
 * are displayed when the user right-clicks the drawable.
 *
 * @version        1.0 12 Dec 1996
 * @author         Andrew Miller
 */
class Drawable extends TextField implements Target
{
  protected Color colorNormal = Color.lightGray;
  protected Color colorHighlight = Color.white;
  protected View parent = null;
  protected TextField field = null;
  protected String nodeName = null;
  protected Popup m_properties = new Popup();

    /**
     * Default constructor.  Construct a drawable without displaying it.
     */
  public Drawable()
  {
	super();
  }

    /**
     * Constructs a Drawable that is dynamically sized to fit the 
     * provided nodename in the specified view.
     *
     * @param x         The drawable's x position in the parent.
     * @param y         The drawable's y position in the parent.
     * @param nodename  The drawable's label.
     * @param parent    The view to display the drawable in.
     */
  public Drawable(int x, int y, String nodename, View parent)
  {
     super();

     init(x,y,nodename, parent);
  }

    /**
     * Initializes and displays a Drawable that is dynamically sized 
     * to fit the provided nodename in the specified view.
     *
     * @param x         The drawable's x position in the parent.
     * @param y         The drawable's y position in the parent.
     * @param nodename  The drawable's label.
     * @param parent    The view to display the drawable in.
     */
  public void init(int x, int y, String nodename, View parent)
  {
     parent = parent;
     nodeName = nodename;

     FontMetrics fmetrics = font().fontMetrics();
     Size size = fmetrics.stringSize(nodename);
     setStringValue(nodename);
     setEditable(false);
     Rect rcDrawable = new Rect(0, 0, size.width+50, size.height*3 );
     setBounds(rcDrawable);
     setJustification(Graphics.CENTERED);
     setBorder(BezelBorder.raisedButtonBezel());
     setBackgroundColor(colorNormal);
     parent.addSubview(this);
     moveTo(x,y);

     keepInView();

     m_properties.setTarget(this);
  }

    /**
     * Move a drawable within the parent view, resizing the view
     * if necessary.
     *
     * @param x         The drawable's x position in the parent.
     * @param y         The drawable's y position in the parent.
     */
  public void moveTo(int x, int y)
  {
    super.moveTo(x,y);
    keepInView();
  }

    /**
     * Resize the parent view (if necessary) so that the
     * drawable is always within the view.
     */
  private void keepInView()
  {
     // when necessary, expand the view to meet our size needs 
     Rect rcParent = superview().bounds();
     Rect rcDrawable = bounds();

     if(rcParent.width < rcDrawable.x + rcDrawable.width)
     {
         rcParent.width = rcDrawable.x + rcDrawable.width;
     }
 
     if(rcParent.height < rcDrawable.y + rcDrawable.height)
     {
         rcParent.height = rcDrawable.y + rcDrawable.height;
     }

     superview().setBounds(rcParent);

  }

    /**
     * Returns' the drawable's node name.
     *
     */
  public String getNodeName()
  {
	return nodeName;
  }

    /**
     * Add a property to the drawable.  Drawable properties are
     * displayed when the user right-clicks on the drawable.
     * @param strProp       The propery string.
     * @param strCommand    The command string to fire when the user selects the property
     */
  public void addProperty(String strProp, String strCommand)
  {
      m_properties.addItem(strProp, strCommand);
  }

    /**
     * Default action when a user selects a property item.
     * Hides the property Popup.
     * @param strProp       The propery command string.
     * @param strCommand    The object sending the command.
     */
  public void performCommand(String string, Object obj)
  {
        hideProperties();
  }

    /**
     * Display the drawable's property popup menu.
     * Menu is shows above and to the right if possible.
     */
  public void showProperties()
  {
     // dynamically calculate the properties height
     if(m_properties.count() < 1)
         return;

     Font font = Font.defaultFont();
     FontMetrics metrics = font.fontMetrics();
     int charHeight = metrics.charHeight();
     int numItems = m_properties.count();

     // properties popup has arbitrary width
     Rect rcProp = new Rect(0,0,100,charHeight * numItems); 
     m_properties.setBounds(rcProp);
          
     Rect rcParent = superview().bounds();
     Rect rcNode = bounds();

     // show properties to the right of the node
     // if possible, otherwise go to the down and left
     int xPos = 0;
     int yPos = 0;

     if(rcParent.x + rcParent.width/2 + rcProp.width >
        rcParent.x + rcParent.width)
     {
        // go left
        xPos = rcNode.x + rcNode.width/2 - rcProp.width;
     }
     else
     {
        // go right
        xPos = rcNode.x + rcNode.width/2;
     }

     if(rcNode.y - rcProp.height < rcParent.y)
     {
        // go down
         yPos = rcNode.y + rcNode.height/2;
     }
     else
     {
        // go up
         yPos = rcNode.y + rcNode.height/2 - rcProp.height;
     }

     m_properties.moveTo(xPos, yPos);
     superview().addSubview(m_properties);
     
     
     // Fake a mouse click to get the popup to display itself
     MouseEvent event = new MouseEvent(0, MouseEvent.MOUSE_DOWN,0,0,0);
     m_properties.mouseDown(event);
  }

    /**
     * Hide an active property menu.
     */
  public void hideProperties()
  {
      m_properties.removeFromSuperview();
      superview().addDirtyRect(m_properties.bounds());
  }

    /**
     * Display the drawable's  property menu if
     * the user clikced the right mouse button.
     * @return true if user right-clicked
     */
  public boolean mouseDown(MouseEvent event)
  {
     // modifiers == 4 for right click
     if(event.modifiers() == 4) // right click (needs to be tested on UNIX)
     {
        showProperties();
        return true;
     }
     else
     {
        return false; // not handled
     }
  }
}


