package objectguess;

import java.io.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import java.awt.*;

/**
 * Title:        ObjectGuess
 * Description:  This application builds a tree of questions used to guess any object. If
 * the application fails to correctly guess the object, a new question node is added to the tree.
 * Date:    Sept. 10, 2001
 * @author William Dubel
 * @version 1.0
 */
public class Guess extends JFrame
{
	private JMenuItem newGame, loadTree, help, quit, about, feel, saveTree, clearTree;
	private JMenu fileMenu, helpMenu;
	private JMenuBar bar;
	private JPanel mainPanel;
	private JFileChooser fileChooser = new JFileChooser();
	private boolean treeUpdated;
	private TreeNode currentTree, treeTop;

	private Container c;
	private ItemHandler itemHandler = new ItemHandler();

	public Guess()
	{
		super("Object Guesser");
		c = getContentPane();

		setJMenuBar(bar = new JMenuBar());

		(fileMenu = new JMenu("File")).setMnemonic('F');;			// This is the File Menu

		(newGame = new JMenuItem("New Game...",'N')).addActionListener(itemHandler);
		(loadTree = new JMenuItem("Load Object Tree File...",'L')).addActionListener(itemHandler);
		(saveTree = new JMenuItem("Save Object Tree File...",'S')).addActionListener(itemHandler);
		(clearTree = new JMenuItem("Clear Object Tree...",'C')).addActionListener(itemHandler);
		(quit = new JMenuItem("Exit",'x')).addActionListener(itemHandler);

		saveTree.setEnabled(false);

		fileMenu.add(newGame);
		fileMenu.add(loadTree);
		fileMenu.add(clearTree);
		fileMenu.add(saveTree);
		fileMenu.addSeparator();
		fileMenu.add(quit);

		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

		(helpMenu = new JMenu("Help")).setMnemonic('H');

		(about = new JMenuItem("About Object Guesser...",'A')).addActionListener(itemHandler);
		(help = new JMenuItem("Help",'H')).addActionListener(itemHandler);
		(feel = new JMenuItem("Look and Feel...",'L')).addActionListener(itemHandler);

		helpMenu.add(about);
		helpMenu.add(help);
		helpMenu.add(feel);

		bar.add(fileMenu);
		bar.add(helpMenu);

		(mainPanel = new JPanel()).setLayout(new FlowLayout());
		treeTop = new TreeNode("nothing");
		treeUpdated = false;

		setSize(500,220);

		//c.add(mainPanel,BorderLayout.CENTER);

		//Center the application on the screen
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension frameSize = getSize();
		if (frameSize.height > screenSize.height) frameSize.height = screenSize.height;
		if (frameSize.width > screenSize.width) frameSize.width = screenSize.width;
		setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
		setVisible(true);

		addWindowListener( new WindowAdapter()	{
			public void windowClosing( WindowEvent e )
			{
				int answer = -1;
				if (treeUpdated == true) answer = askSave();
				if (answer!=JOptionPane.CANCEL_OPTION)
				{
					if (answer==JOptionPane.OK_OPTION)	{		save();		}
					System.exit(0);
				}
		}	}
		);
	}

	private class ItemHandler implements ActionListener
	{
		public void actionPerformed( ActionEvent e )
		{
			// Code to handle File events
			if (e.getSource()==newGame)
			{
				// Must change code from JOptionPane to work within the application panel  XXXXXXXXX
				newGame.setEnabled(false);
				loadTree.setEnabled(false);
				clearTree.setEnabled(false);     //needed for now
				int result;
				boolean yesAnswer, stillPlaying;
				final int YES = JOptionPane.YES_OPTION, NO = JOptionPane.NO_OPTION;
				String newItem;
				String newQuestion;

				currentTree = treeTop;
				stillPlaying = true;
				while (currentTree.isQuestion() && stillPlaying==true)
				{
					result = JOptionPane.showInternalConfirmDialog(c, currentTree.GetContents(), "Question",
					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

					if (result==YES) currentTree = currentTree.getYes();
					if (result==NO) currentTree = currentTree.getNo();
					if (result!=YES && result!=NO) stillPlaying=false;
				}
				if (stillPlaying)
				{
					result = JOptionPane.showInternalConfirmDialog(c, "Your object must be " +
						   currentTree.GetContents() + "!\nAm I right?", "Object Found!",
					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
					if (result==YES) JOptionPane.showInternalMessageDialog(c, "I win! Please play again...");
					if (result==NO)
					{
						newItem = JOptionPane.showInternalInputDialog(c, "Please enter your object:");
						newQuestion = JOptionPane.showInternalInputDialog(c, "Please enter a question that would " +
							"distinguish\nbetween " + currentTree.GetContents() + " and " + newItem + ":");
						result = JOptionPane.showInternalConfirmDialog(c, "If thinking of " + newItem +
							", How would someone respond to your question,\n\"" + newQuestion + "\"?",
							"New Object Addition", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
						if (newItem!=null && newQuestion!=null && (result==YES || result == NO))
						{
							yesAnswer = result==YES;
							currentTree.insert(newItem, newQuestion, yesAnswer);
							treeUpdated = true;
							saveTree.setEnabled(true);
						}
					}
				}
				newGame.setEnabled(true);
				loadTree.setEnabled(true);
				clearTree.setEnabled(true);     //needed for now
				//End of code that needs to be changed XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
			}
			if (e.getSource()==loadTree)
			{
				int answer = -1;
				if (treeUpdated == true) answer = askSave();
				if (answer!=JOptionPane.CANCEL_OPTION)
				{
					if (answer==JOptionPane.OK_OPTION)	{		save();		}

					int result = fileChooser.showOpenDialog(c);
					if (result!=JFileChooser.CANCEL_OPTION)
					{
						ObjectInputStream in=null;
						try
						{
							File filename = fileChooser.getSelectedFile();

							in = new ObjectInputStream(new FileInputStream(filename));

							treeTop = (TreeNode)in.readObject();
							currentTree = treeTop;

							saveTree.setEnabled(false);
							treeUpdated = false;

							in.close();
						}
						catch(FileNotFoundException fnfe)	{
							JOptionPane.showMessageDialog(c,"Exception: File not found.");	}
						catch(IOException ioe)
						{
							JOptionPane.showMessageDialog(c,"Exception: Input Problem.");
							try { if (in!=null) in.close(); }
							catch(IOException ioe2)
							{
								JOptionPane.showMessageDialog(c,"Exception: Can't close file.");
							}
						}
						catch(ClassNotFoundException se)	{
							JOptionPane.showMessageDialog(c,"Invalid or currupt data file.");	}
					}
				}
			}
			if (e.getSource()==clearTree)
			{
				int answer = -1;
				if (treeUpdated == true) answer = askSave();
				if (answer!=JOptionPane.CANCEL_OPTION)
				{
					if (answer==JOptionPane.OK_OPTION)	{		save();		}

					treeTop = new TreeNode("nothing");
					currentTree = treeTop;
				}
			}
			if (e.getSource()==saveTree)					{		save();				}
			if (e.getSource()==quit)
			{
				int answer = -1;
				if (treeUpdated == true) answer = askSave();
				if (answer!=JOptionPane.CANCEL_OPTION)
				{
					if (answer==JOptionPane.OK_OPTION)	{		save();				}
					System.exit(0);
				}
			}
			// Code to handle Help menu item events
			if (e.getSource()==about) {
				JOptionPane.showMessageDialog(c,
					"Object Guesser\n\nAuthor: William Dubel\n" +
					"Created: September 10, 2001\n\nI didn't come up with the idea for this\nprogram, " +
					"I remember playing something similar\non the original Apple Macintosh series but\n" +
					"I don't remember who was the author. I\nrewrote it in Java as a programming example",
					"About Object Guesser", JOptionPane.PLAIN_MESSAGE);
			}
			if (e.getSource()==help)
			{
				JOptionPane.showMessageDialog(c,
					"Object Guesser Help:\n\nThe better your questions are phrased, the better the\n" +
					"computer will be at guessing your object!\nWhen entering the name of your object, " +
					"include the\npreposition - 'an apple' instead of 'apple' where appropriate.\n" +
					"Also, enter your question exactly as you would like it to\nappear, including " +
					"punctuation.", "Object Guesser Help", JOptionPane.PLAIN_MESSAGE);
			}
			if (e.getSource()==feel)  {
				UIManager.LookAndFeelInfo looks[] = UIManager.getInstalledLookAndFeels();
				String options[] = new String[looks.length];
				for (int i=0; i<looks.length; i++) options[i]=looks[i].getClassName();

				Object selection = JOptionPane.showInputDialog(c, "Choose a Look and Feel:",
					"Look and Feel", JOptionPane.INFORMATION_MESSAGE, null, options, options[0]);
				if (selection!=null)  {
					try	{
						UIManager.setLookAndFeel((String)selection);
						SwingUtilities.updateComponentTreeUI(c.getParent());
					}
					catch(Exception lnfe)	{
						JOptionPane.showMessageDialog(c,"Exception: " + lnfe.getMessage());
					}
				}
			}
		}
	}

	private int askSave()
	{
		return JOptionPane.showConfirmDialog(c, "The current object tree has not been saved, " +
			"would you like to save it?", "Object Tree Updated",
			JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
	}

	private void save()
	{
		int result = fileChooser.showSaveDialog(c);
		if (result!=JFileChooser.CANCEL_OPTION)
		{
			ObjectOutputStream out=null;
			try
			{
				File filename = fileChooser.getSelectedFile();
				out = new ObjectOutputStream(new FileOutputStream(filename));

				out.writeObject(treeTop);
				out.close();
				treeUpdated = false;
			}
			catch(IOException ioe)
			{
				JOptionPane.showMessageDialog(c,"Exception: Read Problem.");
				try { if (out!=null) out.close(); }
				catch(IOException ioe2)
				{
					JOptionPane.showMessageDialog(c,"Exception: Can't close file.");
				}
			}
			catch(Exception se)	{
				JOptionPane.showMessageDialog(c,"General Exception.");	}
		}
	}

	public static void main(String[] args) {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		new Guess();
	}
}
/** This class is a simple Binary Tree Structure
  * @author William Dubel
  */
class TreeNode implements Serializable
{
	private TreeNode yes, no;
	private String contents;

	public TreeNode(String item)
	{
		yes = no = null;
		contents = item;
	}

	public TreeNode(TreeNode parent)
	{
		yes = no = null;
		contents = parent.contents;
	}

	public void insert(String item, String question, boolean noMeansNo)
	{
		if (noMeansNo)
		{
			no = new TreeNode(this);
			yes = new TreeNode(item);
			contents = question;
		}
		else
		{
			yes = new TreeNode(this);
			no = new TreeNode(item);
			contents = question;
		}
	}

	public TreeNode getYes()        {   return yes;                 }
	public TreeNode getNo()        {   return no;                 }
	public boolean isQuestion()     {   return (yes!=null);         }
	public String GetContents()     {   return contents;            }
}
