/** @ (#) estimation_n.java - 01/08/06
 *
 * @author Jean-Paul QUELEN
 * 
 *
 */

import java.awt.* ;
import java.awt.event.* ;
import java.util.* ;

public class estimation_n extends java.applet.Applet {
  static final long serialVersionUID = 220215L;
  TextField tng, tpg, tns, tmin, tmax, tclasses, tseuil;
  TextArea tres;
  int ng = 0, ns, res, min, max, classes, mediane, arrondi, cmin, cmax;
  double pg, moyenne, ecartype, seuil, darrondi;
  Label lg, lpg, lns, lres;
  Button BoutonSimul, ok;
  Random r;
  int [] tabres;
  dessin d;
  boolean bsimul;
  

  private double gparmd (String s)
  { s = getParameter (s) ;
  	double d = 1.0 ;
  	if (s != null)
    { try { d = new Double (s).doubleValue () ; }
      catch (NumberFormatException nfe) { }
    }
    if (d < 0.0) d = 0.0 ;
    else if (d > 1.0) d = 1.0 ;
    return d ;
  }

  private int gparmi (String s)
  { int i = 1 ;
    s = getParameter (s) ;
    if (s != null)
    { try { i = Integer.parseInt (s) ; }
      catch (NumberFormatException nfe) { }
      if (i < 1) i = 1 ;
    }
    return i ;
  }

  public void init() {
    new Font ("Arial", Font.PLAIN, 8);
  	setBackground (Color.lightGray);
    setLayout (new BorderLayout());
    bsimul = true;
	if (ng == 0) {
      ng = gparmi ("ng");
      pg = gparmd ("pg");
      ns = gparmi ("ns");
      if (ns < 2)
        ns = 2;
      seuil = gparmd ("seuil");
      classes = gparmi ("classes");
      arrondi = gparmi ("arrondi");
	}
    darrondi = Math.pow (10, arrondi);
    add (new controles (), BorderLayout.NORTH);
    add (d = new dessin (), BorderLayout.CENTER);
  }

  public String getAppletInfo ()
  { return "estimation_n par J.-P. Quelen" ; }

////////////////////////////////////////////////////////////////////////////////
protected class dessin extends Canvas {
  static final long serialVersionUID = 220215L;
  Image img;
  Graphics g;
  int w, h;
  int [] histo;

  public dessin() { 
  }

  public void update (Graphics g1) {
    paint (g1);
  }

  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, h);
      g1.drawImage (img, 0, 0, this);
    } else {
      g.setColor (Color.white);
      g.fillRect (0, 0, w, h);
      g1.drawImage (img, 0, 0, this);
    if (bsimul) {
      bsimul = false ;

// simulation

      tabres = new int [ns];
   	  r = new Random ();
 	  for (int i = 0; i < ns; i ++) {
        int total = 0;
 		int totalg = 0;
 	  	while (totalg < ng) {
		  total++;
          if (r.nextDouble() <= pg)
            totalg++;
        }
 		tabres [i] = total;
	    tns.setText (Integer.toString (i));
      }
      tns.setText (Integer.toString (ns));
// tri

      int nsm1 = ns - 1;
      qsort (0, ns - 1);

// recherche du maximum et du minimum

      min = tabres [0];
      max = tabres [nsm1];
      cmin = min;
      cmax = max;
      if (cmin == cmax)
        cmax++;
      tmin.setText (Integer.toString (cmin));
      tmax.setText (Integer.toString (cmax));
    }
    if (tabres != null) {
    	histo = new int [classes];
//    for (int i = 0 ; i < histo.length ; i ++) histo [i] = 0 ;

// rangement en classes - moyenne - ecartype

    double dcmaxmmin = cmax - cmin;
    double pas = dcmaxmmin / (double) classes;
    double somme = 0.0;
    double somme2 = 0.0;
    for (int i = 0; i < ns; i ++) {
      double d = cmin + pas;
      double tabresi = tabres [i];
      somme += tabresi;
      somme2 += tabresi * tabresi;
      if (tabresi >= cmin)
        for (int j = 0 ; j < classes ; j ++) {
		  if (tabresi <= d) {
            histo [j] ++;
   		  	break ;
   		}
   	  	d += pas ;
   	  }
    }
    moyenne = somme / ns;
    ecartype = Math.sqrt (somme2 / ns - moyenne * moyenne);
    String s = "effectifs :\n";
    for (int j = 0; j < classes; j ++)
      s += histo [j] + "\t";
    tres.setText (s + "\n");

// recherche max pour cadrage de l'histogramme

    int maxhisto = 0;
    for (int i = 0; i < classes; i ++)
      if (histo [i] > maxhisto)
        maxhisto = histo [i];

// affichage de l'histogramme

    g.setColor (Color.blue);
    int wpas = (int) ((double) w / (double) classes);
    int wi = 0;
    double hsmax = (double) h / (double) maxhisto;
    for (int i = 0; i < classes; i ++) {
	  int jh = h - (int)(hsmax * histo [i]);
      g.drawRect (wi, jh, wpas, h - jh - 1);
      wi += wpas ;
    }
    g.drawLine (0, h - 1, w, h - 1);
    int nss2m1 = ns / 2 - 1;
    double mediane;
    if (ns % 2 == 0)
      mediane = (tabres [nss2m1] + tabres [nss2m1 + 1]) / 2.0; 
    else
      mediane = tabres [nss2m1 + 1];
    g.setColor (Color.red);
    wi = (int)((mediane - cmin) * w / dcmaxmmin);
    g.drawLine (wi, 0, wi, h);    

// seuil

    double nsxs = (double)(ns) * seuil / 2.0; // bilatéral seuil /2 de chaque côté
    int nsxsm1 = (int)(nsxs) - 1;
    int nsmnsxsm1 = ns - nsxsm1 - 2;
    if (nsxsm1 < 0)
      nsxsm1 = 0;
    if (nsmnsxsm1 >= ns)
      nsmnsxsm1 = ns - 1;
    int dvm = tabres [nsxsm1];
    int dvm1 = tabres [nsmnsxsm1];
    int xi = (int) ((double)(dvm - cmin) * w / dcmaxmmin);
    g.setColor (Color.yellow);
    g.drawLine (xi, 0, xi, h);
    xi = (int) ((dvm1 - cmin) * w / dcmaxmmin);
    g.drawLine (xi, 0, xi, h);

    g.setColor (Color.black);
    g.drawString ("moyenne = " + sarrondi (moyenne) + " ; ecart-type = " + sarrondi (ecartype), 10, 10);
    g.drawString ("min = " + min + " ; max = " + max + " ; médiane = " + mediane + " ; seuil = " + seuil + " : [" + dvm + " , " + dvm1 + "]", 10, 25);
    g1.drawImage (img, 0, 0, this);
    }
  }
  }

// tri

  private void qsort (int lo0, int hi0)
  { int lo = lo0;
    int hi = hi0;
    int mid ;
    if ( hi0 > lo0)
    { mid = tabres [(lo0 + hi0) / 2] ;
      while (lo <= hi)
      { while ((lo < hi0) && (tabres [lo] < mid)) ++ lo ;
        while ((hi > lo0) && (tabres [hi] > mid )) -- hi ;
        if( lo <= hi )
        { int id = tabres [lo] ;
          tabres [lo] = tabres [hi] ;
          tabres [hi] = id ;
          ++ lo ;
          -- hi ;
        }
      }
      if (lo0 < hi) qsort (lo0, hi) ;
      if (lo < hi0) qsort (lo, hi0) ;
    }
  }

  private String sarrondi (double d)
  { if (arrondi > 0) d = Math.floor (d * darrondi) / darrondi ;
    return new Double (d) . toString () ;
  }

}
////////////////////////////////////////////////////////////////////////////////
protected class controles extends Panel implements ActionListener {
  static final long serialVersionUID = 220215L;
  GridBagLayout gbl ;
  GridBagConstraints gbc ;
  Font f ;

  private Label ajoutlbl (String s)
  { Label lbl = new Label (s, Label.RIGHT) ;
    lbl.setBackground (Color.lightGray) ;
    lbl.setFont (f) ;
    gbl.setConstraints(lbl, gbc) ;
    return lbl ;
  }

  private TextField ajouttf (int n)
  { TextField tf = new TextField (Integer.toString (n), 10) ;
    tf.setFont (f) ;
    gbl.setConstraints (tf, gbc) ;
    return tf ;
  }

  private TextField ajouttf (double d)
  { TextField tf = new TextField (new Double(d).toString (), 10) ;
    tf.setFont (f) ;
    gbl.setConstraints (tf, gbc) ;
    return tf ;
  }

  private Button ajoutbouton (String s)
  { Button bouton = new Button (s) ;
  	bouton.addActionListener (this) ;
    bouton.setFont (f) ;
    gbl.setConstraints (bouton, gbc) ;
    return bouton ;
  }

	public controles ()
	{ f = new Font ("Arial", Font.PLAIN, 10) ;
		gbl = new GridBagLayout () ;
    gbc = new GridBagConstraints () ;
    setLayout (gbl) ;
    gbc.fill = GridBagConstraints.HORIZONTAL ;
    gbc.weightx = 1.0 ;
    gbc.weighty = 1.0 ;
    add (ajoutlbl ("n = ")) ;
    add (tng = ajouttf (ng)) ;
    add (ajoutlbl ("p = ")) ;
    add (tpg = ajouttf (pg));
    tpg.setFont (f) ;
    gbl.setConstraints(tpg, gbc) ;
    add (ajoutlbl ("nsimul = ")) ;
    add (tns = ajouttf (ns));
    gbc.gridwidth = GridBagConstraints.REMAINDER ;
    add (BoutonSimul = ajoutbouton ("Simule")) ;
    gbc.gridwidth = 1 ;
    add (ajoutlbl ("seuil = ")) ;
    add (tseuil = ajouttf (seuil)) ;
    add (ajoutlbl ("nb classes = ")) ;
    add (tclasses = ajouttf (classes)) ;
    gbc.gridheight = 2 ;
    add (ok = ajoutbouton ("Ok")) ;
    gbc.gridwidth = GridBagConstraints.REMAINDER ;
    add (tres = new TextArea ("", 3, 20)) ;
    gbl.setConstraints (tres, gbc) ;
    gbc.gridx = 0 ;
    gbc.gridwidth = 1 ;
    gbc.gridheight = 1 ;
    add (ajoutlbl ("min = ")) ;
    gbc.gridx = 1 ;
    add (tmin = ajouttf (cmin)) ;
    gbc.gridx = 2 ;
    add (ajoutlbl ("max = ")) ;
    gbc.gridx = 3 ;
    add (tmax = ajouttf (cmax)) ;
    r = new Random ();
  }

  private double s2d (double d, TextField tf)
  { try { d = new Double(tf.getText()).doubleValue () ; }
    catch (NumberFormatException nfe) { }
    tf.setText (new Double(d).toString ()) ;
    return d ;
  }

  private int s2i (int i, TextField tf)
  { try { i = Integer.parseInt (tf.getText ()) ; }
    catch (NumberFormatException nfe) { }
    tf.setText (Integer.toString (i)) ;
    if (i < 1) i = 1 ;
    return i ;
  }

  public void actionPerformed (ActionEvent evt)
  { if (evt.getSource () == BoutonSimul)
 	  { ng = s2i (ng, tng) ;
 		  pg = s2d (pg, tpg) ;
   		ns = s2i (ns, tns) ;
   		if (ns < 2) ns = 2 ;
 	    bsimul = true ;
   	}
 	  else if (evt.getSource () == ok ) bsimul = false ;
   	classes = s2i (classes, tclasses) ;
   	seuil = s2d (seuil, tseuil) ;
   	cmin = s2i (cmin, tmin) ;
   	cmax = s2i (cmax, tmax) ;
    d.repaint() ;
  }
}

////////////////////////////////////////////////////////////////////////////////

/*
 * permet le fonctionnement en mode commande 22/02/15
 * usage : estimation_n.jar
 */

	public static void main (String [] args) {
		int w = 800;
		int h = 800;

// Création et lancement de l'applet
		estimation_n e = new estimation_n();

		e.ng = 100;
		e.pg = 0.25;
		e.ns = 1000;
		e.classes = 10;
		e.seuil = 0.05;
		e.arrondi = 2;

		e.init ();
		e.start ();

// Création de la fenêtre contenant l'applet
		Frame f = new Frame ("Loi binomiale négative") ;
		f.addWindowListener (new fermer ()) ;
		f.add (e) ;
		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 we) {
			System.exit (0) ;
		}
	}


}
