/*****************************************************************
  Team: Jon Gregory, Gor Nishanov

  Small java program developed by Gor Nishanov for
  the project #1

  ****************************************************************/

import java.awt.*;
import java.applet.Applet;
import java.util.Random;

class SelectSort extends SortPanel {
  void sort() {
    for(int i = 0; i < N-1; ++i) {
      for(int j = i + 1; j < N; ++j)
        if(!inOrder(i,j)) swap(i,j);
    }
  }
  String sortName() { return "Selection"; }
}
class BubbleSort extends SortPanel {
  void sort() {
    for(int i = N; --i >= 0; ) {
      for(int j = 0; j < i; ++j)
        if(!inOrder(j,j+1)) swap(j,j+1);
    }
  }
  String sortName() { return "Bubble"; }
}
class QuickSort extends SortPanel {
  String sortName() { return "Quick"; }
  void sort() {
    quickSort(0,N-1);
  }
  void quickSort(int L, int R) {
    int l = L, r = R, m;
    if (R > L) {
      m = a[(L+R)/2];
      while( l <= r ) {
        while( (l < R) && (a[l] < m) ) ++l;
        while( (r > L) && (a[r] > m) ) --r;
        if( l <= r ) swap(l++, r--);
      }
      if( L < r )  quickSort( L, r );
      if( l < R )  quickSort( l, R );
    }
  }
}

class SortPanel extends Panel implements Runnable {
    final int SIZE     = 100;

    final int BARWIDTH = 1;
    final int BARSTEP  = 2;
    final int MARGIN   = 2;

    final int N = (SIZE - BARSTEP)/(BARWIDTH + BARSTEP);
    final int MAX = (SIZE - 2 * MARGIN);
    final int MIN = 10;

    int[] a = new int[MAX];

    boolean active = false;

    int abs(int v) { return (v<0)?-v:v; }

    boolean sorted = false;

    void reset() {
      if(! active) {
        Random r = new Random(1000);
        for(int i = 0; i < MAX; ++i) {
          a[i] = abs(r.nextInt() % (MAX - MIN)) + MIN;
        }
        repaint();
      }
      sorted = false;
    }

    void XCenter(String s, Color clr, int y) {
      Graphics g = getGraphics();
      FontMetrics fm = g.getFontMetrics();
      int w = fm.stringWidth(s);
      g.setColor(Color.black);
      g.drawString(s, (SIZE - w)/2+1, y+1);
      g.setColor(clr);
      g.drawString(s, (SIZE - w)/2, y);
    }

    String sortName() {
      return "Override Me";
    }

    public void run() {
      active = true;
      SortDemo.sortDemo.checkButtons();
      sort();
      XCenter("Complete", Color.yellow, SIZE/2);
      active = false;
      sorted = true;
      SortDemo.sortDemo.checkButtons();
    }

    SortPanel() {
      reset();
    }

    final int x = 1 + MARGIN;

    int y(int i) {
      return 1 + BARSTEP + i * (BARSTEP + BARWIDTH);
    }

    void drawBarPro(Graphics g, Color clr1, Color clr2, int i) {
      g.setColor(clr1);
      g.drawRect(x,y(i),a[i],BARWIDTH);
      g.setColor(clr2);
      g.drawRect(a[i]+1,y(i),SIZE - a[i] - MARGIN, BARWIDTH);
    }

    void drawBar(Graphics g, Color clr, int i) {
      drawBarPro(g, clr, Color.white, i);
    }

    public void paint(Graphics g) {
      g.drawRect(0,0,SIZE+2,SIZE+2);
      for(int i = 0; i < N; ++i) {
        drawBar(g, Color.black, i);
      }
      XCenter(sortName(),Color.red,SIZE + 13);
      if( sorted ) 
        XCenter("Complete", Color.yellow, SIZE/2);
    }

    void sort() {} // should be overriden

    boolean inOrder(int i, int j) {
      Graphics g = getGraphics();
      drawBar(g, Color.red, i);
      drawBar(g, Color.red, j);
      pause(25);
      drawBar(g, Color.black, i);
      drawBar(g, Color.black, j);
      return a[i] < a[j];
    }

    void pause(int n) {
      try {
      Thread.currentThread().sleep(n);
      } catch (Exception e) {
      }
    }

    synchronized void swap(int i, int j) {
      Graphics g = getGraphics();
      int tmp = a[i]; a[i] = a[j]; a[j] = tmp;
      drawBarPro(g, Color.blue, Color.blue, i);
      drawBarPro(g, Color.blue, Color.blue, j);
      pause(50);
      drawBar(g, Color.black, i);
      drawBar(g, Color.black, j);
    }

    public Dimension preferredSize() {
        return new Dimension(SIZE+3, SIZE+20);
    }
}

public class SortDemo extends Applet {
    SortPanel a, b, c;
    Button startButt, scramButt, quittButt;

    public SortDemo() {
        add(a = new SelectSort());
        add(b = new BubbleSort());
        add(c = new QuickSort());

        add(startButt = new Button("Start"));
        add(scramButt = new Button("Scramble"));
        add(quittButt  = new Button("Quit"));

        checkButtons();
    }
    void startAll() {
      new Thread(a).start();
      new Thread(b).start();
      new Thread(c).start();
    }
    void resetAll() {
      a.reset();
      b.reset();
      c.reset();
      checkButtons();
    }

    public void checkButtons() {
      startButt.enable(true);
      scramButt.enable(true);
      quittButt.enable(true);
      if(a.active || b.active || c.active) {
        startButt.enable(false);
        scramButt.enable(false);
        quittButt.enable(false);
      } else if(a.sorted || b.sorted || c.sorted ) {
        startButt.enable(false);
      } else if(!a.sorted && !b.sorted && !c.sorted) {
        scramButt.enable(false);
      }
    }

    public boolean action(Event evt, Object arg) {
      if(arg.equals("Start")) startAll();
      if(arg.equals("Scramble")) resetAll();
      if(arg.equals("Quit")) System.exit(0);
      return true;
    }

    static SortDemo sortDemo;

    public static void main(String args[]) {
        Frame f = new Frame("Sort Demo");
        sortDemo = new SortDemo();
        sortDemo.init();
        sortDemo.start();

        f.add("Center", sortDemo);
        f.resize(550, 150);
	f.show();
    }
}

