/* desintegr2arsk.java - jpq - 14/01/09
 * desintégration du potassium en calcium avec une probabilité proba1
 * et en argon avec une probabilité proba2
 * ajout de main() le 05/02/18
 */

import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.util.*;

public class desintegr2arsk extends java.applet.Applet {
  static final long serialVersionUID = 180205L;
  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) {}
	if (d <= 0.0 || d >= 1.0)
	  d = 0.5;
    return d;
  }

  public void init ()
  { setLayout (new BorderLayout ());
  	setFont (new Font ("Arial", Font.PLAIN, 10));
  	double proba1 = gparmd ("proba1", 0.02);
    double proba2 = gparmd ("proba2", 0.002);
    double p12 = proba1 + proba2;
    if (p12 > 1.0)
    { proba2 = 0.0;
    	p12 = proba1;
    }
    D = new dessin (gparmi ("nparticules", 10000), proba1, proba2, p12, gparmi ("max", 50), gparmi ("dt", 0));
    C = new controles (D);
    add (C, BorderLayout.NORTH);
    add (D, BorderLayout.CENTER);
  }

  public void destroy ()
  { remove (D); remove (C); }

  public String getAppletInfo ()
  { return "desintegr2arsk par j.-p. Quelen"; }

////////////////////////////////////////////////////////////////////////////////
protected class dessin extends Canvas implements MouseMotionListener {
  static final long serialVersionUID = 180205L;
  Image img;
  Graphics g;
  int nparticules, max, bsup, w, h, hmax, dt, xret, yret;
  double proba1, proba2, p12;
  double [] histogramme;
  boolean retrace;
  Random rnd;

  public dessin (int nparticules, double proba1, double proba2, double p12, int max, int dt)
  { this.nparticules = nparticules;
    this.proba1 = proba1;
    this.proba2 = proba2;
    this.p12 = p12;
    this.max = max;
    this.dt = dt;
    retrace = false;
    rnd = new Random ();
    addMouseMotionListener (this);
    setCursor (new Cursor (Cursor.CROSSHAIR_CURSOR));
  }

  private void h (Graphics g)
  { bsup = max - 1;
    while (bsup >= 0 && histogramme [bsup] == 0.0)
	  bsup --;
    bsup ++;
    hmax = 0;
    for (int i = 0; i < bsup; i ++) {
	  int hi = (int)(histogramme [i]);
      if (hi > hmax)
	    hmax = hi;
    }
    g.setColor (Color.white);
    g.fillRect (1, 1, w - 2, h - 2);
    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 (Integer.toString (hmax) + "_", 5, 40);
    g.setColor (Color.black);

    for (int j = 0; j < bsup; j ++) {
	  int x = j * (w - 20) / bsup + 20;
      int y = h - 40 - (int)((histogramme [j] * (h - 80)) / hmax);
      g.drawLine (x, y, x, y);
    }
    g.drawRect (0, 0, w - 1, h - 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.white);
      g.fillRect (1, 1, w - 2, h - 2);
      g.setColor (Color.black);
      g.drawRect (0, 0, w - 1, h - 1);
    }
    if (histogramme == null)
	  histogramme = new double [max];
    if (retrace) {
	  retrace = false;
      for (int j = 0; j < histogramme.length; j ++)
	    histogramme [j] = 0.0;
      int temps = 0;
      int nndes = nparticules;
      int n1 = 0;
      int n2 = 0;
      while (nndes > 0) {
	    if (temps + 2 >= histogramme.length) {
		  max += max;
          double [] nh = new double [max];
          System.arraycopy (histogramme, 0, nh, 0, histogramme.length);
          histogramme = nh;
        }
        histogramme [temps ++] = (double)(n2)/(double)(nndes);
//        histogramme [temps ++] = n1;
//        histogramme [temps ++] = n2;
        h (g);
        g1.drawImage (img, 0, 0, this);
        if (dt > 0) {
		  try {
		    Thread.sleep (dt);
		  }
          catch (InterruptedException e) {}
        }
        int nnndes = nndes;
        for (int i = 0; i < nndes; i ++) {
		  double rndnd = rnd.nextDouble ();
          if (rndnd < proba1) {
			nnndes --;
            n1 ++;
          } else if (rndnd < p12) {
			nnndes --;
            n2 ++;
          }
        } 
        nndes = nnndes;
      }
    }
    g.setColor (Color.white);
    g.fillRect (0, 0, w, 25);
    g.setColor (Color.black);
    if (bsup > 0)
      g.drawString ("(" + ((xret - 20) * bsup / (3 * (w - 20))) + ", " + ((yret - h + 40) * hmax / (80 - h)) + ")", 10, 20);
    g.drawRect (0, 0, w - 1, h - 1);
    g1.drawImage (img, 0, 0, this);
  }

  public void mouseDragged (MouseEvent e)
  { e.consume ();
  	xret = e.getX () + 1;
  	yret = e.getY ();
  	repaint ();
  }

  public void mouseMoved (MouseEvent e)
  { e.consume ();
  	xret = e.getX () + 1;
  	yret = e.getY ();
  	repaint ();
  }

}
////////////////////////////////////////////////////////////////////////////////
protected class controles extends Panel implements ActionListener {
  static final long serialVersionUID = 180205L;
  dessin D;
  TextField tparticules, tproba1, tproba2, tdt;
  Button ok;

  private Label ajoutlbl (String s)
  { Label lbl = new Label (s);
    lbl.setBackground (Color.lightGray);
    return lbl;
  }

  private TextField atf (String s, int n)
  { if (s != "")
  	{ Label lbl = new Label (s);
      lbl.setBackground (Color.lightGray);
      add (lbl);
    }
    TextField tf = new TextField (n);
    return tf;
  }

  private TextField ajouttf (String s, int n, int n1)
  { TextField tf = atf (s, n);
    tf.setText (Integer.toString (n1));
    return tf;
  }

  private Button ajoutb (String s)
  { Button b = new Button (s);
    b.addActionListener (this);
    return b;
  }

  public controles (dessin D)
  { this.D = D;
    setBackground (Color.lightGray);
    add (tdt = ajouttf ("dt (en ms) :", 2, D.dt));
    add (tparticules = ajouttf ("Nombre de particules :", 5, D.nparticules));
    add (tproba1 = atf ("Probabilités de désintégration :", 5));
    add (tproba2 = atf ("", 5));
    tproba1.setText (Double.toString (D.proba1));
    tproba2.setText (Double.toString (D.proba2));
    add (ok = ajoutb ("ok"));
  }

  private int pint (TextField tf, int i, boolean b)
  { try { i = Integer.parseInt (tf.getText ()); }
    catch (NumberFormatException nfe) { }
    if (b && (i <= 0)) i = 1;
    tf.setText (Integer.toString (i));
    return i;  
  }

  private double pdbl (TextField tf, double d)
  { double dd = d;
    try { dd = new Double (tf.getText ()) . doubleValue (); }
    catch (NumberFormatException nfe) { }
    if ((dd > 0.0) && (dd < 1.0)) d = dd;
    return d;  
  }

  public void actionPerformed (ActionEvent e)
  { if (e.getSource () == ok)
    { D.dt = pint (tdt, D.dt, false);
      D.nparticules = pint (tparticules, D.nparticules, true);
      double p1 = pdbl (tproba1, D.proba1);
      double p2 = pdbl (tproba2, D.proba2);
      double p12 = p1 + p2;
      if (p12 <= 1.0)
      { D.proba1 = p1;
      	D.proba2 = p2;
      	D.p12 = p12;
      	tproba1.setText (Double.toString (p1));
      	tproba2.setText (Double.toString (p2));
      }
      D.retrace = true;
      D.repaint ();
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

	public static void main (String [] args) {

// Création et lancement de l'applet
		desintegr2arsk d = new desintegr2arsk();
		d.init ();
		d.start ();

// Création de la fenêtre contenant l'applet
		Frame f = new Frame ("desintegrv2arsk");
		f.addWindowListener (new fermer ());
		f.add (d);
		f.setSize (650, 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);
		}
	}

}
