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

public class TestStack
	extends JApplet
	implements ActionListener
{

	private MyStack stack = new MyStack();
	private MyQueue queue = new MyQueue();

	// GUI components to represent our data.
	private JList stackList = new JList();
	private JList queueList = new JList();
	private JTextField newItem = new JTextField();
	private JTextField retrievedStackItem = new JTextField();
	private JTextField retrievedQueueItem = new JTextField();
	private JLabel message = new JLabel("", JLabel.CENTER);

	// Action command strings.
	private static String ADD = "add";
	private static String REMOVE = "remove";

	public void init()
	{
		Container pane = getContentPane();
		pane.setLayout(new GridBagLayout());
		
		// Create GUI components.
		JButton addButton = new JButton("Add/Push");
		JButton removeButton = new JButton("Remove/Pop");
		ImageIcon arrow = new ImageIcon(getImage(getCodeBase(), "downarrow.gif"));

		// Set constraints so that these components span the entire applet.
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.weightx = 1;
		gbc.weighty = 2;
		gbc.gridwidth = GridBagConstraints.REMAINDER;
		gbc.fill = GridBagConstraints.BOTH;
		pane.add(message, gbc);
		gbc.weighty = 1;
		gbc.fill = GridBagConstraints.VERTICAL;
		pane.add(addButton, gbc);
		gbc.fill = GridBagConstraints.BOTH;
		pane.add(newItem, gbc);
		
		// Here is something new and fun: Borders.  Read the BorderFactory API for more info!
		// Borders are graphics that decorate whatever component you assign the Border.
		// The TitledBorder is great for labeling things.
		newItem.setBorder(BorderFactory.createTitledBorder("New Item"));
		
		// Now add two columns
		// First, two arrows
		gbc.weighty = 0;
		gbc.gridwidth = GridBagConstraints.RELATIVE;
		pane.add(new JLabel(arrow), gbc);
		gbc.gridwidth = GridBagConstraints.REMAINDER;
		pane.add(new JLabel(arrow), gbc);

		// Now two scrollable Lists.
		// The JLists don't scroll themselves, so we need to use a JScrollPane object.
		gbc.weighty = 10;
		gbc.gridwidth = GridBagConstraints.RELATIVE;
		JScrollPane sp1, sp2;
		pane.add(sp1 = new JScrollPane(queueList), gbc);
		gbc.gridwidth = GridBagConstraints.REMAINDER;
		pane.add(sp2 = new JScrollPane(stackList), gbc);
		sp1.setBorder(BorderFactory.createTitledBorder("Queue Contents"));
		sp2.setBorder(BorderFactory.createTitledBorder("Stack Contents"));

		// Now, two more arrows
		gbc.weighty = 0;
		gbc.gridwidth = GridBagConstraints.RELATIVE;
		pane.add(new JLabel(arrow), gbc);
		gbc.gridwidth = GridBagConstraints.REMAINDER;
		pane.add(new JLabel(arrow), gbc);

		// Two results text fields
		gbc.weighty = 1;
		gbc.gridwidth = GridBagConstraints.RELATIVE;
		pane.add(retrievedQueueItem, gbc);
		gbc.gridwidth = GridBagConstraints.REMAINDER;
		pane.add(retrievedStackItem, gbc);
		
		// Let's give these text comonents borders, too!
		retrievedQueueItem.setBorder(BorderFactory.createTitledBorder("Item From Queue"));
		retrievedStackItem.setBorder(BorderFactory.createTitledBorder("Item From Stack"));
		
		// And, finally, the "remove" button
		gbc.fill = GridBagConstraints.VERTICAL;
		pane.add(removeButton, gbc);
		
		// Set up the Event handling
		addButton.setActionCommand(ADD);
		addButton.addActionListener(this);
		removeButton.setActionCommand(REMOVE);
		removeButton.addActionListener(this);
		newItem.setActionCommand(ADD);
		newItem.addActionListener(this);
		
		// Start 
		setMessage("Add some items");
		displayLists();
	}

	// 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 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 ADD command.
	    if (command.equals(ADD))
	    {
		addNewItem();
		return;
	    }

	    // Test for the REMOVE command.
	    if (command.equals(REMOVE))
	    {
	    	retrieveItem();
		return;
	    }
	}
	
	/**
	 * Update the message bar.
	 */
	private void setMessage(String msg)
	{
		message.setText(msg);
	}

	/**
	 * Add the newItem to both the stack and queue.
	 */
	private void addNewItem()
	{
	    // Let's add/push the newItem value.
	    // First make sure that there is a value;
	    String s = newItem.getText();
	    if (s == null || s.length() == 0)
	    {
		setMessage("Nothing to add");
		return;
	    }
	    setMessage("Adding: " + s);
	    queue.add(s);
	    stack.push(s);
	    displayLists();
	    // Let's remove the added item from the text field.
	    newItem.setText("");
	}

	/**
	 * Retrieve the first item from both the stack and queue.
	 */
	private void retrieveItem()
	{
	    // Get the two strings from each list.
	    String queueString = (String) queue.remove();
	    String stackString = (String) stack.pop();
	    // Add the strings to the two "retrieved" text fields.
	    if (queueString == null || stackString == null)
	    {
		setMessage("Lists are empty!");
		retrievedQueueItem.setText("");
		retrievedStackItem.setText("");		
	    }
	    else
	    {
		setMessage("Items retrieved!");
		retrievedQueueItem.setText(queueString);
		retrievedStackItem.setText(stackString);		
		displayLists();
	    }
	}
	
	/**
	 * Update the two JList items so we can see the contents.
	 * You normally wouldn't do this since you're not supposed
	 * to care about the "insides" of an object.  But for teaching
	 * purposes, we're "opening the hood" for you.
	 *<p>
	 * This method will display the queue and stack in a JList so you can
	 * see their contents.
	 */
	private void displayLists()
	{
	    queueList.setListData(queue.getList());
	    stackList.setListData(stack.getList());
	}

}
