import java.util. *;
import java.awt. *;
import java.io. *;
import java.net. *;
import java.applet.Applet;

/** Execute a splay tree operation on a binary search tree. */

class SplayTreeOperation extends DictionaryOperation implements Runnable {

  /** Initialize with a given Action, snapshot of the current graph
   ** (SimpleGraph), the tree's panel and an IconLibrary */

  SplayTreeOperation(Action a, Tree t, SimpleGraph sg, 
		     SplayTreePanel p, IconLibrary ih)
  {
     super(a, t, sg, (GraphPanel) p, ih);
  }

  private Node whereToSplay = null;

  /** execute the splay after binary search tree operations are
   ** completed */
  public void prologue(int op, Node n) throws InterruptedException {

      if (n == null) return;

      switch (op) {

	case DELETE :
	      Node toDelete = n.deleteWhich();
	      if (toDelete != null)
		whereToSplay = toDelete.parent;
	      else
		whereToSplay = null;
	      break;

	default :
	      whereToSplay = n;
	      break;
      }
  }

  /** execute the splay after binary search tree operations are
   ** completed */
  public void epilogue(int op, Node n) throws InterruptedException {

      if (whereToSplay == null) return;

      switch (op) {

        case PAUSE:	
        case WAIT:	
        case NOOP:	
		return;

	case DELETE:
  	case INSERT:
	case LOCATE:
		whereToSplay.splay (true);
		splay (whereToSplay);
	        waitToSettle (whereToSplay);
		whereToSplay.splay (false);
	      	break;

	default :
	      break;
      }
  }

  void splay (Node n) throws InterruptedException {

    Node p = null;
    Node first, second;  // parent and grandparent
    Node rotating;	 // current rotating node

    n.splay(true);

    int stepNo = 1;

    panel.title("Splay:");

    while (n.parent != null) {

	n.inserting = false;

	waitToSettle(n);
	n.setGraphics();

	p = n.parent;

	if (p.parent != null) {

	    panel.title("Splay (step " + stepNo + "):");

	    boolean x_left = n.isLeft();
	    boolean p_left = p.isLeft();

	    if (x_left == p_left) {
		first = p;
		second = p.parent;
	    }
	    else {
		first = p.parent;
		second = p;
	    }
	    first.working(true);
	    second.working(true);

	    // first rotation 

	    second.rotating(true);

	    Node toRotate = (x_left == p_left) ? n.parent : n;

	    panel.caption((toRotate == n) ? 
			  ("Rotate twice at the selected node (" 
				     + n.value 
				     + ").") : 
			  "First rotate at its parent ... ");

	    rotate (snapshot, toRotate);
	    waitToSettle (toRotate);

	    second.working(false);
	    second.found(false);

	    briefPause();

	    if (toBeDeleted != null) {
	      toBeDeleted.deletePick = false;
	      toBeDeleted.setGraphics();
	    }

	    if (toRotate != n) 
		panel.caption("and then at the selected node ("+n.value+").");
	}
	else {
	    panel.title("Splay:");
	    panel.caption("Rotate at the selected node (" + n.value + ").");
	    first = p;
	    first.working(true);
	}

	rotate(snapshot, n);
	waitToSettle(n);
	briefPause();

	first.working(false);
	first.found(false);
    }
  }
}

/** */
class SplayTreePanel extends GraphPanel implements Runnable {

  SplayTreePanel (SplayTree st, Layout l, Dimension dim, IconLibrary im) {
    super((Graph) st, l, dim, im);
  }

  public void launchAction(int action) {

    if (rotating || pick == null) return;

    Action a = new Action();
    a.op = action;

    switch(action) {

	  case DictionaryOperation.INSERT : 
	    	a.node = insertAndPlace(getInsertValue(pick));
	    	a.node.x = pick.x;
	    	a.node.y = pick.y;
	       	break;

	  case DictionaryOperation.DELETE :
	  case DictionaryOperation.LOCATE :
	    	a.node = pick;
	    	break;

	  default :
	    	break;
    }

    nextAction(a);
    unpick();
  }

  /** */
  public synchronized void startOperation() {
    rotating = true;
    super.startOperation();
  }

  /** */
  public synchronized void endOperation() {
    rotating = false;
    super.endOperation();
  }

  protected void animate (Action a) {

    if (layout.demoMode) {
	follow = a.node;
    }
    SplayTreeOperation splay; 
    splay = new SplayTreeOperation(a,tree,snapshot,this,images);
    Thread t = new Thread(splay);
    tree.continuation(t);
    t.start();
  }
}

public class SplayTree extends Graph {

  SplayTreePanel stPanel;

  protected void launchAction (Object arg) {
     if ("Insert".equals (arg)) 
        stPanel.launchAction(DictionaryOperation.INSERT);
     else if ("Delete".equals (arg)) 
	stPanel.launchAction(DictionaryOperation.DELETE);
     else if ("Locate".equals (arg))
	stPanel.launchAction(DictionaryOperation.LOCATE);
  }

  public void init() {
      initPrelude();

      Dimension d = size();
      Dimension pDim = new Dimension(d.width, d.height-100);

      stPanel = new SplayTreePanel (this, layout, pDim, images);
      panel = stPanel;

      add ("Center", panel);
      showChoices();
      showButtons();
  }
  public void start() {
      stPanel.initialTree = edges;
      stPanel.start();
  }
  public void stop() {
      stPanel.stop();
  }
}


