// CLTIndTrials.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 CLTIndTrials
	extends java.applet.Applet
{
	Float[] xSpikes;		// Variables for simulation
	Float[] ySpikes;
	Float[] xLines;
	Float[] yLines;
	
	LineSpikeGraph lsg;				// AWT elements
	
	Panel dispArea;
	Panel controls;		// Panel for user controls
	Panel prob;
	
	Label numl1, numl2, numl3, numl4, numl5, numl6, numl7;			// Controls
	TextField num1, num2, num3;
	
	Label[] pl;
	TextField[] p;
	
	Button go;
	
	GridBagLayout gbl, gblp;
	GridBagConstraints cc, ccp;
	
	float[] density;
	float mean, std;
		
	// Initialize applet
	public void init()
	{	
		numl1 = new Label("n =");			// Create controls
		num1 = new TextField("5", 4);
		numl2 = new Label("kmin =");			// Create controls
		num2 = new TextField("", 4);
		numl3 = new Label("kmax =");			// Create controls
		num3 = new TextField("", 4);
		numl4 = new Label("exact =");
		numl5 = new Label("                  ");
		numl6 = new Label("approx =");
		numl7 = new Label("                  ");
		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[1].setText(".2");
		p[2].setText(".2");
		p[3].setText(".2");
		p[4].setText(".2");
		p[5].setText(".2");
		
		lsg = new LineSpikeGraph(); // initialize a graphing space
		
		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(lsg);
		
		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 = 1;
		cc.gridy = 0;
		gbl.setConstraints(numl1, cc);
		controls.add(numl1);
		
		cc.gridx = 2;
		gbl.setConstraints(num1, cc);
		controls.add(num1);
		
		cc.gridx = 0;
		cc.gridy = 1;
		gbl.setConstraints(numl2, cc);
		controls.add(numl2);
		
		cc.gridx = 1;
		gbl.setConstraints(num2, cc);
		controls.add(num2);
		
		cc.gridx = 2;
		gbl.setConstraints(numl3, cc);
		controls.add(numl3);
		
		cc.gridx = 3;
		gbl.setConstraints(num3, cc);
		controls.add(num3);
		
		cc.gridx = 0;
		cc.gridy = 2;
		gbl.setConstraints(numl4, cc);
		controls.add(numl4);
		
		cc.gridx = 1;
		gbl.setConstraints(numl5, cc);
		controls.add(numl5);
		
		cc.gridx = 2;
		gbl.setConstraints(numl6, cc);
		controls.add(numl6);
		
		cc.gridx = 3;
		gbl.setConstraints(numl7, cc);
		controls.add(numl7);
		
		cc.gridx = 0;
		cc.gridy = 3;
		cc.gridwidth = 4;
		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
			{
				minStr = num2.getText().trim();
				maxStr = num3.getText().trim();
				if (minStr.length() != 0 && maxStr.length() != 0)
					simulate(Integer.valueOf(num1.getText()).intValue(),
        				Integer.valueOf(minStr).intValue(),
        				Integer.valueOf(maxStr).intValue());
        		else if (minStr.length() != 0)
        			simulate(Integer.valueOf(num1.getText()).intValue(),
        				Integer.valueOf(minStr).intValue(),
        				Integer.valueOf(maxStr).intValue());
        		else
        			simulate(Integer.valueOf(num1.getText()).intValue());
        		return true;					// Generate correct number of tosses
			}
		}
		return super.handleEvent(evt);	// Handle other events as usual
	}
	
	public float normal(float x, float mu, float sigma) {
		return 1 / (sigma * (float)  Math.pow(2 * Math.PI, .5)) * 
			(float) Math.pow(Math.E, -1 * Math.pow(x - mu, 2) / (2 * 
				Math.pow((double) sigma, 2)));	
	}
	
	public float normalArea(float a, float b) {
		float mu = 0f;
		float sigma = 1f;
		int subdivisions = (int) Math.max(100, 20 * (double) Math.round(
			(double) b - (double) a + .5));
		float dx = (b - a) / (float) subdivisions;
		float sum = normal(a, mu, sigma) + normal(b, mu, sigma);
		float x;
		for (int k = 1; k < subdivisions; k++) {
			x = a + (float) k * dx;
			if (k % 2 == 1)
				sum += 4 * normal(x, mu, sigma);
			else
				sum += 2 * normal(x, mu, sigma);
		}
		return dx / 3 * sum;
	}
	
	public float[] convolve(float[] d1, float[] d2) {
		float[] results = new float[d1.length + d2.length - 1];
		for (int i = 0; i < results.length; i++) {
			results[i] = 0;	
		}
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d2.length; j++) {
				results[i + j] += d1[i] * d2[j];	
			}	
		}	
		return results;
	}
	
	public float[] getSnDensity(int n, float[] prob) {
		float[] density = prob;
		for (int c = 2; c <= n; c++) {
			density = convolve(density, prob);	
		}
		return density;
	}
	
	public void setPoints(int num) 
	{
		float temp;
		
		float[] prob = new float[10];
		float sum = 0;
		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] /= sum;
			p[i].setText(String.valueOf(prob[i]));
		}
		density = getSnDensity(num, prob);
		
		mean = 0;
		float variance = 0;
		for (int k = 0; k < density.length; k++) {
			mean += k * density[k];
			variance += (int) Math.pow((double) k, 2) * density[k];
		}
		variance -= (float) Math.pow((double) mean, 2);
		std = (float) Math.pow((double) variance, .5);
		if (std == 0)
			std = 1 / (num * 9);		//??????????????
	
    	float xmin = -4f;
    	float xmax = 4f;
    	float dx = (xmax - xmin) / 100f;
    	
    	// +-1
    	int kmin = (int) Math.floor(Math.max(0, (double) (mean - 4 
    		* std))) + 1;
    	int kmax = (int) Math.ceil(Math.min((double) num * 9, 
    		(double) (mean + 4 * std))) - 1;
    	xLines = new Float[101];
    	yLines = new Float[101];
    	xSpikes = new Float[kmax - kmin + 1];
    	ySpikes = new Float[kmax - kmin + 1];
    		
    	for (int k = kmin; k <= kmax; k++) {
    		xSpikes[k - kmin] = new Float((k - mean) / std);
    		temp = (float) density[k] * std;
    		ySpikes[k - kmin] = new Float(temp);
	    }
	    
	    for (int i = 0; i < 101; i++) {
	    	xLines[i] = new Float(xmin + i * dx);
	    	yLines[i] = new Float(normal(xmin + i * dx, 0f, 1f));
	    }
	}
	
	// Calculate probabilities
    public void simulate(int num)
    {	
    	setPoints(num);
	    
		dispArea.remove(lsg);
		lsg = new LineSpikeGraph(xLines, yLines, xSpikes, ySpikes);	// Create new LineSpikeGraph
		dispArea.add(lsg);							// Put up the graph
		validate();
	}
	
	// Calculate probabilities
    public void simulate(int num, int min, int max)
    {
    	setPoints(num);
	    
		dispArea.remove(lsg);
		lsg = new LineSpikeGraph(xLines, yLines, xSpikes, ySpikes,
			((float) min - mean) / std, ((float) max - mean) / std);	// Create new LineSpikeGraph
		dispArea.add(lsg);							// Put up the graph
		
		
		if (min == max) {
			numl5.setText(String.valueOf(density[min]));
			numl7.setText(String.valueOf(normal((min - mean) / std, 0f, 1f)
				/ std));
		}
		else {
			float sum = 0;
			for (int k = min; k <= max; k++) {
				sum += density[k];
			}
			int flag = 1;
			numl5.setText(String.valueOf(sum));
			numl7.setText(String.valueOf(normalArea((min - mean) / std
				- .5f / std * flag, (max - mean) / std 
				+ .5f / std * flag)));
		}
		
		
		validate();
   	}
}




