import java.awt.*;
import java.io.InputStream;
import java.util.Hashtable;
import java.net.*;


public class GestTri extends java.applet.Applet  {

  PanelTri panelTri;

  // Constructeur de GestTri
      public GestTri() {
      BorderLayout b = new BorderLayout();
      setLayout(b);
      add("Center", panelTri = new PanelTri());
      setBackground(Color.blue);
      setForeground(Color.white);
      Dimension size = b.preferredLayoutSize(this);
      resize(800, 3000);
    }


  // Initialisation de l' applet.
  public void init() {
    panelTri.setAlgo();
  }
 }


class PanelTri extends Panel implements Runnable {

  // compteur de lignes d'edition
  int ligne;

  // Le thread de tri (ou null).
  private Thread lancetri;

  // Tableau qui va etre trie
  int chiffre[];

  //Les couleurs associees a chaque numero genere
  int coul[];

  //Les etats associes aux valeurs (Valeur placee ou pas encore)
  int place[];

  //Stockage pour step by step
  int stock [];

  //Choix du mode d'execution
  int choix;

  //Indicateur de debut
  int debut;

  //Indicateur de fin de l'affichage
  int fin;

  //Instance de l'algo de tri
  AlgoTri algo;

  // Construction du panel de tri
  PanelTri() {
    Button step,direct;
    step = new Button("STEP");
    add (step);
    direct = new Button("DIRECT");
    add (direct);
    setAlgo();
    resize(800, 3000);
    stock=new int[500];
    ligne=0;
    debut=1;
    fin=0;
  }

  public Dimension preferredSize() {
    return new Dimension(800, 3000);
  }

  public Dimension minimumSize() {
    return new Dimension(800, 3000);
  }

  // Permet de ne pas lancer deux tri en meme temps
  // si l'utilisateur reclique avant que le tri precedent
  // ne soit termine, et reinitialise les variables
  void setAlgo() {
    if(lancetri != null) {
      lancetri.stop();
      lancetri = null;
    }
    ligne=0;
    fin=0;
  }

  // Remplit le tableau de chiffres avec des nombres aleatoires
  // compris entre 1 et 99 et alloue a chacun une couleur par defaut
  void remptab() {
    Graphics g = getGraphics();
    for (int i=0;i<500;i++)
      stock[i]=0;
    g.clearRect (130,45,800,3000);
    ligne=0;
    int ch[] = new int[5];
    int c[]  = new int[5];
	int pl[] = new int[5];
    for (int i=0; i < 5; i++)
      {
        c[i]=i;
      }
    for (int i = 5; --i >= 0;)
      {
        ch[i] = ((int)(Math.random() * 99)+1);
      }
	for (int i = 5; --i >= 0;)
      {
        pl[i] = 0;
      }
    chiffre = ch;
    coul    = c;
	place   = pl;
  }


  // Appel de la fonction d'affichage en accord avec le bouton selectionne
  public void afficher(){
    Graphics g = getGraphics();
    if (choix==1)
      afficher2(g);
    else
      if (fin == 0)
        afficher1 (g);
      else
        afficherfin(g);
  }


  //
  // Lance l'affichage et attend un peu
  // @see AlgoTri
  void pause() {
    int ch[] = chiffre;
    int c[]  = coul;
	int pl[] = place;
    if (lancetri != null)
      {
        for (int k=0;k<5;k++)
          {
            stock[k+(ligne*15)]=ch[k];
            stock[k+(ligne*15)+5]=c[k];
			stock[k+(ligne*15)+10]=pl[k];
          }
        if (choix == 1)
          ligne++;
        else
          afficher();
      }
    try {Thread.sleep(20); }
    catch (InterruptedException e){}
  }


  //   Dessin d'une ligne dans le cas de "DIRECT"
  public void afficher1(Graphics g) {
    int ch[] = chiffre;
    int c[]  = coul;
	int pl[] = place;
    int p1 = 10;
    int p2;
    int i=0;

    for (i = 0;i < 5;i++) {
      switch (c[i]) {
      case (0):
        g.setColor(Color.white);
        break;
      case (1):
        g.setColor(Color.pink);
        break;
      case (2):
        g.setColor(Color.cyan);
        break;
      case (3):
        g.setColor(Color.green);
        break;
      case (4):
        g.setColor(Color.yellow);
        break;
      default :
        g.setColor(Color.red);
      }

      p1 = p1 + 120;
      p2 = p1 + 13;
	  if (pl[i] == 0) 
	   {
         g.fillRect (p1,45 + ligne*45,40,40);
	   }
      else
	   {
         g.fillOval (p1,45 + ligne*45,40,40);
       }
      g.setColor(Color.black);
      g.drawString (""+ ch[i],p2,70 + ligne * 45);
    }
    ligne++;
  }
  //   Affichage du message "tri termine"
  public void afficherfin(Graphics g)
  {
    ligne++;
    g.setColor(Color.black);
    g.fillOval (300,45 + ligne*45,200,40);
    g.setColor(Color.white);
    g.drawString ("TRI TERMINE",360,70 + ligne * 45);
    ligne--;
  }

  //   Dessin d'une ligne dans le cas du step by step
  //   a partir du tableau "stock" dans lequel toutes
  //   les etapes du tri ont ete enregistrees
  public void afficher2(Graphics g) {
    int s[] = stock;
    int p1 = 10;
    int p2=0;
    int i=0;

    for (i = 0;i < 5;i++) {
      switch (s[i+(ligne*15)+5]) {
      case (0):
        g.setColor(Color.white);
        break;
      case (1):
        g.setColor(Color.pink);
        break;
      case (2):
        g.setColor(Color.cyan);
        break;
      case (3):
        g.setColor(Color.green);
        break;
      case (4):
        g.setColor(Color.yellow);
        break;
      default :
        g.setColor(Color.red);
      }

      p1 = p1 + 120;
      p2 = p1 + 13;
	  if (s[i+(ligne*15)+10] == 0)
	  {
         g.fillRect (p1,45 + ligne*45,40,40);
      }
	  else
	  {
	     g.fillOval (p1,45 + ligne*45,40,40);
      };
      g.setColor(Color.black);
      g.drawString (""+ s[i+ligne*15],p2,70 + ligne * 45);

    }

    ligne++;
    if (s[1+ligne*15]==0)
      {
        fin=1;
        g.setColor(Color.black);
        g.fillRect (300,45 + ligne*45,200,40);
        g.setColor(Color.white);
        g.drawString ("TRI TERMINE",360,70 + ligne * 45);
      }
  }

  //   Dessin de ce qui pu etre efface en bougeant la fenetre
  public void paint (Graphics g) {
    int s[] = stock;
    int p1 = 10;
    int p2=0;
    int i=0;
    int finpaint=0;
    int ligpaint=0;
    if (stock[1]==0)
      finpaint=1;
    while (finpaint==0)
      {
        p1 = 10;
        p2=0;
        for (i = 0;i < 5;i++) {
          switch (s[i+(ligpaint*15)+5]) {
          case (0):
            g.setColor(Color.white);
            break;
          case (1):
            g.setColor(Color.pink);
            break;
          case (2):
            g.setColor(Color.cyan);
            break;
          case (3):
            g.setColor(Color.green);
            break;
          case (4):
            g.setColor(Color.yellow);
            break;
          default :
            g.setColor(Color.red);
          }

          p1 = p1 + 120;
          p2 = p1 + 13;
		  if (s[i+(ligpaint*15)+10] == 0)
		  {
            g.fillRect (p1,45 + ligpaint*45,40,40);
		  }
		  else
		  {	  
            g.fillOval (p1,45 + ligpaint*45,40,40);
		  };
          g.setColor(Color.black);
          g.drawString (""+ s[i+ligpaint*15],p2,70 + ligpaint * 45);

        }
        ligpaint++;
        if ((s[1+ligpaint*15]==0)||(ligpaint==ligne))                  /* ici ici ici */
          {
            finpaint=1;
          }
      }
    if (fin == 1)
      afficherfin(g);
  }

  // Mise a jour de l'ecran sans l effacer
  public void update (Graphics g){
    paint(g);
  }

  //  Active a la fin de startSort il cree une instance d'algo de tri
  //  puis lance le tri
  public void run() {
    try {
      algo = (AlgoTri)
        Class.forName("Tri").newInstance();
      algo.setParent(this);
      algo.tri(chiffre,coul,place);
      debut=0;
      if (choix !=1 )
        {
          fin=1;
          afficher();
        }
      else
        {
          ligne=0;
          afficher();
        }
    }
    catch(Exception e) {}
  }

  // arrete l'applet et tue l'algo de tri
  // s'il est entrain de s'executer
  public synchronized void stop() {
    if (lancetri != null)
      {
      try {
        lancetri.stop();
      }
      catch (IllegalThreadStateException e) {}
      lancetri = null;
      }
   }


  // Appelle la fonction run
  private synchronized void startSort() {
    if (lancetri == null || !lancetri.isAlive()) {
      remptab();
      lancetri = new Thread(this);
      lancetri.start();
    }
  }

  // Recupere les clicks boutons et les gere
  public boolean action(Event evt,Object arg) {
    Button bouton;
    if (evt.target instanceof Button)
      {
        bouton = (Button) evt.target;
        if (fin == 1)
          debut = 1;
        if (bouton.getLabel() == "DIRECT")
          {
            if (choix==1 && debut !=1 )
              {
                while (fin == 0)
                  {
                    afficher();
                  }
                choix=0;
              }
            else
              {
                choix = 2;
              }
          }
        if (bouton.getLabel() == "STEP")
          {
            choix=1;
            if (debut == 0 && fin == 0)
              afficher();
          }
        if (debut == 1)
          {
            setAlgo();
            startSort();
            return false;
          }
        return false;
      }
    return true;
  }
}
