/* *
 *
 * binomiale2.java - jpq - 05/11/05 - 31/10/10 - 01/11/10 - 27/12/10 - 05/12/11 - 12/02/12 - 18/02/12 - 09/05/12 - 13/02/15
 *
 * Calcul des probabilités ; loi binomiale
 * utilise les "BigDecimal"
 * attention le temps de calcul peut devenir long si n est grand
 * modification le 09/02/18
 */

import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.math.*;

public class binomiale2 extends java.applet.Applet implements ActionListener {
    static final long serialVersionUID = 180209L;
    dessin D;
    TextField tn, tp, ta, tmax, tmin, tka, tkb, tpc;
    TextArea tat;
    int n, max, min, ka, kb;
    double p, pc;
    Button ok, cpc, ok1;
    int arrond = 2;
    double darrond;

  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 ()    {
        setFont (new Font ("sans-serif", Font.PLAIN, 10));
        setLayout (new BorderLayout ());

		n = gparmi ("n", 10);
		p = gparmd ("p", 0.5);

    	Panel pnl = new Panel ();
        add (pnl, BorderLayout.NORTH);
        pnl.setBackground (Color.LIGHT_GRAY);

        pnl.add (new Label ("n ="));
        pnl.add (tn = new TextField (4));
        tn.setText (Integer.toString (n));
        pnl.add (new Label ("p ="));
        pnl.add (tp = new TextField (4));
        tp.setText (Double.toString (p));

        pnl.add (new Label ("a ="));
        pnl.add (tka = new TextField (4));
        tka.setText (Integer.toString (ka));
        pnl.add (new Label ("b ="));
        pnl.add (tkb = new TextField (4));
        tkb.setText (Integer.toString (kb));

        pnl.add (new Label ("déc."));
        pnl.add (ta = new TextField (2));
        ta.setText (Integer.toString (arrond));

        pnl.add (ok = new Button ("Ok"));
        ok.addActionListener (this);
        pnl.add (tpc = new TextField ("5", 1));
        pc = 5;
        pnl.add (cpc = new Button ("%"));      // pour test bilatéral au risque de 5%
        cpc.addActionListener (this);

        pnl = new Panel ();
        add (pnl, BorderLayout.SOUTH);
        pnl.setBackground (Color.LIGHT_GRAY);
        pnl.add (tat = new TextArea ("", 3, 50, TextArea.SCROLLBARS_HORIZONTAL_ONLY));
        pnl.add (new Label ("Affichage; min"));
        pnl.add (tmin = new TextField (4));
        tmin.setText (Integer.toString (min));
        pnl.add (new Label ("max"));
        pnl.add (tmax = new TextField (4));
        pnl.add (ok1 = new Button ("Ok"));
        ok1.addActionListener (this);
        tmax.setText (Integer.toString (max));

        add (D = new dessin(), BorderLayout.CENTER);
    }

    private String sarrondi (BigDecimal bd) {
        return sarrondi (bd.doubleValue ());
    }

    private String sarrondi (double d) {
        if (arrond > 0)
            return Double.toString (Math.floor (d * darrond) / darrond);
        else
            return "";
    }

    public String getAppletInfo () {
        return "binomiale3 09/05/12 par J.-P. Quelen";
    }

    public void actionPerformed (ActionEvent e) {
        if ((e.getSource () == ok) || (e.getSource () == ok1) || (e.getSource () == cpc)) {

// Lecture des paramètres n et p; réinitiatisation de a, b, min et max si modification

            boolean change = false;
            int an = n;
            try {
                n = Integer.parseInt (tn.getText ());
            }
            catch (NumberFormatException nfe) {
            }
            if (n <= 0)
                n = an;
            tn.setText (Integer.toString (n));

            double ap = p;
            try {
                p = Double.parseDouble (tp.getText ());
            }
            catch (NumberFormatException nfe) {
            }
            if ((p < 0.0) || (p > 1.0))
                p = ap;
            tp.setText (Double.toString (p));
            change = (n != an) || (p != ap);
            
// lecture ou réinitialisation des paramètres a et b

            if (change) {
                ka = 0;
                kb = n;
            }
            else {
                try {
                    ka = Integer.parseInt (tka.getText ());
                }
                catch (NumberFormatException nfe) {
                }
                try {
                    kb = Integer.parseInt (tkb.getText ());
                }
                catch (NumberFormatException nfe) {
                }
                ka = Math.max (0, Math.min (ka, n));
                kb = Math.max (0, Math.min (kb, n));
                if (ka >= kb) {
                    ka = 0;
                    kb = n;
                }
            }
            tka.setText (Integer.toString (ka));
            tkb.setText (Integer.toString (kb));

// lecture ou réinitialisation des paramètres d'affichage min et max

            if ((change) && (e.getSource () != ok1) || (max == 0)) { // modif 09/05/12
                min = 0;
                max = n;
            }
            else {
                try {
                    min = Integer.parseInt (tmin.getText ());
                }
                catch (NumberFormatException nfe) {
                }
                try {
                    max = Integer.parseInt (tmax.getText ());
                }
                catch (NumberFormatException nfe) {
                }
                min = Math.max (0, Math.min (min, n));
                max = Math.max (0, Math.min (max, n));
                if (min >= max) {
                    min = 0;
                    max = n;
                }
            }
            tmin.setText (Integer.toString (min));
            tmax.setText (Integer.toString (max));


            int aarrond = arrond;
            try {
                aarrond = Integer.parseInt (ta.getText ());
            }
            catch (NumberFormatException nfe) {
            }
            if (aarrond >= 0)
                arrond = aarrond;
            darrond = Math.pow (10.0, arrond);
//            biarrond = BigInteger.TEN . pow (arrond);
            ta.setText (Integer.toString (arrond));

// lecture
            try {
                double pc1 = Double.parseDouble (tpc.getText ());
                if (pc1 >= 0.0 && pc1 <= 100.0)
                    pc = pc1;
                tpc.setText (Double.toString (pc));
            }
            catch (NumberFormatException nfe) {
            }
            D.change = change;
            D.calcul = true;
            D.bcpc = (e.getSource () == cpc);
            D.repaint ();
        }
    }

////////////////////////////////////////////////////////////////////////////////

protected class dessin extends Canvas {
    static final long serialVersionUID = 180209L;
    BigDecimal [] histogramme;
    boolean calcul;                         // = false; envoie le calcul si n, p max, min ou déc ont changés
    boolean change;                         // = true si premier calcul ou si n et p ont changé.
    boolean bcpc;                           // = true si détermination de l'intervalle de fluctuation au niveau 95%
    double dmax;
    int amin, amax, aka, akb;
    int [] x, y;
    BigDecimal deuxcinq;
    BigDecimal neufseptcinq;

// double buffering

    Image img;
    Graphics g;
    int wimg, himg, w, h;

    private void efface () {
        g.setColor (Color.white);
        g.fillRect (0, 0, w, h);
        g.setColor (Color.black);
        g.drawRect (0, 0, w - 1, h - 1);
    }

// affichage de i à l'écran pour faire partienter...

    private void patiente (Graphics g, int i) {
        g.setColor (Color.white);
        g.fillRect (1, 1, 100, 20);
        g.setColor (Color.black);
        g.drawString (Integer.toString (i), 10, 10);
    }


    public void update (Graphics g) {
        paint (g);
    }

    public void paint (Graphics g1) {
        w = getWidth ();
        h = getHeight ();
        if ((img == null) || (w != wimg) || (h != himg)) {
            wimg = w;
            himg = h;
            img = createImage (w, h);
            g = img.getGraphics ();
            efface ();
			calcul = true;
        }
        if (bcpc) {
            calcul = change = true;
            ka = 0;
            kb = n;
        }
        if (calcul) {
            calcul = false;
            efface ();

// intialisation

            if (max == 0) max = n;
            int maxp1 = Math.max (kb, max) + 1;
            int np1 = n + 1;
            if ((histogramme == null) || (maxp1 > histogramme.length)) {
                histogramme = new BigDecimal [maxp1];
                x = new int [maxp1];
                y = new int [maxp1];
            }
            if (max > amax)
                change = true;
            deuxcinq = new BigDecimal (pc / 200.0);
            neufseptcinq = new BigDecimal (1.0 - pc / 200.0);

// calcule les probas et on les met dans histogramme; recherche du maximum
// si p == 0 ou p == 1, pas de calculs
    
            if ((p == 0.0) || (p == 1.0)) {
                for (int i = 0; i <= n; i ++)
                    histogramme [i] = BigDecimal.ZERO;
                if (p == 0.0) {
                    histogramme [0] = BigDecimal.ONE;
                    if (bcpc)
                        ka = kb = 0;
                }
                else {
                    histogramme [n] = BigDecimal.ONE;
                    if (bcpc)
                        ka = kb = n;
                }
                dmax = 1.0;
                tka.setText (Integer.toString (ka));
                tkb.setText (Integer.toString (kb));
            }
            else {

// calcul 
                if (change) {

                    BigDecimal bp = new BigDecimal (tp.getText());
                    BigDecimal bq = BigDecimal.ONE.subtract (bp);
                    BigDecimal bpn = BigDecimal.ONE;
                    BigDecimal bqn = bq.pow (n);
                    BigDecimal iparmin = BigDecimal.ONE;
                    BigDecimal j = new BigDecimal (n);
                    BigDecimal k = BigDecimal.ONE;
                    BigDecimal somme = BigDecimal.ZERO;
                    int kbmax = Math.max (kb, max);
                    boolean bka = false;
                    for (int i = 0; i <= kbmax; i ++) {
                        patiente (g1, i);
                        histogramme [i] = iparmin.multiply(bpn).multiply(bqn);
                        if (bcpc) {
                            somme = somme.add (histogramme [i]);
                            if (bka) {
                                if (somme.compareTo (neufseptcinq) >= 0) {
                                    bcpc = false;
                                    kb = i;
                                    tka.setText (Integer.toString (ka));
                                    tkb.setText (Integer.toString (kb));
                                }
                            }
                            else
                                if (bka = (somme . compareTo (deuxcinq) >= 0))
                                    ka = i;
                        }
                        iparmin = iparmin.multiply(j).divide(k);
                        j = j.subtract (BigDecimal.ONE);
                        k = k.add (BigDecimal.ONE);
                        if (bqn.compareTo (BigDecimal.ONE) < 0) {
                            bpn = bp.multiply (bpn);
                            bqn = bqn.divide (bq);
                        }
                    }
                }
                change = change || (min != amin) || (max != amax) || (ka != aka) || (kb != akb) || bcpc;
                if (change) {
                    dmax = 0.0;
                    for (int i = min; i <= max; i ++) {
                        patiente (g1, i);
                        dmax = Math.max (dmax, histogramme[i].doubleValue());
                    }
                }
            }

            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 (dmax), 5, 40);

// calcul et affichage du diagramme en bâtons

            if (change) {
                int j = 0;
                int maxmmin = max - min;
                for (int i = min; i <= max; i ++) {
                    patiente (g1, i);
                    x [i] = j ++ * (w - 50) / maxmmin + 20;
                    y [i] = h - 40 - (int) (histogramme [i] . doubleValue () * (h - 80) / dmax);
                }
            }
            for (int i = min; i <= max; i ++) {
                patiente (g1, i);
                if ((i >= ka) && (i <= kb))
                    g.setColor (Color.black);
                else
                    g.setColor (Color.red);
                int xi = x [i];
                g.drawLine (xi, y [i], xi, h - 40);
                g.setColor (Color.blue);
                g.drawString (Integer.toString (i), xi, h - 10);
            }

// création de la table valeurs, probabilités, cumuls (fonction de répartition)

            String s1 = "n\t";
            String s2 = "p\t";
            BigDecimal somme1 = BigDecimal.ZERO;
            BigDecimal somme;
            String ssomme = "s\t";
            for (int i = 0; i < min; i ++) {
                patiente (g1, i);
                somme1 = somme1.add (histogramme [i]);
            }
            somme = somme1;
            for (int i = min; i <= max; i ++) {
                patiente (g1, i);
                s1 += Integer.toString (i) + "\t";
                BigDecimal dhi = histogramme [i];
                s2 += sarrondi (dhi) + "\t";
                somme = somme.add(dhi);
                ssomme += sarrondi (somme) + "\t";
            }
            tat.setText (s1 + "\n" + s2 + "\n" + ssomme);
            somme1 = BigDecimal.ZERO;
            for (int i  = 0; i < ka; i ++) {
                patiente (g1, i);
                somme1 = somme1.add (histogramme [i]);
            }
            somme = somme1;
            for (int i = ka; i <= kb; i ++) {
                patiente (g1, i);
                somme = somme.add(histogramme [i]);
            }
            g.drawString ("p ([0, a[) = " + sarrondi (somme1) + "          p ([a, b]) = " + sarrondi (somme.subtract(somme1)) + "          p (]b, n]) = " + sarrondi (BigDecimal.ONE.subtract(somme)), 50, 10);
        }
        g1.drawImage (img, 0, 0, this);
        amin = min;
        amax = max;
        aka = ka;
        akb = kb;
    }
}

////////////////////////////////////////////////////////////////////////////////

/*
 * permet le fonctionnement en mode commande 13/02/15
 */

	public static void main (String [] args) {
		int w = 600;
		int h = 450;

// Création et lancement de l'applet
		binomiale2 b2 = new binomiale2 ();
		b2.n = 0;
		b2.init ();
		b2.start ();

// Création de la fenêtre contenant l'applet
		Frame f = new Frame ("Loi binomiale");
		f.addWindowListener (new fermer ());
		f.add (b2);
		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);
		}
	}

}
