// BranchingSimulation.java

// Written by Julian Devlin, 8/97, for the text book
// "Introduction to Probability," by Charles M. Grinstead & J. Laurie Snell

import java.applet.Applet;
import java.awt.*;

public class BranchingSimulation
	extends java.applet.Applet
{
	MultiLineGraph mlg;				// AWT elements
	
	Float[] xc;
	Float[] yc;
	
	Panel dispArea;
	Panel controls;		// Panel for user controls
	Panel prob;
	
	//Label numl;			// Controls
	//TextField num;
	
	Label[] pl;
	TextField[] p;
	
	Button go;
	
	GridBagLayout gbl, gblp;
	GridBagConstraints cc, ccp;
	
	float[] density;
	float mean, std;
	GeneralSimulation gs;
		
	// Initialize applet
	public void init()
	{	
		//numl = new Label("Maximum generations = ");			// Create controls
		//num = new TextField("10", 4);
		go = new Button("Go");
		
		pl = new Label[10];
		p = new TextField[10];
		for (int i = 0; i < 10; i++) {
			pl[i] = new Label("P(" + i + ") =");
			p[i] = new TextField("0", 4);	
		}
		p[0].setText(".2767");
		p[1].setText(".3289");
		p[2].setText(".1949");
		p[3].setText(".0862");
		p[4].setText(".0509");
		p[5].setText(".0329");
		p[6].setText(".0183");
		p[7].setText(".0080");
		p[8].setText(".0026");
		p[9].setText(".0006");
		
		mlg = new MultiLineGraph();
		
		dispArea = new Panel();				// Set up window
		controls = new Panel();
		prob = new Panel();
		setLayout(new BorderLayout(5, 5));
		
		add("South", controls);
		add("West", prob);
		add("Center", dispArea);
		
		dispArea.setLayout(new GridLayout(1, 1));
		dispArea.add(mlg);
		
		gblp = new GridBagLayout();
		ccp = new GridBagConstraints();
		prob.setLayout(gblp);
		for (int i = 0; i < 10; i++) {
			ccp.gridx = 0;
			ccp.gridy = i;
			gblp.setConstraints(pl[i], ccp);
			prob.add(pl[i]);
			ccp.gridx = 1;
			gblp.setConstraints(p[i], ccp);
			prob.add(p[i]);	
		}
		
		gbl = new GridBagLayout();
		controls.setLayout(gbl);
		
		cc = new GridBagConstraints();
		
		/*cc.gridx = 0;
		cc.gridy = 0;
		gbl.setConstraints(numl, cc);
		controls.add(numl);
		
		cc.gridx = 1;
		gbl.setConstraints(num, cc);
		controls.add(num);
		*/
		//cc.gridx = 0;
		//cc.gridy = 1;
		//cc.gridwidth = 2;
		gbl.setConstraints(go, cc);
		controls.add(go);
		
		validate();
	}
	
	// Handle events
	public boolean handleEvent(Event evt)
	{
		String minStr, maxStr;
		if (evt.target instanceof Button)
		{
			if (evt.target == go && evt.id == Event.ACTION_EVENT)	// When button is clicked
			{
        		simulate();
        		return true;					// Generate correct number of tosses
			}
		}
		return super.handleEvent(evt);	// Handle other events as usual
	}
	
	public float genFunctionDiscrete(float[] prob, float x) {
		float sum = 0;
		for (int i = 0; i < prob.length; i++) {
			sum += prob[i] * (float) Math.pow((double) x, (double) i);

		}
		return sum;
	}
	
	public float expectationDiscrete(float[] prob) {
		float sum = 0;
		for (int i = 0; i < prob.length; i++) {
			sum += i * prob[i];	
		}
		return sum;
	}
	
	public float varianceDiscrete(float[] prob) {
		 float sum = -1 * expectationDiscrete(prob);
		 for (int i = 0; i < prob.length; i++) {
		 	sum += (float) Math.pow((double) i, 2) * prob[i];	
		 }	
		 return sum;
	}
	
	public float sampleNormal(float mean, float std) {
		return std * (float) Math.pow(-2 * Math.log(Math.random()), .5) * 
			(float) Math.cos(2 * Math.PI * Math.random()) + mean;	
	}
	
	// Calculate probabilities
    public void simulate()
    {	
    	float[] prob = new float[10];
		float probability = 0;
		float sum = 0;
		int generation;
		float genSize;
		int changePoint = 500;
		int offspring;
		float genMean;
		float genStd;
		
		xc = new Float[260];
		yc = new Float[260];
		
		for (int i = 0; i < 10; i++) {
			prob[i] = Float.valueOf(p[i].getText()).floatValue();	
			sum += prob[i];
		}
		for (int i = 0; i < 10; i++) {
			prob[i] = round(prob[i] / sum, .001f);
			p[i].setText(String.valueOf(prob[i]));
		}
		
		float mean = expectationDiscrete(prob);
		float variance = varianceDiscrete(prob);
		gs = new GeneralSimulation(prob);
		
		for (int exp = 0; exp < 10; exp++) {
			generation = 0;
			genSize = 1;
			for (int g = 0; g < 25; g++) {
				xc[(exp * 26) + g] = new Float(g);
				yc[(exp * 26) + g] = new Float(genSize / (float) Math.pow((double)
					mean, (double) g));
				if (genSize < changePoint) {
					offspring = 0;
					for (int parent = 0; parent < genSize; parent++) {
						offspring += gs.nextRand();	
					}
					genSize = offspring;
				}
				else {
					genMean = genSize * mean;
					genStd = (float) Math.pow((double) genSize, .5);
					genSize = sampleNormal(genMean, genStd);
				}
			}
			xc[(exp * 26) + 25] = new Float(25);
			yc[(exp * 26) + 25] = new Float(genSize / (float) Math.pow((double)
				mean, (double) 25));
		}
		
		dispArea.remove(mlg);
		mlg = new MultiLineGraph(xc, yc, 26);	// Create new LineSpikeGraph
		dispArea.add(mlg);
		
		validate();
	}
	
	public float round(float num, float accuracy) {
		return accuracy * Math.round(num / accuracy);
	}
	
}




