// Node.java

package lab08;

import java.awt.*;

public class Node {
    public static final int WIDTH = 80;
    public static final int HEIGHT = 50;
    public static final int DATA_HEIGHT = 40;
    public static final int LINK_HEIGHT = 20;
   
    private Object value;
    private Node leftChild;
    private Node rightChild;

    public Node (Object value, Node leftChild, Node rightChild) {
        this.value = value;
        this.leftChild = leftChild;
        this.rightChild = rightChild;
    }

    public Object getValue () {
        return value;
    }

    public void setValue (Object value) {
        this.value = value;
    }

    public Node getLeftChild () {
        return leftChild;
    }

    public void setLeftChild (Node leftChild) {
        this.leftChild = leftChild;
    }

    public Node getRightChild () {
        return rightChild;
    }

    public void setRightChild (Node rightChild) {
        this.rightChild = rightChild;
    }

    /**
     * Renders the node in a window using the Graphics object
     * g, at the (x,y) location specified by the Point parameter.
     * @param g Graphics object used for drawing in app window.
     * @param base Point object representing the start point for
     *   drawing the node, defined as the midpoint of the top edge
     *   of the node rectangle.
     * @return Array of 2 Point objects, representing the tips of
     * the left and right child link arrows respectively. These
     * two Points furnish the start locations for painting the
     * left and right child nodes.
     */
    public Point [] render (Graphics g, Point base, int level) {
        int xbase = base.x;
        int ybase = base.y;
    
        int xloc = xbase - WIDTH / 2;
        int yloc = ybase;
    
        // Draw box with value and link compartments...
    
        Color oldColor = g.getColor ();
        g.setColor (Color.white);
        g.fillRect (xloc+1, yloc+1, WIDTH-1, HEIGHT-1);
        g.setColor (oldColor);
        g.drawRect (xloc, yloc, WIDTH, HEIGHT);   

        g.drawLine (xloc, yloc + DATA_HEIGHT,
                    xloc + WIDTH, yloc + DATA_HEIGHT);
        g.drawLine (xbase, yloc + DATA_HEIGHT,
                    xbase, yloc + HEIGHT);

        // Render value in this node...
        
        if (value instanceof Item) {
           // Display Item in value compartment, using Item paint() method...
           ((Item) value).paint (g,
                new Point (xbase + 2 - WIDTH/2, ybase + DATA_HEIGHT/2), 
                new Dimension (WIDTH-4, DATA_HEIGHT-4));
        }
        else {
            // Display value as String in value compartment...
            String str = value.toString ();
            FontMetrics fm = g.getFontMetrics ();
            int strWidth = fm.stringWidth (str);

            g.drawString (str,
                xbase - strWidth / 2, yloc + DATA_HEIGHT - 10);
        }

        // Draw links: use electrical ground symbol to depict
        // null link and arrow to represent valid link to
        // another node...
    
        Point [] childPoints = new Point [2];
    
        int ystart = yloc + (HEIGHT + DATA_HEIGHT) / 2;   

        if (leftChild == null) {
            childPoints [0] =
                drawNullLink (g, new Point (xbase - WIDTH / 4, ystart));
        }
        else {
            childPoints [0] =
                drawLink (g, new Point (xbase - WIDTH / 4, ystart),
                    level, -1);
        }

        if (rightChild == null) {
            childPoints [1] = 
                drawNullLink (g, new Point (xbase + WIDTH / 4, ystart));
        }
        else {
            childPoints [1] =
                drawLink (g, new Point (xbase + WIDTH / 4, ystart),
                    level, 1);
        }

        return childPoints;
    }

    /**
     * Renders a null link as a vertical straight line, terminated
     * at the bottom end by an electrical-ground symbol. The base (top)
     * of the link is specified by the startPoint parameter.
     * @param g Graphics object used for drawing in app window.
     * @param startPoint Point object representing the start (top) point
     *        for drawing the null link.
     */
    public static Point drawNullLink (Graphics g, Point startPoint) {
        int xstart = startPoint.x;
        int ystart = startPoint.y;
     
        int ystop = ystart + LINK_HEIGHT;
  	
        g.drawLine (xstart, ystart, xstart, ystop);

        int y = ystop;
        int dy = HEIGHT / 12;
        int w = WIDTH / 6;

        for (int n = 0; n < 3; n++) {
            g.drawLine (xstart - w, y, xstart + w, y);
            y += dy;
            w -= 4;
        }

        return new Point (xstart, ystop);
    }

    /**
     * Node class (static) method for rendering a non-null
     * child link from a node. Each link is drawn as a straight
     * line segment slanting downward either to the left or right,
     * and starting from the location specified by the
     * startPoint parameter.
     * @param g Graphics object used for drawing in app window.
     * @param startPoint Point object specifying the location of
     * the start point (normally within a node link compartment).
     * @param level Level number of the node in tree from which
     *    this child link is being drawn.
     * @param dir Left/right child indicator, determines direction
     * of downward slant (-1 for left, 1 for right).
     */
    public static Point drawLink (
        Graphics g, Point startPoint,
        int level, int dir) {

        int xstart = startPoint.x;
        int ystart = startPoint.y;

        int xsep;
    
        if (level == 0)
            xsep = 0;
        else {
            xsep = 400;
            for (int n = 0; n < level; n++)
                xsep /= 2;
            if (dir < 0)
                xsep = -xsep;
        }

        int xstop = xstart + xsep / 2;
        int ystop = ystart + LINK_HEIGHT;

        g.drawLine (xstart, ystart, xstop, ystop);

        return new Point (xstop, ystop);
    } 
}
