// TwoArm.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 TwoArm extends java.applet.Applet implements Runnable
{
	Float[] xc1;
	Float[] yc1;
	Float[] xc2;
	Float[] yc2;
	
	int[] win, lose;
	float[] p;
	float[] expected;
	
	TextArea ta;
	DoubleLineGraph dlg;
	Label numl1, numl2;
	TextField num1, num2;
	Choice c;
	Button go;
		
	Panel graphArea;
	Panel controls;
	
	GridBagLayout gbl;
	GridBagConstraints cc;
	
	JRandom myRand;
	
	Thread runner;
	boolean isrunning;

	// Set up all controls and put them in the window
	public void init() {
		numl1 = new Label("p(m1) =");	// Create controls
		num1 = new TextField(".4", 4);
		numl2 = new Label("p(m2) =");	// Create controls
		num2 = new TextField(".6", 4);
		c = new Choice();
		c.addItem("Play best");
		c.addItem("Play winner");
		go = new Button("Simulate");
		
		graphArea = new Panel();				// Set up window
		controls = new Panel();
		setLayout(new BorderLayout(5, 5));
	
		gbl = new GridBagLayout();
		controls.setLayout(gbl);
		
		cc = new GridBagConstraints();
		
		cc.gridx = 0;
		cc.gridy = 0;
		gbl.setConstraints(numl1, cc);
		controls.add(numl1);
		
		cc.gridx = 1;
		gbl.setConstraints(num1, cc);
		controls.add(num1);
		
		cc.gridx = 2;
		gbl.setConstraints(numl2, cc);
		controls.add(numl2);
		
		cc.gridx = 3;
		gbl.setConstraints(num2, cc);
		controls.add(num2);
		
		cc.gridy = 1;
		cc.gridx = 0;
		cc.gridwidth = 4;
		gbl.setConstraints(c, cc);
		controls.add(c);
		
		cc.gridy = 2;
		cc.gridx = 0;
		cc.gridwidth = 4;
		gbl.setConstraints(go, cc);
		controls.add(go);
		
		ta = new TextArea(15, 20);
		dlg = new DoubleLineGraph();
		add("Center", graphArea);
		graphArea.setLayout(new GridLayout(1, 2));
		graphArea.add(ta);
		graphArea.add(dlg);
		add("South", controls);
		
		myRand = new JRandom();
	}
	
	// Beta density
	public float beta(int a, int b, float x) {
		return (float) (Math.pow((double) x, (double) (a - 1)) 
			* Math.pow((double) (1 - x), (double) (b - 1)) / beta(a, b));
	}
	
	public float beta(int a, int b) {
		return 1f / (Combinatorics.choose(a + b - 1, a - 1) * b);
	}
	
	// Start running a thread
	public void start() {
		if (runner == null) {
			runner = new Thread(this);
			runner.start();
			isrunning = true;
		}
	}
	
	// Stop the thread
	public void stop() {
		if (runner != null) {
			runner.stop();
			runner = null;
			isrunning = false;
		}
	}
	
	// Do things
	public void run() {
		while (true) {
			float p1 = Float.valueOf(num1.getText()).floatValue();
	        float p2 = Float.valueOf(num2.getText()).floatValue();
	        int state = c.getSelectedIndex();
		
			long time;
			
			int machine = 0;
			win = new int[2];
			win[0] = 0;
			win[1] = 0;
			lose = new int[2];
			lose[0] = 0;
			lose[1] = 0;
			p = new float[2];
			p[0] = p1;
			p[1] = p2;
			expected = new float[2];
			
			ta.appendText("Machine          Result\n\n");
			if (state == 0) {									// Play best machine
				for (int i = 0; i < 10; i++) {
					ta.appendText("   " + String.valueOf(machine + 1) + "                    ");
					if (myRand.nextFloat(0, 1) < p[machine]) {
						win[machine]++;
						ta.appendText("W\n");
					}
					else {
						lose[machine]++;
						ta.appendText("L\n");
					}
					expected[0] = (float) (win[0] + 1) / (float) (win[0] + lose[0] + 2);
					expected[1] = (float) (win[1] + 1) / (float) (win[1] + lose[1] + 2);
					if (expected[0] >= expected[1])
						machine = 0;
					else
						machine = 1;
					setArrays();
					graphArea.remove(dlg);
					dlg = new DoubleLineGraph(xc1, yc1, xc2, yc2);	// Create new Double...
					graphArea.add(dlg);							
					validate();
					graphArea.repaint();
					validate();
					
					time = System.currentTimeMillis();
					while (System.currentTimeMillis() < time + 3000) {
						// wait 3 seconds
					}
					
				}
			}
			else {
				for (int i = 0; i < 10; i++) {				// Play the winner
					ta.appendText("   " + String.valueOf(machine + 1) + "                    ");
					if (myRand.nextFloat(0, 1) < p[machine]) {
						win[machine]++;
						ta.appendText("W\n");
					}
					else {
						lose[machine]++;
						ta.appendText("L\n");
						machine = 1 - machine;
					}
					setArrays();
					graphArea.remove(dlg);
					dlg = new DoubleLineGraph(xc1, yc1, xc2, yc2);	// Create new Double...
					graphArea.add(dlg);							
					validate();
					graphArea.repaint();
					validate();
					
					time = System.currentTimeMillis();
					while (System.currentTimeMillis() < time + 3000) {
						// 3 second delay
					}
					
				}
			}
			isrunning = false;
			runner.suspend();
		}
	}					
	
	public void setArrays() {
		xc1 = new Float[26];
		yc1 = new Float[26];
		xc2 = new Float[26];
		yc2 = new Float[26];
		
		for (int i = 0; i < 26; i++) {
			xc1[i] = new Float((float) i * .04f);
			xc2[i] = new Float((float) i * .04f);
			yc1[i] = new Float(beta(win[0] + 1, lose[0] + 1, (float) i * .04f));
			yc2[i] = new Float(beta(win[1] + 1, lose[1] + 1, (float) i * .04f));
		}
	}
	
	
	// Handle events
	public boolean handleEvent(Event evt)
	{
		if (evt.target instanceof Button)
		{
			if (evt.target == go && evt.id == Event.ACTION_EVENT)	// When button is clicked
			{
				ta.setText("");			// Reset output window
				runner.resume();
				isrunning = true;
        		return true;					// Generate correct number of tosses
			}
		}
		return super.handleEvent(evt);	// Handle other events as usual
	}
}