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

class BadOperationException extends Exception
{
	String label;
	BadOperationException() 
	{
		label = "E";
	}
}

// Any class that wants to contain KeyboardButton objects
// should implement this interface. This way KeyboardButton
// objects could be used in more than one project, if the
// class and the interface were made public.

interface KeyboardOwner
{
	public void insertString(String s);
}

class KeyboardButton extends Button
{
	KeyboardOwner owner;
	KeyboardButton(KeyboardOwner ownerArg, String label)
	{
		// Call the parent class constructor
		super(label);
		// Record our owner
		owner = ownerArg;
	}
	public boolean action(Event event, Object arg)
	{
		// We've been clicked upon, so insert the text
		owner.insertString(getLabel());
		// We're completely done processing
		// the action, so return 'true'. Otherwise,
		// the container (the applet) would also
		// have action called, which we don't need.
		return true;
	}
}

public class PrettyCalculator extends Applet implements KeyboardOwner
{
	Button add;
	Button subtract;
	Button multiply;
	Button divide;
	Button equals;
	Button clear;
	Button lastOperation;
	TextField result;
	float current = 0;
	public void init()
	{
		// First, set a nicer font for the
		// applet, to provide larger buttons.
		setFont(new Font("Helvetica", Font.PLAIN, 14));
	
		// Create a GridBagLayout manager and set it
		// as the layout manager for the applet
		GridBagLayout gridbag = new GridBagLayout();
		setLayout(gridbag);
		// We set various members of this object
		// to indicate where and how large each
		// component should be 
		GridBagConstraints c = new GridBagConstraints();
		// For all of our components, we want the cell
		// to be completely filled by the component
		// on both axes, so we need to ask for that by 
		// setting fill.
		c.fill = GridBagConstraints.BOTH;
		// We want to make sure java gives us any extra
		// space in the applet and distributes it evenly
		// among the components on each line.
		// If we don't do this, the calculator will
		// only be given the minimum space to accommodate
		// the buttons.
		c.weightx = 1.0;
		c.weighty = 1.0;
		// The readout should be as wide as the entire calculator,
		// so make sure it takes up all four cells across.
		c.gridwidth = GridBagConstraints.REMAINDER;
		// The readout is in cell 0, 0
		c.gridx = 0;
		c.gridy = 0;
		result = new TextField();
		gridbag.setConstraints(result, c);
		add(result);
		// Go back to one cell across
		c.gridwidth = 1;

		// New row
		c.gridy = 1;
		KeyboardButton b;
		b = new KeyboardButton(this, "7");
		gridbag.setConstraints(b, c);	
		add(b);
		b = new KeyboardButton(this, "8");
		// At position 1,0 in the grid... and so it goes
		c.gridx = 1;
		gridbag.setConstraints(b, c);	
		add(b);
		b = new KeyboardButton(this, "9");
		c.gridx = 2;
		gridbag.setConstraints(b, c);	
		add(b);
		divide = new Button("/");
		c.gridx = 3;
		gridbag.setConstraints(divide, c);	
		add(divide);

		// Next line
		c.gridy = 2;
		b = new KeyboardButton(this, "4");
		c.gridx = 0;
		gridbag.setConstraints(b, c);	
		add(b);
		b = new KeyboardButton(this, "5");
		c.gridx = 1;
		gridbag.setConstraints(b, c);	
		add(b);
		b = new KeyboardButton(this, "6");
		c.gridx = 2;
		gridbag.setConstraints(b, c);	
		add(b);
		multiply = new Button("*");
		c.gridx = 3;
		gridbag.setConstraints(multiply, c);	
		add(multiply);
		b = new KeyboardButton(this, "1");

		// Next line
		c.gridy = 3;
		c.gridx = 0;
		gridbag.setConstraints(b, c);	
		add(b);
		b = new KeyboardButton(this, "2");
		c.gridx = 1;
		gridbag.setConstraints(b, c);	
		add(b);
		b = new KeyboardButton(this, "3");
		c.gridx = 2;
		gridbag.setConstraints(b, c);	
		add(b);
		subtract = new Button("-");
		c.gridx = 3;
		gridbag.setConstraints(subtract, c);	
		add(subtract);

		// New row
		c.gridy = 4;
		c.gridx = 0;
		b = new KeyboardButton(this, "0");
		gridbag.setConstraints(b, c);	
		add(b);
		b = new KeyboardButton(this, ".");
		c.gridx = 1;
		gridbag.setConstraints(b, c);	
		add(b);
		equals = new Button("=");
		c.gridx = 2;
		gridbag.setConstraints(equals, c);	
		add(equals);
		add = new Button("+");
		c.gridx = 3;
		gridbag.setConstraints(add, c);	
		add(add);

		// Last row: one big button
		c.gridy = 5;
		c.gridx = 0;
		// Span the entirety of the calculator horizontally
		c.gridwidth = GridBagConstraints.REMAINDER;
		clear = new Button("Clear");
		gridbag.setConstraints(clear, c);
		add(clear);
		lastOperation = null;
	}
	public boolean action(Event event, Object arg)
	{
		try {
			if ((event.target == add) ||
				(event.target == subtract) ||
				(event.target == multiply) ||
				(event.target == divide))
			{
				completeOperation();
				lastOperation = (Button) event.target;
				result.setText("");
				result.requestFocus();
			} else if (event.target == equals) {
				completeOperation();
				lastOperation = null;
				String text = Float.toString(current);
				result.setText(text);
				result.requestFocus();
			} else if (event.target == clear) {
				current = 0;
				lastOperation = null;
				result.setText("");
				result.requestFocus();
			}
		} catch (BadOperationException e) {
			lastOperation = null;
			result.setText(e.label);
		}		
		return true;
	}
	// Keep our promise to implement the KeyboardOwner interface
	public void insertString(String s)
	{
		// Get the text so far
		String text = result.getText();
		// Append what was inserted
		text += s;
		// And set it back into the control
		result.setText(text);
		// Set the caret to the end by selecting
		// zero characters at the end of the text
		result.select(text.length(), text.length());
		// And give the focus back to the control
		// so the real keyboard can be mixed with
		// the simulated one easily
		result.requestFocus();
	}
	void completeOperation() throws BadOperationException {
		String text = result.getText();
		Float value;
		try {
			value = Float.valueOf(text);
		} catch (java.lang.NumberFormatException ne) {
			BadOperationException oe = new BadOperationException();
			throw oe;
		}
		float f = value.floatValue();
		if (lastOperation == add) {
			current += f;
		} else if (lastOperation == subtract) {
			current -= f;
		} else if (lastOperation == multiply) {
			current *= f;
		} else if (lastOperation == divide) {
			if (f == 0) {
				// Prevent division by zero
				BadOperationException oe = 
					new BadOperationException();
				throw oe;
			} else {
				current /= f;
			}
		} else if (lastOperation == null) {
			current = f;
		}
	}
}

