//     $Id: DrawableNode.java,v 3.1 1998/12/01 14:18:57 te3d Exp $    
 ////////////////////////////////////////////////////////////////////////////
 //
 // File:    DrawableNode.java
 //
 // Purpose: A DrawableNode is a graphical representation of
 //          a Node.  Properties:
 // 
 //            o Elliptical shape
 //            o Name     - label
 //            o Recovery - not visible  (only in Details window)
 //            o Stable   - green border is stable, red is unstable
 //
 //          This is a base class, and can used by several modules.
 //          For that reason, we don't specify the Invoking modules.
 //
 // Authors:
 //   txe  Travis Emmitt  emmitt@virginia.edu
 //
 // Modifications:
 //   28-OCT-1998  txe  (v1) Initial creation (was screen.Node)
 //   29-OCT-1998  txe  Removed Toggle
 //   03-NOV-1998  txe  Added comments, removed unused methods.
 //   06-NOV-1998  rgb  Added version control header info
 //
 //   13-NOV-1998  txe  (v2) Extends Node, added exceptions
 //   15-NOV-1998  txe  Added new exceptions
 //   16-NOV-1998  txe  Added exceptions, comments, constants
 //
 //   30-NOV-1998  txe  (v3) Improved format, speed
 //
 ////////////////////////////////////////////////////////////////////////////
 import java.applet.*;
 import java.awt.*;
 public class DrawableNode extends Node {
   private int x;                // X coordinate of northwest corner
   private int y;             // Y coordinate of northwest corner
   private int w;             // width
   private int h;             // height
   private final static int
     MAX_LABEL_LEN       = 10,  // maximum label length (truncate)
     MIN_FILL_WIDTH      = 20,  // how big must it be to deserve fill&label
     NORMAL_MODE              = 0,   // normal viewing mode
     SHOW_ALL_NODES        = 1,   // mode option: show all nodes
     DEPENDEE_MODE       = 2,   // mode option: we're a dependee
     DEPENDER_MODE         = 3;   // mode option: we're a depender
   private final static Color
     LABEL_COLOR     = new Color (0.0f, 0.0f, 0.0f), // black
     STABLE_FCOLOR   = new Color (0.3f, 0.6f, 0.3f), // dk green
     STABLE_BCOLOR   = new Color (0.8f, 1.0f, 0.9f), // lt green
     UNSTABLE_FCOLOR = new Color (0.6f, 0.3f, 0.3f), // dk red
     UNSTABLE_BCOLOR = new Color (0.9f, 0.5f, 0.5f), // lt red
     DEPENDEE_FCOLOR = new Color (1.0f, 0.9f, 1.0f), // white
     DEPENDEE_BCOLOR = new Color (0.9f, 0.2f, 0.2f), // red
     DEPENDER_FCOLOR = new Color (0.0f, 0.3f, 0.0f), // dk green
     DEPENDER_BCOLOR = new Color (1.0f, 1.0f, 0.5f); // yellow
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  DrawableNode  [constructor]
   //
   // Purpose: This creates a new DrawableNode representing the
   //          specified Node, with the specified bounds.
   //   
   ///////////////////////////////////////////////////////////////////
   public DrawableNode (Node new_node, int new_bounds[])
   throws BoundsException, IndexException, NullException {
     if (new_node == null) {
       throw new NullException ("new_node");
     }
     if (new_bounds == null) {
       throw new NullException ("new_bounds");
     }
     Copy (new_node);
     int i = 0;
     try {
       x = new_bounds[i++];
       y = new_bounds[i++];
       w = new_bounds[i++];
       h = new_bounds[i++];
     }
     catch (Exception e) {
       throw new IndexException ("new_bounds", i);
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Draw
   //
   // Purpose: This displays the Node on the screen.
   //             The mode is used for handling special display
   //          cases (see constants at top).
   //   
   ///////////////////////////////////////////////////////////////////
   public void Draw (Graphics graphics, int mode)
   throws GraphicsException, NullException {
     if (graphics == null) {
       throw new NullException ("graphics");
     }
     int font_size = (w / MAX_LABEL_LEN) * 2;
     int label_len = Math.min (name.length(), MAX_LABEL_LEN);
     String label  = name.substring (0, label_len);
     int label_x   = GetCenterX() - ((font_size * label_len) / 4);
     int label_y   = GetCenterY() + (font_size / 2);
     Color edge_color  = null;
     Color fill_color  = null;
     Color label_color = null;
     if (mode == SHOW_ALL_NODES) {
       edge_color  = (stable ? STABLE_FCOLOR : UNSTABLE_FCOLOR);
       fill_color  = edge_color;
       label_color = null;
     }
     else if (mode == DEPENDEE_MODE) {
       edge_color  = DEPENDEE_FCOLOR;
       fill_color  = DEPENDEE_BCOLOR;
       label_color = edge_color;
     }
     else if (mode == DEPENDER_MODE) {
       edge_color  = DEPENDER_FCOLOR;
       fill_color  = DEPENDER_BCOLOR;
       label_color = edge_color;
     }
     else {
       edge_color  = (stable ? STABLE_FCOLOR : UNSTABLE_FCOLOR);
       fill_color  = (stable ? STABLE_BCOLOR : UNSTABLE_BCOLOR);
       label_color = LABEL_COLOR;
     }
     try {
       graphics.setColor (fill_color);
       graphics.fillOval (x, y, w, h);
       graphics.setColor (edge_color);
       graphics.drawOval (x, y, w, h);
       if (label_color != null) {
     graphics.setColor (label_color);
     graphics.setFont  (new Font ("Helvetica", Font.PLAIN, font_size));
     graphics.drawString (label, label_x, label_y);
       }
     }
     catch (Exception e) {
       throw new GraphicsException (e);
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetCenterX
   //
   // Purpose: Returns X coordinate of center of Node.
   //   
   ///////////////////////////////////////////////////////////////////
   public int GetCenterX () {
     return x + (w / 2);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetY
   //
   // Purpose: Returns Y coordinate of center of Node.
   //   
   ///////////////////////////////////////////////////////////////////
   public int GetCenterY () {
     return y + (h / 2);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Inside
   //
   // Purpose: This returns true if the specified coordinate
   //          is within the DrawableNode (assumes elliptical shape),
   //          false otherwise.
   //   
   ///////////////////////////////////////////////////////////////////
   public boolean Inside (int new_x, int new_y) {
     double dx = new_x - GetCenterX ();
     double dy = new_y - GetCenterY ();
     dy = (double) (dy * w) / (double) Math.max (h, 1);
     return (Math.sqrt ((dx * dx) + (dy * dy)) < (double) w / 2);
   }
 }
 ////////////////////////////////////////////////////////////////////////////