/* galton.java - jpq - 09/01/03
 * modification et ajout de main() le 06/02/18
 */
 
import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.util.*;

public class galton extends java.applet.Applet {
  static final long serialVersionUID = 180206L;
  controles C;
  dessin D;

  private int getparmi (String s, int n) {
	int nn = 0;
    try {
	  s = getParameter (s);
	  nn = Integer.parseInt (s);
	}
	catch (NumberFormatException e) {}
	catch (NullPointerException e) {}
	if (nn <= 0)
	  nn = n;
    return nn;
  }
    
  public void init () {
	setLayout (new BorderLayout ());
    int nclous = getparmi ("nclous", 10);
    int nb = getparmi ("nbilles", 10);
    int dt = getparmi ("dt", 5);
    D = new dessin (nclous, dt, nb);
    C = new controles (D);
    D.C = C;
    add (C, BorderLayout.NORTH);
    add (D, BorderLayout.CENTER);
  }

  public void destroy ()
  { remove (D); remove (C); }

  public String getAppletInfo ()
  { return "galton par j.-p. Quelen"; }

////////////////////////////////////////////////////////////////////////////////
protected class dessin extends Canvas {
  static final long serialVersionUID = 180206L;
  int nclous, n, dt, boucle;
  int L, H, Ls2, Hs4, Hb, Hb1;
  Random rnd;
  int [] classes;
  controles C;
  Image img;
  Graphics g;

  public dessin (int nclous, int dt, int n)
  { this.nclous = nclous;
    this.dt = dt;
    this.n = n;
    classes = new int [nclous + 1];
    gtab.maj (classes.length, classes);
    rnd = new Random ();
  }

// dessin de l'entonnoir

  private void ent (Graphics g)
  { g.setColor (Color.white);
    g.fillRect (1, 1, L, Hs4 - 10);
    g.setColor (Color.black);
    g.drawLine (Ls2 - Hs4, 1, Ls2 - 10, Hs4 - 10);
    g.drawLine (Ls2 + 10, Hs4 - 10,  Ls2 + Hs4, 1);
    g.setColor (Color.blue);
    for (int i = 0; i < n; i ++)
    { int x = (int)(rnd.nextDouble () * (Math.max (0, Hs4 - 15)));
      int y = (int)(rnd.nextDouble () * (Math.max (0, Hs4 - x - 15)));
      x *= (int)(rnd.nextDouble () * 2) * 2 - 1;
      g.fillOval (Ls2 + x, y, 7, 7);
    }
    g.setColor (Color.black);
    g.drawLine (0, 0, L, 0);
  }

  public void update (Graphics g)
  { paint (g); }

  public void paint (Graphics g1) {
    if (img == null || L + 2 != getSize().width || H + 2 != getSize().height) {
	  L = getSize().width;
      H = getSize().height;
      img = createImage (L, H);
      g = img.getGraphics ();
      L -= 2; H -= 2;
      Ls2 = L / 2;
      Hs4 = H / 4;
      Hb = H - 50;
    }
    g.setColor (Color.black);
    g.drawRect (0, 0, L + 1, H + 1);
    g.setColor (Color.white);
    g.fillRect (1, 1, L, H);
// dessin de l'entonnoir
    ent (g);
// dessin des clous
    g.setColor (Color.green);
    int pas = (Hb - Hs4) / nclous;
    int dec = 0;
    int x = Ls2 - 2;
    int x1 = x;
    int y = Hs4 - 2;
    for (int i = 0; i < nclous; i ++)
    { while (x1 - 3 - dec > 0)
      { g.fillOval (x, y, 5, 5);
        g.fillOval (x1, y, 5, 5);
        x += pas;
        x1 -= pas;
      }
      y += pas;
      if (dec == 0) dec = pas / 2; else dec = 0;
      x = Ls2 - 2 + dec;
      x1 = x;
    }
// dessin des bacs
    Hb1 = y;
    g.setColor (Color.black);
    g.drawLine (1, H, L, H);
    int dec1 = 0;
    if (dec == 0) dec1 = pas / 2;
    x = Ls2 + dec1;
    x1 = x;
    int ind = nclous / 2;
    int ind1 = ind;
    while (x1 + pas > 0)
    { g.setColor (Color.black);
      g.drawLine (x, H, x, Hb1);
      g.drawLine (x1, H, x1, Hb1);
      g.setColor (Color.blue);
      if ((ind >= 0) && (ind < classes.length))
      { int ci = classes [ind];
        if (ci > 0) g.fillRect (x - pas, H - ci, pas, ci);
      }
      if ((ind1 >= 0) && (ind1 < classes.length))
      { int ci = classes [ind1];
        if (ci > 0) g.fillRect (x1 - pas, H - ci, pas, ci);
      }
      x += pas;
      x1 -= pas;
      ind ++;
      ind1 --;
    }
   g1.drawImage (img, 0, 0, this);
// dessin de la bille qui tombe
    while (boucle > 0)
    { boucle --;
      n --;
      ent (g);
      C.tn.setText (Integer.toString (n));
      dec = 0;
      int xp = 10000;
      int yp = 10000;
      x = Ls2 - 3;
      y = Hs4 - pas / 2 - 3;
      ind = 0;
      for (int i = 0; i < nclous; i ++)
      { boolean brnd = (rnd.nextDouble () >= 0.5);
        if (brnd) x += pas / 2; else x -= pas / 2;
        if (brnd) ind ++;
        for (int k = 0; k < pas; k ++)
        { g.setColor (Color.white);
          g.fillOval (xp, yp, 7, 7);
          g.setColor (Color.blue);
          g.fillOval (x, y, 7, 7);
//          g1.drawImage (img, 0, 0, this);
          xp = x; yp = y ++;
          if (dt > 0)
          { try { Thread.sleep (dt); }
            catch (InterruptedException e) {}
          }
        }
        if (i == 0)
        { g.setColor (Color.black);
          g.drawLine (Ls2 - Hs4, 1, Ls2 - 10, Hs4 - 10);
          g.drawLine (Ls2 + 10, Hs4 - 10,  Ls2 + Hs4, 1);
//          g1.drawImage (img, 0, 0, this);
        }
      }
      g.setColor (Color.white);
      g.fillOval (xp, yp, 7, 7);
      if ((ind >= 0) && (ind < classes.length)) classes [ind] ++;
    x = Ls2 + dec1;
    x1 = x;
    ind = nclous / 2;
    ind1 = ind;
    while (x1 + pas > 0)
    { g.setColor (Color.black);
      g.drawLine (x, H, x, Hb1);
      g.drawLine (x1, H, x1, Hb1);
      g.setColor (Color.blue);
      if ((ind >= 0) && (ind < classes.length))
      { int ci = classes [ind];
        if (ci > 0) g.fillRect (x - pas, H - ci, pas, ci);
      }
      if ((ind1 >= 0) && (ind1 < classes.length))
      { int ci = classes [ind1];
        if (ci > 0) g.fillRect (x1 - pas, H - ci, pas, ci);
      }
      x += pas;
      x1 -= pas;
      ind ++;
      ind1 --;
    }
    g1.drawImage (img, 0, 0, this);
// 
    gtab.maj (nclous + 1, classes);
    }
  }
}
////////////////////////////////////////////////////////////////////////////////
protected class controles extends Panel implements ActionListener {
  static final long serialVersionUID = 180206L;
  dessin D;
  TextField tn, tdt, tnclous;
  Button ok, plus, etoile;
  Font f;

  private Label ajoutlbl (String s)
  { Label l = new Label (s);
    l.setBackground (Color.lightGray);
    l.setFont (f);
    return l;
  }

  private TextField ajouttf (int i, int j)
  { TextField T = new TextField (Integer.toString (i), j);
    T.setFont (f);
    return T;
  }

  private Button ajoutb (String s)
  { Button b = new Button (s);
    b.addActionListener (this);
    b.setFont (f);
    return b;
  }

  public controles (dessin D)
  { this.D = D;
    f = new Font ("Arial", Font.PLAIN, 10);
    setBackground (Color.lightGray);
    setLayout (new GridLayout(2, 1));
    Panel p = new Panel ();
    add (p);
    p.add (ajoutlbl ("clous :"));
    p.add (tnclous = ajouttf (D.nclous, 2));
    p.add (ok = ajoutb ("RAZ"));
    p = new Panel ();
    add (p);
    p.add (ajoutlbl ("dt :"));
    p.add (tdt = ajouttf (D.dt, 2));
    p.add (ajoutlbl ("billes :"));
    p.add (tn = ajouttf (D.n, 3));
    p.add (plus = ajoutb ("+"));
    p.add (etoile = ajoutb ("*"));
  }

  private int maj (TextField T, int n)
  { try { n = Integer.parseInt (T.getText ()); }
      catch (NumberFormatException nfe) { }
    if (n <= 0) n = 1;
    return n;
  }

  public void actionPerformed (ActionEvent e)
  { Object obj = e.getSource ();
    if (( obj == ok) || (obj == plus) || (obj == etoile))
    { int n = maj (tn, D.n);
      if (n >= 0) D.n = n;
      tn.setText (Integer.toString (D.n));
      try { D.dt = Integer.parseInt (tdt.getText ()); }
      catch (NumberFormatException nfe) { }
      tdt.setText (Integer.toString (D.dt));
      if (obj == ok)
      { int nclous = maj (tnclous, D.nclous);
        if (nclous > 0) D.nclous = nclous;
        if (D.classes.length < nclous + 1) D.classes = new int [nclous + 1];
        else for (int i = 0; i < D.classes.length; i ++) D.classes [i] = 0;
        gtab.maj (D.nclous + 1, D.classes);
      }
      else if (obj == plus) D.boucle = 1;
           else D.boucle = D.n;
      tnclous.setText (Integer.toString (D.nclous));
      tdt.setText (Integer.toString (D.dt));
      D.repaint ();
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

	public static void main (String [] args) {

		galton a = new galton ();
		a.init ();
		a.start ();

		afftab a1 = new afftab ();
		a1.init ();
		a1.start ();

		Frame f = new Frame ("Planche de Galton");
		f.addWindowListener (new fermer ());
		f.add (a);
		f.setSize (360, 480);
		f.setVisible (true);

		Frame f1 = new Frame ("Tableau de résultats");
		f1.addWindowListener (new fermer ());
		f1.add (a1);
		f1.setSize (280, 100);
		f1.setVisible (true);

    }

// Permet la fermeture de la fenêtre contenant l'applet
	protected static final class fermer extends WindowAdapter {
		public void windowClosing (WindowEvent e) {
			System.exit (0);
		}
	}

}
////////////////////////////////////////////////////////////////////////////////
class gtab {
  static final long serialVersionUID = 180206L;
  static boolean change;
  static int dim;
  static int [] tableau;

  static public void maj (int d, int [] tab)
  { dim = d;
    tableau = tab;
    change = true;
  }
}
