// ConvolutionDemo.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 ConvolutionDemo
	extends java.applet.Applet
{
	SpikeGraph sg;				// AWT elements
	
	Float[] xc;
	Float[] yc;
	
	Panel dispArea;
	Panel controls;		// Panel for user controls
	Panel prob;
	
	Label[] pl;
	Label numl1, numl2;
	TextField num1, num2;
	TextField[] p1;
	TextField[] p2;
	
	Button go;
	
	GridBagLayout gbl, gblp;
	GridBagConstraints cc, ccp;
		
	// Initialize applet
	public void init()
	{	
		go = new Button("Go");
		
		pl = new Label[10];
		p1 = new TextField[10];
		p2 = new TextField[10];
		for (int i = 0; i < 10; i++) {
			pl[i] = new Label("P(" + i + ") =");
			p1[i] = new TextField("0", 4);	
			p2[i] = new TextField("0", 4);
		}
		
		numl1 = new Label("No.");
		numl2 = new Label("No.");
		num1 = new TextField("0", 4);
		num2 = new TextField("O", 4);
		
		sg = new SpikeGraph();
		
		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(sg);
		
		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(p1[i], ccp);
			prob.add(p1[i]);	
			ccp.gridx = 2;
			gblp.setConstraints(p2[i], ccp);
			prob.add(p2[i]);	
		}
		
		ccp.gridx = 1;
		ccp.gridy = 10;
		gblp.setConstraints(numl1, ccp);
		prob.add(numl1);
		ccp.gridy = 11;
		gblp.setConstraints(num1, ccp);
		prob.add(num1);
		
		ccp.gridx = 2;
		ccp.gridy = 10;
		gblp.setConstraints(numl2, ccp);
		prob.add(numl2);
		ccp.gridy = 11;
		gblp.setConstraints(num2, ccp);
		prob.add(num2);
		
		gbl = new GridBagLayout();
		controls.setLayout(gbl);
		
		cc = new GridBagConstraints();
		
		gbl.setConstraints(go, cc);
		controls.add(go);
		
		validate();
	}
	
	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;
	}
	
	// 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(Integer.valueOf(num1.getText()).intValue(),
        			Integer.valueOf(num2.getText()).intValue());
        		return true;					// Generate correct number of tosses
			}
		}
		return super.handleEvent(evt);	// Handle other events as usual
	}
	
	// Calculate probabilities
    public void simulate(int num1, int num2)
    {	
    	xc = new Float[9 * (num1 + num2) + 1];
    	yc = new Float[9 * (num1 + num2) + 1];
    	float[] temp1 = new float[10];
    	float[] temp2 = new float[10];
    	float[] probs;
    	float sum1 = 0, sum2 = 0;
    	
    	for (int i = 0; i < 10; i++) {
    		temp1[i] = Float.valueOf(p1[i].getText()).floatValue();
    		temp2[i] = Float.valueOf(p2[i].getText()).floatValue();
    		sum1 += temp1[i];
    		sum2 += temp2[i];
		}
		for (int i = 0; i < 10; i++) {
			temp1[i] = round(temp1[i] / sum1, .001f);
			p1[i].setText(String.valueOf(temp1[i]));
			temp2[i] = round(temp2[i] / sum2, .001f);
			p2[i].setText(String.valueOf(temp2[i]));
		}
    	
    	probs = new float[1];
    	probs[0] = 1;
    	
    	for (int i = 0; i < num1; i++) {
    		probs = convolve(temp1, probs);
    	}
    	
    	for (int i = 0; i < num2; i++) {
    		probs = convolve(temp2, probs);
    	}
    		
    	
    	for (int i = 0; i < xc.length; i++) {
    		xc[i] = new Float(i);
    		yc[i] = new Float(probs[i]);
    	}
    	
		dispArea.remove(sg);
		sg = new SpikeGraph(xc, yc);	// Create new SpikeGraph
		dispArea.add(sg);							// Put up the graph
		
		validate();
	}
	
	public float round(float num, float accuracy) {
		return accuracy * Math.round(num / accuracy);
	}
	
}




