import java.lang.*;
import java.awt.*;
import java.applet.*;


class ISortPanel extends Canvas {
  private int LEFTMARGIN=50;
  private int TOPMARGIN=80;
  private int BOXSIZE=30;
  private int NextStep=0;

  private int MoveStep=-1;
  private int MoveHead=-1;
  private int MoveTail=-1;

  private int UP=-35;
  private int NORMAL=0;
  private int DOWN=35;

  private Font f;
  private long PAUSE_TIME=300;

  private int I=-1;
  private int J=-1;

  public int arr[];
  public int posx[];
  public int posy[];

  private int blue=-1;
  private int current=0;
  private boolean Erase=false;

  private Thread kicker;


  public ISortPanel() {
   /* set background as White */
   setBackground(Color.white);

   int a[] = new int[10];
   arr = a;

   int px[] = new int[10];
   posx = px;

   int py[] = new int[10];
   posy = py;

   f = new Font("Courier", Font.PLAIN, 14);
   reset();
  }

  public void reset()
  {
   NextStep = 0;
   blue=-1;
   current=0;

   for (int i=0; i<10; i++) {
        posx[i] = i;
        posy[i] = NORMAL;
   }

   arr[0] = 3;  arr[1] = 10;  arr[2] = 4;  arr[3] = 6;  arr[4] = 8;
   arr[5] = 9;  arr[6] = 7;   arr[7] = 2;  arr[8] = 1;  arr[9] = 5;

   repaint();
  }

  public void paint(Graphics g) {

   System.out.println("paint!");
   if (J<0 && MoveStep<0) g.clearRect(0, 0, size().width-1, size().height-1);
   g.drawRect(0, 0, size().width-1, size().height-1);

   g.setFont(f);

   if (J>=0 || MoveStep>=0) {

    if (J>=0) {
      if (Erase) {
	EraseElement(g, J, posx[J], posy[J]); 
      } else {
/*	if (posy[I] == UP) g.setColor(Color.red);
	if (posy[I] == DOWN) g.setColor(Color.red); */

	if (J <= blue)
	  g.setColor(Color.blue);
	else
	  g.setColor(Color.black);
	DrawElement(g, J, posx[J], posy[J]); 
      }
    }

    if (MoveStep >= 0) {
      if (Erase) {
	for (int k=MoveHead; k<=MoveTail; k++) {
	  EraseElement(g, k, posx[k], posy[k], MoveStep);
	}
      } else {
	for (int k=MoveHead; k<=MoveTail; k++) {
	  g.setColor(Color.blue);
	  DrawElement(g, k, posx[k], posy[k], MoveStep);
	}
      }
    }

    return;
   }

   for (int i=0; i<10; i++) {
    if (i <= blue)
	g.setColor(Color.blue);
    else
	g.setColor(Color.black);
/*    if (posy[i] == UP) g.setColor(Color.red);
    if (posy[i] == DOWN) g.setColor(Color.green);  */
    DrawElement(g, i, posx[i], posy[i]);
   }

  }

  public void update(Graphics g) { 
	System.out.println("update!"); 
	this.paint(g); 
  }

  public void EraseElement(Graphics g, int index, int positionX, int positionY)
  {
     g.clearRect(LEFTMARGIN+(BOXSIZE+1)*positionX, TOPMARGIN+positionY,
                BOXSIZE+1, BOXSIZE+1);
  }

  public void EraseElement(Graphics g, int index, 
			int positionX, int positionY, int m)
  {
     g.clearRect((int)(LEFTMARGIN+(BOXSIZE+1)*positionX+(BOXSIZE+1)*(m/5.0)), 
		TOPMARGIN+positionY, BOXSIZE+1, BOXSIZE+1);
  }



  public void DrawElement(Graphics g, int index, int positionX, int positionY) {
     if (current == index) {
       g.setColor(Color.red);
       g.drawOval(LEFTMARGIN+(BOXSIZE+1)*positionX+2, TOPMARGIN+positionY+2, 
                BOXSIZE-4, BOXSIZE-4);
     } else {
       g.drawRect(LEFTMARGIN+(BOXSIZE+1)*positionX, TOPMARGIN+positionY, 
                BOXSIZE, BOXSIZE);
     }

     g.drawString(Integer.toString(arr[index]),
         LEFTMARGIN+(BOXSIZE+1)*positionX+8, TOPMARGIN+20+positionY);
  }

  public void DrawElement(Graphics g, int index, int positionX, 
			int positionY, int m) {
     g.drawString(Integer.toString(arr[index]),
	(int)(LEFTMARGIN+(BOXSIZE+1)*positionX+8 + (BOXSIZE+1)*(m/5.0)), 
	TOPMARGIN+20+positionY);
     
     g.drawRect((int)(LEFTMARGIN+(BOXSIZE+1)*positionX + (BOXSIZE+1)*(m/5.0)), 
		TOPMARGIN+positionY, BOXSIZE, BOXSIZE);
  }
   


  public void GoAndUpdate(int i, int j) {
   int tmp;

   /* Wait a while before really go */
   try {
       Thread.sleep(PAUSE_TIME);
   } catch (InterruptedException e1){
   }

   J = j;
   

   for (int k=0; k<j-i; k++) {
     Erase = true;
     paint(this.getGraphics());

     posx[j] -= 1;
     Erase = false;
     paint(this.getGraphics());

    try {
      Thread.sleep(PAUSE_TIME);
    } catch (InterruptedException e1){
    }
   }

   Erase = true;
   paint(this.getGraphics());

   blue++;
   current = -1;
   posy[j] = NORMAL;
   Erase = false;
   paint(this.getGraphics());


   /*
    *  Updating...
    */
   tmp = arr[j];
   for (int k=j; k>i; k--) arr[k] = arr[k-1];
   arr[i] = tmp;

   for (int k=i; k<=j; k++) posx[k] = k;

   J = -1;


   try {
     Thread.sleep(PAUSE_TIME);
   } catch (InterruptedException e1){
   }

  }	/* End GoAndUpdate() */


  void Move(int i, int j) {
   
   try {
     Thread.sleep(PAUSE_TIME/3);
   } catch (InterruptedException e1){
   }

   MoveHead = i;
   MoveTail = j;
   MoveStep = 0;

   for (int k=1; k<=5; k++) {
    Erase = true;
    paint(this.getGraphics());

    MoveStep = k;
    Erase = false;
    paint(this.getGraphics());
   
    try {
      Thread.sleep(PAUSE_TIME/3);
    } catch (InterruptedException e1){
    }
   }

   Erase = true;

   for (int k=i; k<=j; k++) posx[k] += 1;
   MoveStep = -1;

  }


  void Up(int i) {
   int tmp;

   J = i;
   current = i;

   try {
     Thread.sleep(PAUSE_TIME);
   } catch (InterruptedException e1){
   }

   Erase = true;
   paint(this.getGraphics());

   posy[i] = UP;
   Erase = false;
   paint(this.getGraphics());

   J = -1;

   try {
     Thread.sleep(PAUSE_TIME);
   } catch (InterruptedException e1){
   }
  }



  public void Next() {
   Draw draw = new Draw();

   draw.SetISortPanel(this);
   switch (NextStep) {
    case 0:
	blue++;
	current = 1;
	repaint();
	break;

    case 1:
	blue++;
	current = -1;
	repaint();
	break;

    case 2:
	current = 2;
	repaint();
	break;

    case 3:
	draw.AddUpIndex(2);
	draw.start();
	break;

    case 4:
	draw.AddMoveIndex(1, 1);
	draw.start();
	break;

    case 5:
	draw.AddGoIndex(1, 2);
	draw.start();
	break;

    case 6:
	draw.AddUpIndex(3);
	draw.AddMoveIndex(2, 2);
	draw.AddGoIndex(2, 3);
	draw.start();
	break;

    case 7:
	draw.AddUpIndex(4);
	draw.AddMoveIndex(3, 3);
	draw.AddGoIndex(3, 4);

	draw.AddUpIndex(5);
	draw.AddMoveIndex(4, 4);
	draw.AddGoIndex(4, 5);

	draw.AddUpIndex(6);
	draw.AddMoveIndex(3, 5);
	draw.AddGoIndex(3, 6);

	draw.AddUpIndex(7);
	draw.AddMoveIndex(0, 6);
	draw.AddGoIndex(0, 7);

	draw.AddUpIndex(8);
	draw.AddMoveIndex(0, 7);
	draw.AddGoIndex(0, 8);

	draw.AddUpIndex(9);
	draw.AddMoveIndex(4, 8);
	draw.AddGoIndex(4, 9);

	draw.start();
	break;

    default:
   }

   NextStep++;
  }

}


class Draw extends Thread {
  private int I[] = new int[100];
  private int J[] = new int[100];
  private int count=0;
  private ISortPanel p;

  private int order[] = new int[100];

  public void SetISortPanel(ISortPanel panel) {
   p = panel;
  }

  public void AddUpIndex(int i) {
   I[count]=i; 
   order[count] = 0;
   count++;
  }

  public void AddMoveIndex(int i, int j) {
   I[count]=i;
   J[count]=j;
   order[count] = 1;
   count++;
  }

  public void AddGoIndex(int i, int j) {
   I[count]=i;
   J[count]=j;
   order[count] = 2;
   count++;
  }

  public void run() { 
    for (int i=0; i<count; i++) {
        if (order[i] == 0) 
          p.Up(I[i]);
        else if (order[i] == 1)
          p.Move(I[i], J[i]);
	else
	  p.GoAndUpdate(I[i], J[i]);
    }
  }

}

