import java.awt.*;
import Point;
class BSTrb
  {
    int N;
    NodeRB head;
    NodeRB z;
    int depth;

    int delay;
    Graphics page;

    void clear(Color c)
      { 
        int h = page.getClipRect().height;
        int w = page.getClipRect().width;
        page.setColor(c);
        page.fillRect(0, 0, w, h);
      }

    BSTrb(int N, int d, int sw, int delay, Graphics page)
      {
        this.page = page;
        this.z = new NodeRB(0, 0, null, 0, null, null);
        z.l = z; z.r = z;
        this.head = z; this.depth = d; 
        if (sw == 0)
          for (int i = 0; i < N; i++)
            {
              this.delay = delay;
              this.head = insert(this.head, Math.random(), 2, 0);
              head.red = 0;
              clear(Color.lightGray);
              this.delay = 1;
              drawTree(head, head);
            }
        if (sw == 1)
          for (int i = 0; i < N; i++)
            {
              this.delay = delay;
              this.head = insert(this.head, ((double) i)/((double) N+1), 2, 0);
              head.red = 0;
              clear(Color.lightGray);
              this.delay = 1;
              drawTree(head, head);
            }
        System.out.println(N + "-node tree built"); 
      }
    void maxmin()
      {
        this.delay = 1;
        while (head.r != z)
          {
            head = rotL(head);
            drawTree(head, head);
          }
        while (head.l != z)
          {
            head = rotR(head);
            drawTree(head, head);
          } 
      }
    void drawVertex(Point p, Color c)
      { 
        int h = page.getClipRect().height-16;
        int w = page.getClipRect().width-16;
        if (c == Color.white)
             page.setColor(Color.black);
        else page.setColor(Color.lightGray);
        page.fillOval( (int) (w*p.x)+6, (int) (h*p.y)+6, 16, 16);
        page.setColor(c);
        for (int j = 0; j < delay; j++)
          {
            page.fillOval( (int) (w*p.x)+8, (int) (h*p.y)+8, 16, 16);
          }
      }
    void drawEdge(Point p, Point q, Color c)
      { 
        int h = page.getClipRect().height-16;
        int w = page.getClipRect().width-16;
        page.setColor(c);
        page.drawLine( (int) (w*p.x)+16, (int) (h*p.y)+16, 
                         (int) (w*q.x)+16, (int) (h*q.y)+16);
        if (c == Color.lightGray)
          {
            page.drawLine( (int) (w*p.x)+17, (int) (h*p.y)+17, 
                         (int) (w*q.x)+17, (int) (h*q.y)+17);
            page.drawLine( (int) (w*p.x)+15, (int) (h*p.y)+15, 
                         (int) (w*q.x)+15, (int) (h*q.y)+15);
          }
      }
    NodeRB rotL(NodeRB h)
      {
        double offset, lim;
        lim = 1.0/((double) this.depth+1); offset = .005;
        for (double x = 0; x < lim; x += offset)
          {
            h.pt.y += offset; 
            moveTree(h.l, h, offset);
            if (h.r != z) 
              { h.r.pt.y -= offset; moveTree(h.r.r, h.r, -offset); }
          }
        NodeRB x = h.r; h.r = x.l; x.l = h; 
        drawTree(x.l, x);
        return x;
      }
    NodeRB rotR(NodeRB h)
      {
        double offset, lim;
        lim = 1.0/((double) this.depth+1); offset = .005;
        for (double x = 0; x < lim; x += offset)
          {
            h.pt.y += offset; 
            moveTree(h.r, h, offset);
            if (h.l != z) 
              { h.l.pt.y -= offset; moveTree(h.l.l, h.l, -offset); }
          }
        NodeRB x = h.l; h.l = x.r; x.r = h; 
        drawTree(x.r, x);
        return x;
      }
    void moveTree(NodeRB h, NodeRB p, double offset)
      {
        double y; 
        if (h == z) return;
        drawVertex(h.pt, Color.lightGray);
        drawVertex(p.pt, Color.lightGray);
        drawEdge(p.pt, h.pt, Color.lightGray);
        h.pt.y += offset; 
        if (h.red == 0)
             drawEdge(p.pt, h.pt, Color.black);
        else drawEdge(p.pt, h.pt, Color.red);
        drawVertex(h.pt, Color.white);
        drawVertex(p.pt, Color.white);
        moveTree(h.l, h, offset);
        moveTree(h.r, h, offset);
      }
    void drawTree(NodeRB h, NodeRB p)
      {
        if (h == z) return;
        if (h.red == 0)
             drawEdge(p.pt, h.pt, Color.black);
        else drawEdge(p.pt, h.pt, Color.red);
        drawVertex(h.pt, Color.white);
        drawVertex(p.pt, Color.white);
        drawTree(h.l, h);
        drawTree(h.r, h);
      }
   NodeRB insert(NodeRB h, double v, int d, int sw)
     { 
       if (h == z) 
         {
           double sy = ((double) d+1)/((double) this.depth+1);
           Point s = new Point(v, sy);
           return new NodeRB(v, d+1, s, 1, z, z);
         }
       drawVertex(h.pt, Color.red);
       if ((h.l.red == 1) && (h.r.red == 1)) 
         { h.red = 1; h.l.red = 0; h.r.red = 0; }
       if (v < h.v) 
         { 
           h.l = insert(h.l, v, d+1, 0); 
           if ((h.red == 1) && (h.l.red == 1) && (sw == 1)) h = rotR(h); 
           if ((h.l.red == 1) && (h.l.l.red == 1)) 
             { h = rotR(h); h.red = 0; h.r.red = 1; }
         }
       else
         { 
           h.r = insert(h.r, v, d+1, 1); 
           if ((h.red == 1) && (h.r.red == 1) && (sw == 0)) h = rotL(h); 
           if ((h.r.red == 1) && (h.r.r.red == 1)) 
             { h = rotL(h); h.red = 0; h.l.red = 1; }
         }
       drawVertex(h.pt, Color.white);
       return h;
     }
  }

