import jdsl.core.algo.traversals.*;
import java.awt.*;
import java.awt.geom.*;
import jdsl.core.api.*;

/**
	* @author Lucy Perry (lep)
	* @version JDSL 2
	*/
public class TreeDrawer extends EulerTour {
  // Traversal of a tree that is specialized to draw a
  // tree within an applet.
  protected int Yoffset = 40;       // Y offset from (0,0)
  protected int Xoffset = 20;       // X offset from (0,0)
  protected Graphics g;             // where to draw the tree
  protected Color background;       // fill color
  protected int totalShift;         // a running total to shift bounding boxes.  The shift
                                    //    distance is the sum of the shifts stored at 
                                    //    ancestors.

  public TreeDrawer(Graphics gg) {
    g=gg;
    background = g.getColor();
  }
  
  /**
   * When visiting a node for the first time we shift x by totalShift
   */
  protected void visitFirstTime(Position pos){
    int x = ((Integer)pos.get("x")).intValue();
    int shift = ((Integer)pos.get("shift")).intValue();
    pos.set("x", new Integer(x+totalShift));
    totalShift += shift;
  }
  
  
  /**
   * When visiting a node for the last time we draw the node.
   */
  protected void visitLastTime(Position pos){
    int shift = ((Integer)pos.get("shift")).intValue();
    if(!tree_.isRoot(pos)) {
      //Draw the edge to the parent
      g.setColor(Color.black);
      g.drawLine(xPos(pos), yPos(pos), xPos(tree_.parent(pos)),
		 yPos(tree_.parent(pos)));
    }
    Color strColor;
    if (tree_.isExternal(pos)) {
      strColor=Color.black;
    } else {
      strColor=Color.red;
    }
    drawString(pos, strColor);
    totalShift -= shift;
    cleanup(pos);
  }
  
  /**
   * External nodes are drawn in the same manner as internal nodes
   */
  protected void visitExternal( Position pos ) { 
    visitFirstTime(pos);
    visitLastTime(pos);
  }
  
  /**
   * Draw the string at its proper location.
   */
  private void drawString(Position pos, Color strColor) {
    String str=pos.element().toString();
    int ascent = ((Integer)pos.get("ascent")).intValue();
    int descent = ((Integer)pos.get("descent")).intValue();
    Rectangle2D bounds = ((Rectangle2D)pos.get("bounds"));
    int height = (int)bounds.getHeight();
    int width = (int)bounds.getWidth();
    int x = xPos(pos)-width/2;
    int y = yPos(pos)-ascent/2;
    g.setColor(background);
    g.fillRect(x,y,width,ascent+descent);
    y += ascent;
    g.setColor(strColor);
    g.drawString(str,x,y);
  }
  
  private int xPos(Position p) {
    int x = ((Integer)p.get("x")).intValue();
    int width = ((Integer)p.get("width")).intValue();
    return x + width/2 + Xoffset;
  }
  
  private int yPos(Position p) {
    return ((Integer)p.get("y")).intValue()+Yoffset;
  }

  private void cleanup(Position p) {
    p.destroy("x");
    p.destroy("y");
    p.destroy("shift");
    p.destroy("ascent");
    p.destroy("descent");
    p.destroy("bounds");
  }
}