import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

// Notice how we are implementing ActionListener.

public class Baseball2
	extends JApplet
	implements ActionListener
{

	// Use a Vector as a database of players
	private Hashtable database = new Vector();

	// GUI components to represent our data.
	private JLabel message = new JLabel("", JLabel.CENTER);
	private JTextField first = new JTextField();
	private JTextField last = new JTextField();
	private JTextField hits = new JTextField();
	private JTextField atBats = new JTextField();
	private JTextField average = new JTextField();

	// Define some action commands for the buttons.
	// This will make more sense later.
	// We could just use the raw Strings, but this is a little
	// safer.  It prevents typo-style mistakes!
	private static String CLEAR = "clear";
	private static String SAVE = "save";
	private static String SEARCH = "search";
	private static String HITS = "hits";
	private static String ATBATS = "atbats";

	public void init()
	{
		Container pane = getContentPane();
		pane.setLayout(new GridBagLayout());

		// Add top message which spans the entire applet.
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.weightx = 1;
		gbc.gridwidth = GridBagConstraints.REMAINDER;
		gbc.fill = GridBagConstraints.HORIZONTAL;
		pane.add(message, gbc);

		// Add labels and textfields.
		GridBagConstraints gbc1 = new GridBagConstraints();
		gbc1.fill = GridBagConstraints.HORIZONTAL;
		GridBagConstraints gbc2 = new GridBagConstraints();
		gbc2.gridwidth = GridBagConstraints.REMAINDER;
		gbc2.weightx = 10;
		gbc2.fill = GridBagConstraints.HORIZONTAL;
		pane.add(new JLabel("First:", JLabel.RIGHT), gbc1);
		pane.add(first, gbc2);
		pane.add(new JLabel("Last:", JLabel.RIGHT), gbc1);
		pane.add(last, gbc2);
		pane.add(new JLabel("Hits:", JLabel.RIGHT), gbc1);
		pane.add(hits, gbc2);
		pane.add(new JLabel("At Bats:", JLabel.RIGHT), gbc1);
		pane.add(atBats, gbc2);
		pane.add(new JLabel("Average:", JLabel.RIGHT), gbc1);
		pane.add(average, gbc2);

		// add blank label for filler.
		pane.add(new JLabel("", JLabel.RIGHT), gbc1);
		// add Buttons for control.
		JPanel p = new JPanel(new GridBagLayout());
		GridBagConstraints gbc4 = new GridBagConstraints();
		gbc4.weightx = 1;
		JButton clear = new JButton("Clear");
		JButton save = new JButton("Save");
		JButton search = new JButton("Search");
		p.add(clear, gbc4);
		p.add(save, gbc4);
		p.add(search, gbc4);
		pane.add(p, gbc2);

		// Set Button controls.

		// Define "action command" for each button.
		// This is just a String which gets passed to
		// the actionListener inside the ActionEvent.  See below.
		clear.setActionCommand(CLEAR);
		save.setActionCommand(SAVE);
		search.setActionCommand(SEARCH);
		hits.setActionCommand(HITS);
		atBats.setActionCommand(ATBATS);

		// Instead of creating the anonymous classes (which we
		// could still do), this time we "implement" the
		// ActionListener ourselves in this class.  So, we can
		// add "this" as our ActionListener.  "this" means
		// "this object".
		clear.addActionListener(this);
		save.addActionListener(this);
		search.addActionListener(this);
		hits.addActionListener(this);
		atBats.addActionListener(this);

		// Set average to be read-only.  i.e. the use
		// can't type in it.  We (the programmer) can still
		// set its value.
		average.setEditable(false);

		// Start clean
		clearFields();
	}

	// Since we are implementing the ActionListener ourselves, we
	// need to define the actionPerformed method in this class.
	// Note that the signature of this method is exactly the same
	// as the anonymous class we have been creating in the past.
	//
	public void actionPerformed(ActionEvent ae)
	{
		// The command variable should be set to the
		// correct command, depending on which button
		// was pressed.  All three buttons will cause
		// this method to be called, but the difference
		// will be the value of "command".  We can now
		// test this variable and take the appropriate
		// action.
		String command = ae.getActionCommand();

		// Just in case.  Shouldn't happen.
		if (command == null)
			return;

		// Test for the CLEAR command.  Now do you understand
		// why it's safer to use the CLEAR variable instead
		// of "clear"?
		if (command.equals(CLEAR))
		{
			// Let's clear all of the TextFields
			clearFields();
			return;
		}

		// Test for the SAVE command.
		if (command.equals(SAVE))
		{
			// Let's save this value to the Hashtable.
			saveAverage();
			return;
		}

		// Test for the SEARCH command.
		if (command.equals(SEARCH))
		{
			// Let's search for this value in the Hashtable.
			searchForName();
			return;
		}

		// Test for the HITS or ATBATS commands.
		if (command.equals(HITS) || command.equals(ATBATS))
		{
			// Update the batting average value.
			updateAverage(calculateAverage());
			return;
		}

	}

	private void clearFields()
	{
		// Let's clear all of the TextFields
		first.setText("");
		last.setText("");
		hits.setText("");
		atBats.setText("");
		average.setText("");
		message.setText("Welcome");
	}

	private void saveAverage()
	{
		// Create a new Name object from the GUI values.
		Name name = new Name(first.getText(), last.getText());
		// Create a new BattingAverage object from 
		// the hits and atBats values.
		BattingAverage ba = calculateAverage();
		// Now save this value in the "database."
		Player player = new Player(name, ba);
		// Remove the "old" version, if any.
// KLC HERE
		database.put(name, ba);

		// Update the message to indicate the save.
		message.setText("Saved " + name);
	}

	private Player searchForName()
	{
		// Create a new Name object from the GUI values.
		Name name = new Name(first.getText(), last.getText());
		// Search for name in database
		BattingAverage ba = (BattingAverage) database.get(name);
		// See if we found anything.
		if (ba == null)
		{
			// Nope.  Show an error message and stop.
			message.setText(name + ": not found");
		}
		else
		{
			// Found a match!  Need to display.
			message.setText("Found: " + name);
			updateAverage(ba);
		}
	}

	/**
	 * Given a BattingAverage object, update the display values
	 *
	 * @param ba the BattingAverage object to display.
	 */
	public void updateAverage(BattingAverage ba)
	{
		if (ba == null)
			return;
		hits.setText("" + ba.getHits());
		atBats.setText("" + ba.getAtBats());
		average.setText("" + ba.getBattingAverage());
		// Note: the setText("" + (int)) is just a quick
		// way of converting a number to a String.
		// There are more "official" ways, but this
		// way is nice and easy. :-)
	}

	/**
	 * Get the hits and atBats value from the GUI and calculate
	 * the batting average.
	 *
	 * @return a BattingAverage object with the value.
	 */
	private BattingAverage calculateAverage()
	{
		// Get values from GUI
		int hitsValue = Integer.parseInt(hits.getText());
		int atBatsValue = Integer.parseInt(atBats.getText());
		return new BattingAverage(hitsValue, atBatsValue);
	}


}
