/* binomial.java - jpq - 10/10/99 - 24/10/99 - 08/02/00 - 03/03/00
 * 8/05/00 - 05/02/02 - 25/02/02
 * ajout de main() le 01/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 = 180201L;
  controles C;
  dessin D;
 
  private int gparm (String s, int n) {
    try {
	  s = getParameter (s);
	  n = Integer.parseInt (s);
	}
	catch (NumberFormatException e) {}
    catch (NullPointerException e) {}
	return Math.max (n, 0);
  }

  public void init () {
    setLayout (new BorderLayout ());
    int NTR = gparm ("brouges", 35);
    int NTV = gparm ("bvertes", 65);
    int nt = gparm ("nt", 10);
    int Nsimul = gparm ("Nsimul", 1);
    D = new dessin (NTR, NTV, nt, Nsimul, 0, 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 = 180201L;
  Image img;
  Graphics g;
  int n, bsup, h, w, N;
  double p, max;
  double [] histogramme;
  double [] [] cnk;
  boolean retrace, binomial;
  int imax, dt, nN, nB, Nsimul, nNpnB;
  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;
    nNpnB = nN + nB;
    rnd = new Random ();
    bsup = n + 1;
    histogramme = new double [bsup];
    cnk = new double [2] [bsup];
    calccnk ();
  }

  public void calccnk ()
  { 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;
    }
  }

  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;
      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;
        for (int k = 0; k < n; k ++) if ((int)(rnd.nextDouble () * nNpnB) + 1 <= nB) 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 = 180201L;
  dessin D;
  TextField tp, /* tdt, */ tNsimul, tnt;
  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, int i)
  { TextField tf = new TextField (Integer.toString (n), i);
    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);
//    add (ajoutlbl ("dt ="));
//    add (tdt = ajouttf (D.dt, 2));
    Label l;
    add (ajoutlbl ("n="));
    add (tnt = ajouttf (D.n, 4));
    add (ajoutlbl ("Nbr. de simulations :"));
    add (tNsimul = ajouttf (D.Nsimul, 4));
    add (ok = ajoutb ("Ok"));
    add (ajoutlbl ("p="));
    add (tp = new TextField (new Double(D.p).toString()));
    tp.setFont (f);
    add (binomial = ajoutb ("B"));
  }

  public void actionPerformed (ActionEvent e)
  { if ((e.getSource () == ok) || (e.getSource () == binomial))
    { double np = D.p;
      try { np = new Double(tp.getText ()).doubleValue(); }
      catch (NumberFormatException nfe) { }
      if ((np >= 0.0) && (np <= 1.0)) D.p = np;
      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));
      int nN = D.Nsimul;
      try { nN = Integer.parseInt (tNsimul.getText ()); }
      catch (NumberFormatException nfe) { }
      if (nN >= 0) D.Nsimul = nN;
      tNsimul.setText (Integer.toString (D.Nsimul));
      nN = D.n;
      try { nN = Integer.parseInt (tnt.getText ()); }
      catch (NumberFormatException nfe) { }
      boolean b = false;
      if (nN >= 0)
      { b = (D.n != nN);
        D.n = nN;
      }
      tnt.setText (Integer.toString (D.n));
      if (D.n > D.histogramme.length)
      { D.bsup = D.n + 1;
        D.histogramme = new double [D.bsup];
        D.cnk = new double [2] [D.bsup];
      }
      if (b)
      { D.bsup = D.n + 1;
        D.calccnk ();
      }
      if (e.getSource () == binomial) D.binomial = ! D.binomial;
      else D.retrace = true;
      D.repaint ();
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

  public static void main (String [] args) {

    binomial b = new binomial();
    b.init();
    b.start();

    Frame f = new Frame ("binomial");
    f.addWindowListener (new fermer ());
    f.add (b);
    f.setSize (500, 400);
    f.setVisible (true);
  }

  protected static final class fermer extends WindowAdapter {
    public void windowClosing (WindowEvent e) {
      System.exit (0);
    }
  }

}
