/* poisson.java - jpq - 06/12/99 - 20/02/15
 * modification le 09/02/18
 */

import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.util.*;

public class poisson extends java.applet.Applet {
  static final long serialVersionUID = 180209L;
  controles C;
  dessin D;

  private int gparmi (String s, int i) {
    try {
      s = getParameter (s);
      i = Integer.parseInt (s);
    }
    catch (NumberFormatException e) {}
    catch (NullPointerException e) {}
    return i;
  }
  
  private double gparmd (String s, double d) {
    try {
      s = getParameter (s);
      d = Double.parseDouble (s);
    }
    catch (NumberFormatException e) {}
    catch (NullPointerException e) {}
    return d;
  }

  public void init ()
  { setLayout (new BorderLayout ());
    int n = gparmi ("nsimul", 100);
    double l = gparmd ("lambda", 1.0);
    D = new dessin (n, l);
    C = new controles (D);
    add (C, BorderLayout.NORTH);
    add (D, BorderLayout.CENTER);
  }

  public void destroy ()
  { remove (D); remove (C); }

  public String getAppletInfo ()
  { return "poisson par j.-p. Quelen"; }

////////////////////////////////////////////////////////////////////////////////
protected class dessin extends Canvas {
  static final long serialVersionUID = 180209L;
  Image img;
  Graphics g;
  Random rnd;
  int n, loi, bsup, w, h;
  double l, expml;
  int [] histogramme = new int [11];
  int arrond = 2;
  double darrond = 100.0;
  double unsr2pi = 1.0 / Math.sqrt (2.0 * Math.PI);
  static final int POISSON = 3;
  static final int NORMALE = 4;
  boolean retrace;

  public dessin (int n, double l)
  { this.n = n;
    this.l = l;
// loi = 0;
    rnd = new Random ();
    init ();
  }

  private void init ()
  { expml = Math.exp (-l);
    bsup = 11;
  }

  private int rndpoiss (double lambda) {
    int resultat = 0;
    double r = rnd.nextDouble();
    double expmlambda = Math.exp (-lambda);
    while (r > expmlambda){
      resultat ++;
      r *= rnd.nextDouble();
    }
    return resultat;
  }

/*  private int rndpoiss (double lambda) {
    double somme = 1;
    double t = 1;
    int n = 0;
    double r = rnd.nextDouble() * Math.exp (lambda);
    while (somme < r) {
      n ++;
      t *= lambda / n;
      somme += t;
    }
    return n;
  } */

  private String sarrondi (double d)
  { if (arrond > 0) d = Math.floor (d * darrond) / darrond;
    return Double.toString (d);
  }

  private void h (Graphics g, int i)
  { g.setColor (Color.white);
    g.fillRect (1, 1, getSize().width - 2, getSize().height - 2);
    g.setColor (Color.yellow);
    g.drawLine (20, getSize().height - 40, getSize().width, getSize().height - 40);
    g.drawLine (20, 40, 20, getSize().height - 40);
    g.setColor (Color.blue);
    g.drawString ("0", 5, getSize().height - 40);
    g.drawString (Integer.toString (i + 1), 5, 40);

    for (int j = 0; j < bsup; j ++)
    { int x = j * (getSize().width - 50) / bsup + 50;
      int y = getSize().height - 40 - histogramme [j] * (getSize().height - 80) / (i + 1);
      g.setColor (Color.black);
      g.drawLine (x, y, x, getSize().height - 40);
      g.setColor (Color.blue);
      g.drawString (Integer.toString (j), x, getSize().height - 10);
    }
      g.setColor (Color.black);
      g.drawRect (0, 0, getSize().width - 1, getSize().height - 1);
  }

  public void update (Graphics g)
  { paint (g); }

  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.black);
      g.drawRect (0, 0, w - 1, h - 1);
      retrace = true;
    }

    g.setColor (Color.black);
    g.drawRect (0, 0, w - 1, h - 1);

    if (retrace)
    { retrace = false;
      for (int i = 0; i < histogramme.length; i ++) histogramme [i] = 0;
      for (int i = 0; i < n; i ++)
      { int j = rndpoiss (l);
        if (j >= bsup)
        { bsup = j + 1;
          if (bsup > histogramme.length)
          { int nh [] = new int [bsup];
            System.arraycopy (histogramme, 0, nh, 0, histogramme.length);
            histogramme = nh;
          }
        }
        histogramme [j] ++;
        h (g, i);
        g1.drawImage (img, 0, 0, this);
      }
    }
    else h (g, n - 1);

      g.setColor (Color.blue);
      switch (loi)
      { case POISSON :
          double proba = expml;
          for (int i = 0; i <= bsup; i ++)
          { int x = i * (getSize().width - 50) / bsup + 50;
            int y = getSize().height - 40 - (int)(proba * (getSize().height - 80));
            g.fillRect (x - 1, y - 1, 3, 3);
            proba = proba * l / (i + 1);         
            g.fillRect (x - 1, y - 1, 3, 3);
          }
          break;
        case NORMALE :
          int Xp = -1; int Yp = -1;
          for (int X = 50; X < getSize().width; X ++)
          { double x2 = ((double)(X - 50) / (getSize().width - 50) * bsup - l);
            x2 = x2 * x2 / l;
            double y = Math.exp (- x2 / 2.0) * unsr2pi / Math.sqrt (l);
            int Y = getSize().height - 40 - (int)(y * (getSize().height - 80));
            if (Xp != -1) g.drawLine (Xp, Yp, X, Y);
            Xp = X; Yp = Y;
          }
    }
      g1.drawImage (img, 0, 0, this);
  }
}
////////////////////////////////////////////////////////////////////////////////
protected class controles extends Panel implements ActionListener {
  static final long serialVersionUID = 180209L;
  dessin D;
  TextField tn, tl;
  Button ok, normale, poisson;

  private Button ajoutbouton (String s)
  { Button b = new Button (s);
    b.addActionListener (this);
    add (b);
    return b;
  }

  private TextField ajouttf (boolean b, Font f, String s, int i, double d)
  { Label l;
    add (l = new Label (s));
    l.setBackground (Color.lightGray);
    l.setFont (f);
    TextField T;
    if (b) T = new TextField (Integer.toString (i), 4);
    else T = new TextField (Double.toString (d), 6);
    add (T);
    T.setFont (f);
    return T;
  }

  public controles (dessin D)
  { this.D = D;
    setLayout (new FlowLayout());
    setBackground (Color.lightGray);
    Font f = new Font ("Arial", Font.PLAIN, 10);
    tn = ajouttf (true, f, "Nsimul", D.n, 0.0);
    tl = ajouttf (false, f, "lambda", 0, D.l);
    ok = ajoutbouton ("Ok");
    poisson = ajoutbouton ("P");
    normale = ajoutbouton ("N");
  }

  private int maj (TextField tf, int n)
  { try { n = Integer.parseInt (tf.getText ()); }
      catch (NumberFormatException nfe) { }
      if (n < 0) n = 0;
      tf.setText (Integer.toString (n));
      return n;
  }

  public void actionPerformed (ActionEvent e)
  { if (e.getSource () == ok)
    { D.n = maj (tn, D.n);
      if (D.n == 0) D.n = 1;
      double l = D.l;
      try { l = new Double(tl.getText ()).doubleValue(); }
      catch (NumberFormatException nfe) { }
      if (l >= 0.0) D.l = l;
      tl.setText (Double.toString (D.l));
      D.retrace = true;
      D.init ();
    }
    else
    { tn.setText (Integer.toString (D.n));
      tl.setText (Double.toString (D.l));
      if (e.getSource () == poisson) D.loi = (D.loi == dessin.POISSON) ? 0 : dessin.POISSON;
      else if (e.getSource () == normale) D.loi = (D.loi == dessin.NORMALE) ? 0 : dessin.NORMALE;
    }
    D.repaint ();
  }
}

////////////////////////////////////////////////////////////////////////////////

/*
 * permet le fonctionnement en mode commande 20/02/15
 */

    public static void main (String [] args) {
        int w = 400;
        int h = 400;

// Création et lancement de l'applet
        poisson p = new poisson ();
        p.init ();
        p.start ();

// Création de la fenêtre contenant l'applet
        Frame f = new Frame ("Loi de Poisson");
        f.addWindowListener (new fermer ());
        f.add (p);
        f.setSize (w, h);
        f.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);
        }
    }

}
