/* binomial.java - jpq - 10/10/99 - 24/10/99 - 08/02/00 - 03/03/00
 * 8/05/00
 * ajout de main() le 05/02/18
 */

import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.util.*;


public class binomial extends java.applet.Applet {
  static final long serialVersionUID = 180205L;
  controles C;
  dessin D;

  public void init ()
  { setLayout (new BorderLayout ());
    D = new dessin (311, 414, 20, 100, 50, 0.5);
    C = new controles (D);
    add (C, BorderLayout.NORTH);
    add (D, BorderLayout.CENTER);
  }

  public void destroy ()
  { remove (D); remove (C);}

  public String getAppletInfo ()
  { return "binomial par j.-p. Quelen"; }

////////////////////////////////////////////////////////////////////////////////
protected class dessin extends Canvas {
  static final long serialVersionUID = 180205L;
  Image img;
  Graphics g;
  int n, bsup, h, w, N;
  double p, max;
  double [] histogramme;
  double [] [] cnk = new double [2] [21];
  boolean retrace, binomial;
  int imax, dt, nN, nB, Nsimul;
  double darrond = 100.0;
  Random rnd;

  public dessin (int nN, int nB, int n, int Nsimul, int dt, double p)
  { this.nN = nN;
    this.nB = nB;
    this.n = n;
    this.Nsimul = Nsimul;
    this.dt = dt;
    rnd = new Random ();
    this.p = p;
//    binomial = false;
    retrace = true;
    bsup = n + 1;
    histogramme = new double [bsup];
    cnk = new double [2] [bsup];
    int k = (n + 1) % 2;
    for (int i = 0; i < n; i ++)
    { cnk [k] [0] = cnk [k] [i + 1] = 1.0;
      int k1 = (k + 1) % 2;
      for (int j = 1; j <= i; j ++) cnk [k] [j] = cnk [k1] [j - 1] + cnk [k1] [j];
      k = k1;
    }
    rnd = new Random ();
  }

  private String sarrondi (double d)
  { return Double.toString (Math.floor (d * darrond) / darrond); }

  public void message (Graphics g, String s)
  { g.drawString (s, 10, 10);
  }

  public void update (Graphics g)
  { paint (g); }

  private void affiche (Graphics g)
  { g.setColor (Color.white);
    g.fillRect (0, 0, w, h);
    g.setColor (Color.yellow);
    g.drawLine (20, h - 40, w, h - 40);
    g.drawLine (20, 40, 20, h - 40);
    g.setColor (Color.blue);
    g.drawString ("0", 5, h - 40);
    g.drawString (sarrondi (max / N), 5, 40);

    for (int j = 0; j < bsup; j ++)
    { int x = j * (w - 50) / bsup + 20;
      int y = h - 40 - (int)(histogramme [j] / max * (h - 80));
      g.setColor (Color.black);
      g.drawLine (x, y, x, h - 40);
      g.setColor (Color.blue);
      g.drawString (Integer.toString (j), x, h - 10);
    }
  }

  public void paint (Graphics g1)
  { if (img == null || w != getSize().width || h != getSize().height)
    { w = getSize().width;
      h = getSize().height;
      img = createImage (w, h);
      g = img.getGraphics ();
      g.setColor (Color.white);
      g.fillRect (0, 0,  w - 2, h - 2);
      g.setColor (Color.black);
      g.drawRect (0, 0, w - 1, h - 1);
    }
    if (retrace)
    { retrace = false;
      double somme = 0.0;
      double somme2 = 0.0;
      double valmin = Double.MAX_VALUE;
      double valmax = - valmin;
      max = 0; N = 0;
      for (int i = 0; i < histogramme.length; i ++) histogramme [i] = 0;
      for (int j = 0; j < Nsimul; j ++)
      { int dn = 0, db = 0;
        int nNpnB = nN + nB;
        for (int k = 0; k < n; k ++) if ((int)(rnd.nextDouble () * nNpnB --) + 1 <= nB - db) db ++; else dn ++;
        histogramme [dn] ++;
        if (histogramme [dn] > max) max = histogramme [dn];
        N ++;
        try { Thread.sleep (dt); }
        catch (InterruptedException e) {}
        affiche (g);
        g1.drawImage (img, 0, 0, this); 
      }
    }
    affiche (g);
    if (binomial)
    { g.setColor (Color.blue);
      double q = 1.0 - p;
      double d = Math.pow (q, n);
      for (int i = 0; i < bsup; i++)
      { int x = i * (w - 50) / bsup + 20;
        int y = h - 40 - (int)(cnk [0] [i] * d * N / max * (h - 80));
        d = d * p / q;
        g.fillRect (x - 1, y - 1, 3, 3);
      }
    }
    g1.drawImage (img, 0, 0, this); 
  }
}
////////////////////////////////////////////////////////////////////////////////
protected class controles extends Panel implements ActionListener {
  static final long serialVersionUID = 180205L;
  dessin D;
  TextField tp, tdt, tNsimul;
  Button ok, binomial;
  Font f;

  private Label ajoutlbl (String s)
  { Label lbl = new Label (s);
    lbl.setBackground (Color.lightGray);
    lbl.setFont (f);
    return lbl;
  }

  private TextField ajouttf (int n)
  { TextField tf = new TextField (Integer.toString (n));
    tf.setFont (f);
    return tf;
  }

  private Button ajoutb (String s)
  { Button b = new Button (s);
    b.setFont (f);
    b.addActionListener (this);
    return b;
  }

  public controles (dessin D)
  { this.D = D;
    setLayout (new FlowLayout());
    setBackground (Color.lightGray);
    f = new Font ("Arial", Font.PLAIN, 10);
    Label l;
    add (ajoutlbl ("n = " + Integer.toString (D.n) + " p = "));
    add (tp = new TextField (new Double(D.p).toString()));
    tp.setFont (f);
    add (ajoutlbl ("Nbr. de simulations :"));
    add (tNsimul = ajouttf (D.Nsimul));
    add (ok = ajoutb ("Ok"));
    add (binomial = ajoutb ("B"));
    add (ajoutlbl ("dt ="));
    add (tdt = ajouttf (D.dt));
  }

  public void actionPerformed (ActionEvent e)
  { if ((e.getSource () == ok) || (e.getSource () == binomial))
    { try { D.p = new Double(tp.getText ()).doubleValue(); }
      catch (NumberFormatException nfe) { }
      if (D.p < 0) D.p = 0; else if (D.p > 1) D.p = 1;
      tp.setText (Double.toString (D.p));
      try { D.dt = Integer.parseInt (tdt.getText ()); }
      catch (NumberFormatException nfe) { }
      if (D.dt < 0) D.dt = 0;
      tdt.setText (Integer.toString (D.dt));
      try { D.Nsimul = Integer.parseInt (tNsimul.getText ()); }
      catch (NumberFormatException nfe) { }
      if (D.Nsimul <= 0) D.Nsimul = 1;
      tNsimul.setText (Integer.toString (D.Nsimul));
      if (e.getSource () == binomial) D.binomial = ! D.binomial;
      else D.retrace = true;
      D.repaint ();
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

	public static void main (String [] args) {

// Création et lancement de l'applet
		binomial a = new binomial();
		a.init ();
		a.start ();

// Création de la fenêtre contenant l'applet
		Frame f = new Frame ("binomial");
		f.addWindowListener (new fermer ());
		f.add (a);
		f.setSize (500, 400);
		f.setVisible (true);
	}

// Permet la fermeture de la fenêtre contenant l'applet
	protected static final class fermer extends WindowAdapter {
		public void windowClosing (WindowEvent we) {
			System.exit (0);
		}
	}
}
