package toy;

import java.applet.*;
import java.awt.*;              //All the dialog objects
import java.awt.event.*;        //So the dialog objects do stuff
import java.awt.datatransfer.*; //Clipboard support
import java.io.*;               //File support
import java.net.*;              //Launching webpage support

import toy.dialog.*;
import toy.image.*;

/**
 * ToyFrame is the frame that launches from the splash screen.  This is the main
 * GUI interface.
 *
 * @author Brian Tsang
 * @version 7.0
 */

public class ToyFrame extends Frame
                      implements ActionListener, ItemListener, Runnable
{
    /**
     * An array of urls that correspond to the MenuItems in the
     * helpMenu.
     * @see #helpMenu
     * @see #helpRequest(int)
     */
    private static final String HELP_URLS[] =
    {
        "http://www.princeton.edu/~btsang/toy/toy.html",
        "http://www.princeton.edu/~btsang/toy/toy2.html",
        "http://www.princeton.edu/~btsang/toy/toy3.html",
        "http://www.princeton.edu/~btsang/toy/toy4.html",
        "http://www.princeton.edu/~btsang/toy/toy5.html",
        "http://www.princeton.edu/~btsang/toy/toy6.html"
    };

    /**
     * The minimum width that the frame can have.  This is semi-arbitrary.
     */
    public static final int MIN_WIDTH  = 576;
    /**
     * The minimum height that the frame can have.  This is semi-arbitrary.
     */
    public static final int MIN_HEIGHT = 432;

    /**
     * The value mode takes when no workspaces are open.
     * @see #mode
     */
    public static final int NULL  = 0;
    /**
     * The value mode takes when the currently selected workspace is in Edit
     * mode.
     * @see #mode
     */
    public static final int EDIT  = 1;
    /**
     * The value mode takes when the currently selected workspace is in Debug
     * mode.
     * @see #mode
     */
    public static final int DEBUG = 2;
    /**
     * The value mode takes when the currently selected workspace is in Sim
     * mode.
     * @see #mode
     */
    public static final int SIM   = 3;


    /**
     * The array of all workspaces.
     * @serial
     */
    private ToyWorkspace workspace[];

    /**
     * The the last opened directory.  This will let us put the FileDialog in
     * the last opened directory for user-friendliness.
     * @serial
     */
    private String lastDirectory;

    /**
     * The index of the currently opened workspace.
     * @see #workspace
     * @serial
     */
    private int currentWorkspace;
    /**
     * The mode of the currently opened workspace.
     * @see #workspace
     * @serial
     */
    private int mode;

    /**
     * A pointer to the launch applet.  This will let us open up web pages when
     * the user selects a help button.
     * @see #helpMenu
     * @see #helpRequest(int)
     * @serial
     */
    private Applet parentApplet;

    /**
     * An object containing the parameters passed into Visual X-TOY via an
     * applet's PARAM tag or the param.ini file.
     * @serial
     */
    private ToyParameterManager parameterManager;

    /**
     * An object containing the images loaded from the applet or from the
     * filesystem.
     * @serial
     */
    private ToyImageManager imageManager;

    /**
     * An object to keep track of which component currently has the focus.
     * We can't count on a non-Sun VM to implement Frame.getSelectedComponent().
     * @serial
     */
    private ToyFocusManager focusManager;

    /**
     * The "File" menu.
     * @serial
     */
    private Menu fileMenu;
    /**
     * The "Edit" menu.
     * @serial
     */
    private Menu editMenu;
    /**
     * The "Mode" menu.
     * @serial
     */
    private Menu modeMenu;
    /**
     * The "Workspace" menu.
     * @serial
     */
    private Menu workspaceMenu;
    /**
     * The "Tools" menu.
     * @serial
     */
    private Menu toolsMenu;
        /**
         * The "Auto-Comment" checkbox menu item.  This controls the feature
         * that automatically updates the comments of the user as the user
         * modifies the code.
         * @serial
         */
        private CheckboxMenuItem autoCommentCheckbox;
        /**
         * The "Syntax Highlighting" checkbox menu item.  This controls wheter
         * or not the program text area in Edit mode is the standard text area
         * or the custom-made ToyTextAreaPeer.
         * @see toy.dialog.ToyTextAreaPeer
         * @serial
         */
        private CheckboxMenuItem highlightingCheckbox;
        /**
         * The "Compiler Warnings" checkbox menu item.  This controls wheter or
         * not non-fatal warnings are enumerated by the compiler in Edit mode.
         * @serial
         */
        private CheckboxMenuItem warningCheckbox;
        /**
         * The "Uninitialized Errors" checkbox menu item.  This controls wheter
         * or not Debug mode will terminate if some sort of uninitialized error
         * occurs.
         * @see toy.ToyException#VARIABLE_UNINITIALIZED
         * @see toy.ToyException#COMMAND_UNINITIALIZED
         * @serial
         */
        private CheckboxMenuItem uninitializedErrorCheckbox;
        /**
         * The "Overflow Errors" checkbox menu item.  This controls wheter or
         * not Debug mode will terminate if an overflow error occurs.
         * @see toy.ToyException#OVERFLOW
         * @serial
         */
        private CheckboxMenuItem overflowErrorCheckbox;
        /**
         * The "Out of Bounds Errors" checkbox menu item.  This controls wheter
         * or not Debug mode will terminate if some sort of out-of-bounds error
         * occurs.
         * @see toy.ToyException#SHIFT_OUT_OF_BOUNDS
         * @see toy.ToyException#PC_OUT_OF_BOUNDS
         * @see toy.ToyException#REGISTER_OUT_OF_BOUNDS
         * @see toy.ToyException#MEM_OUT_OF_BOUNDS
         * @serial
         */
        private CheckboxMenuItem outOfBoundsErrorCheckbox;
        /**
         * The "Close Execution Dialog When Done" checkbox menu item.  This
         * controls wheter or not the execution popup will automatically close
         * itself when the program halts.
         * @see toy.dialog.ToyPopup
         * @serial
         */
        private CheckboxMenuItem closeExecutionCheckbox;
    /**
     * The "Help" menu.
     * @serial
     */
    private Menu helpMenu;

    /**
     * The thread which updates the title and compiler warnings.
     * @serial
     */
    private Thread runner;

    /**
     * The top bar which makes the GUI look like a tabbed pane.
     * @serial
     */
    private ToyTitlePanel titlePanel;

    /**
     * The panel which switches its contents based on the mode.
     * @see #cardLayout
     * @serial
     */
    private Panel cardPanel;
    /**
     * The layout for the cardPanel
     * @see #cardPanel
     * @serial
     */
    private CardLayout cardLayout;
        /**
         * A container which manages all the components associate with Edit
         * mode.
         * @see #debugPanel
         * @see #simPanel
         * @serial
         */
        private ToyEditPanel editPanel;
        /**
         * A container which manages all the components associate with Debug
         * mode.
         * @see #debugPanel
         * @see #simPanel
         * @serial
         */
        private ToyDebugPanel debugPanel;
        /**
         * A container which manages all the components associate with Sim mode.
         * @see #debugPanel
         * @see #simPanel
         * @serial
         */
        private ToySimPanel simPanel;

    /**
     * Constructs a new "Visual X-TOY" GUI frame.
     * @param newParentApplet
     *    the applet which launched this frame, null if Visual X-TOY was run by
     *    an applet.
     * @param newParameterManager
     *    the object encapsulating the starting parameters loaded from either
     *    the applet or the param.ini file.
     * @param newImageManager
     *    the object encapsulating the images loaded from either the applet or
     *    the filesystem.
     */
    public ToyFrame(Applet newParentApplet,
                    ToyParameterManager newParameterManager,
                    ToyImageManager newImageManager)
    {
        super("Visual X-TOY");

        currentWorkspace = 0;
        parentApplet = newParentApplet;
        parameterManager = newParameterManager;
        imageManager = newImageManager;

        try
        {
            //try to find the useableWidth parameters...
            int startWidth, startHeight;

            try
            {
                startWidth = Integer.parseInt(parameterManager.getParameter("startWidth"));
                startHeight = Integer.parseInt(parameterManager.getParameter("startHeight"));
            }
            catch (Exception e)
            {
                startWidth = MIN_WIDTH;
                startHeight = MIN_HEIGHT;
            }

            //Change the size properties of this applet and force a resize calculation
            setSize(startWidth, startHeight);

            //Check Clipboard Permissions and attempt to restore the workspaces
            if (!"false".equals(parameterManager.getParameter("workspaceDump")) &&
                ToyToolkit.hasClipboardPermissions())
                restoreWorkspaces();

            //Check File Permissions
            if (!ToyToolkit.hasFilePermissions())
            {
                if (!ToyToolkit.hasClipboardPermissions())
                    ToyPopup.askUser(
                        this,
                        "Clipboard and Filesystem Security Notification",
                        "Visual X-TOY does not have access to the filesystem or the clipboard\n" +
                        "\tYou will be unable to access useful features such as opening and saving " +
                        "toy files or use the cut, copy, and paste functions from the edit menu.  " +
                        "However, it is still possible to use Visual X-TOY, just open " +
                        "a text editor such as Notepad, SimpleText, or Emacs.  From there, you " +
                        "can copy (Ctrl-C) and paste (Ctrl-V) between to two appications.  " +
                        "However, if you want the convenience of a fully functional Integrated " +
                        "Development Envorionment, please follow the instructions on the \"II. " +
                        "Before You Start\" page.",
                        "OK"
                        );
                else
                    ToyPopup.askUser(
                        this,
                        "Filesystem Security Notification",
                        "Visual X-TOY does not have access to the filesystem\n" +
                        "\tYou will be unable to access useful features such as opening and saving " +
                        "toy files.  However, it is still possible to use Visual X-TOY, just open " +
                        "a text editor such as Notepad, SimpleText, or Emacs.  From there, you " +
                        "can copy and paste between to two appications.  However, if you want the " +
                        "convenience of a fully functional Integrated Development Envorionment, " +
                        "please follow the instructions on the \"II. Before You Start\" page.",
                        "OK"
                        );
            }
            else {
                if (!ToyToolkit.hasClipboardPermissions())
                    ToyPopup.askUser(
                        this,
                        "Clipboard Security Notification",
                        "Visual X-TOY does not have access to the clipboard\n" +
                        "\tYou may be unable to access necessary features such as Cut, Copy, and " +
                        "Paste.  However, IE 5.5 and Nav 4.76 do seem to handle these " +
                        "commands on their own (try using Ctrl-X, Ctrl-C, and Ctrl-V).  Either way, " +
                        "it would be best if you followed the instructions on the \"II. Before " +
                        "You Start\" page so this program can access the clipboard.",
                        "OK"
                        );
            }

            //Load Workspaces if they haven't been loaded already
            if (workspace == null)
            {
                workspace = new ToyWorkspace[1];
                workspace[0] = new ToyWorkspace(
                    "Program Untitled1\n" +
                    "Input:    \n" +
                    "Output:   \n" +
                    "Remarks:  \n" +
                    ToyWorkspace.HEADER_BAR + "\n" +
                    "\n"
                    );
            }

            //Initialize Dialog Objects
            initializeDialogClasses();

            //Set icon
            setIconImage(imageManager.getImage(ToyImageManager.FRAME_ICON));

            //pass the remining initializations on to common event funcitons
            changeWorkspace(0);

            //start the maintenance thread
            runner = new Thread(this);
            runner.start();

            //final resize for good luck
            doLayout();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        enableEvents(AWTEvent.WINDOW_EVENT_MASK | AWTEvent.COMPONENT_EVENT_MASK);
    }

    /**
     * Implement the Runnable interface to have the compiler warnings and title
     * update every second.
     */
    public void run()
    {
        Thread thisThread = Thread.currentThread();

        while (runner == thisThread)
        {
            try
            {
                if (mode == EDIT)
                    editPanel.refresh();

                if (mode != NULL)
                {
                    if (workspace[currentWorkspace].isSaved())
                        setTitle("Visual X-TOY - " + workspace[currentWorkspace].getName());
                        else
                        setTitle("Visual X-TOY - " + workspace[currentWorkspace].getName() + "*");

                    workspaceMenu.getItem(currentWorkspace).setLabel(
                        workspace[currentWorkspace].getName()
                        );
                }
                else
                    setTitle("Visual X-TOY");
            }
            catch (Exception e)
            {
                //whatever
            }

            try
            {
                //pause for a number of milliseconds
                if (runner == thisThread)
                    Thread.sleep(1000);
            }
            catch (Exception e)
            {
                //whatever
            }
        }
    }

    /**
     * Checks for clipboard permissions and tries to recover the workspaces.
     */
    public void restoreWorkspaces()
    {
        Clipboard restoreClipboard;
        Transferable t;
        String restoreString;

        //Attempt to get the clipboard
        restoreClipboard = getToolkit().getSystemClipboard();

        try
        {
            //extracting the string from the clipboard
            t = restoreClipboard.getContents(this);
            if (t == null)
                return;

            restoreString = (String)t.getTransferData(DataFlavor.stringFlavor);

            //the string must begin a certain way if it's really a core dump
            if (!restoreString.startsWith("Visual X-TOY Clipboard Dump (can be used to restore workspaces)\n"))
                return;

            //ok it got this far, lets try and do it

            //initialize array
            workspace = new ToyWorkspace[0];

            while (restoreString.indexOf("@FILE@") >= 0)
            {
                String newText;
                String newFile;
                int start, end;
                ToyWord stdin[];

                //Get the workspace filename
                start = restoreString.indexOf("@FILE@");
                end = restoreString.indexOf("@END@");

                if (start == -1 || end == -1 || end < start)
                {
                    workspace = null;
                    return;
                }

                if (start + "@FILE@".length() == end)
                    newFile = null;
                    else
                    newFile = restoreString.substring(start + "@FILE@".length(), end);

                restoreString = restoreString.substring(end + "@END@".length());

                //Get stdin
                start = restoreString.indexOf("@INPUT@");
                end = restoreString.indexOf("@END@");

                if (start == -1 || end == -1 || end < start ||
                    (end - (start + "@INPUT@".length())) % 4 != 0)
                {
                    workspace = null;
                    return;
                }

                stdin = new ToyWord[(end - (start + "@INPUT@".length())) / 4];

                for (int ctr = 0; ctr < (end - (start + "@INPUT@".length())) / 4; ctr++)
                {
                    stdin[ctr] = ToyWord.parseHexidecimal(
                        restoreString.charAt(start + 7 + ctr * 4),
                        restoreString.charAt(start + 8 + ctr * 4),
                        restoreString.charAt(start + 9 + ctr * 4),
                        restoreString.charAt(start + 10 + ctr * 4)
                        );
                }

                restoreString = restoreString.substring(end + "@END@".length());

                //Get the workspace text
                start = restoreString.indexOf("@TEXT@");
                end = restoreString.indexOf("@END@");

                if (start == -1 || end == -1 || end < start)
                {
                    workspace = null;
                    return;
                }

                newText = restoreString.substring(start + "@TEXT@".length(), end);

                restoreString = restoreString.substring(end + "@END@".length());

                //initialize the new workspace
                ToyWorkspace oldWorkspace[] = workspace;

                workspace = new ToyWorkspace[workspace.length + 1];

                for (int ctr = 0; ctr < oldWorkspace.length; ctr++)
                    workspace[ctr] = oldWorkspace[ctr];

                workspace[workspace.length - 1] = new ToyWorkspace(
                    newText,
                    newFile,
                    stdin
                    );
            }
        }
        catch (Exception e)
        {
            //Restore failed
            //Oh well, no biggie
            //but don't let this mean we didn't have permissions
            //  (see the catch below)
            workspace = null;
            return;
        }
    }

    /**
     * The function called when the "New" menu item is selected.
     */
    public void newRequest()
    {
        ToyWorkspace oldWorkspace[] = workspace;

        workspace = new ToyWorkspace[workspace.length + 1];

        for (int ctr = 0; ctr < oldWorkspace.length; ctr++)
            workspace[ctr] = oldWorkspace[ctr];

        int number = 1;
        boolean done;

        do
        {
            done = true;

            for (int ctr = 0; done && ctr < workspace.length - 1; ctr++)
                if (workspace[ctr].getName().equalsIgnoreCase("Untitled" + number))
                    done = false;

            if (!done)
                number++;
        }
        while (!done);

        workspace[workspace.length - 1] = new ToyWorkspace(
            "Program Untitled" + number + "\n" +
            "Input:    \n" +
            "Output:   \n" +
            "Remarks:  \n" +
            ToyWorkspace.HEADER_BAR + "\n" +
            "\n"
            );

        MenuItem newMenuItem = new MenuItem(
            workspace[workspace.length - 1].getName()
            );
        newMenuItem.addActionListener(this);
        workspaceMenu.add(newMenuItem);

        changeWorkspace(workspace.length - 1);
    }

    /**
     * The function called when the "Open..." menu item is selected.
     */
    public void openRequest()
    {
        FileDialog fileDialog = new FileDialog(this, "Open Workspace", FileDialog.LOAD);

        if (lastDirectory != null)
            fileDialog.setDirectory(lastDirectory);

        fileDialog.setFile("*.toy");
        fileDialog.show();

        if (fileDialog.getFile() != null && fileDialog.getDirectory() != null)
        {
            lastDirectory = fileDialog.getDirectory();

            try
            {
                FileReader file = new FileReader(
                    fileDialog.getDirectory() + fileDialog.getFile()
                    );
                int newChar;
                String textString = "";

                //copy the file, character by character, into the current text
                do
                {
                    newChar = file.read();
                    if (newChar != -1)
                        textString += (char)newChar;
                }
                while (newChar != -1);

                file.close();


                //make a new workspace unless our original untitled is still there
                if (workspace.length == 1 &&
                    workspace[0].getName().equals("Untitled1") &&
                    "".equals(workspace[0].getFileName()) &&
                    workspace[0].isSaved())
                {
                    workspace[0] = new ToyWorkspace(
                        textString,
                        fileDialog.getDirectory() + fileDialog.getFile()
                        );

                    workspaceMenu.getItem(0).setLabel(workspace[0].getName());

                    changeWorkspace(0);
                }
                else {
                    ToyWorkspace oldWorkspace[] = workspace;

                    workspace = new ToyWorkspace[workspace.length + 1];

                    for (int ctr = 0; ctr < oldWorkspace.length; ctr++)
                        workspace[ctr] = oldWorkspace[ctr];

                    workspace[workspace.length - 1] = new ToyWorkspace(
                        textString,
                        fileDialog.getDirectory() + fileDialog.getFile()
                        );

                    MenuItem newMenuItem = new MenuItem(
                        workspace[workspace.length - 1].getName()
                        );
                    newMenuItem.addActionListener(this);
                    workspaceMenu.add(newMenuItem);

                    //change the workspace
                    changeWorkspace(workspace.length - 1);
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();

                ToyPopup.askUser(
                    this,
                    "File Reading Error",
                    "An error occured when reading the file\n" +
                    "\tAn error occured when reading the file.  This probably occured because " +
                    "your browser has a really strange security setting where it allows an " +
                    "applet to open a file dialog box, but doesn't allow it to read the " +
                    "selected file.  Please follow the instructions on the launch page to " +
                    "give this program the appropriate permissions.",
                    "OK"
                    );
            }
        }
    }

    /**
     * The function called when the "Open Exaple Program..." menu item is
     * selected.
     */
    public void openExampleRequest()
    {
        String exampleTitles[] = parameterManager.getExampleTitles();
        String examplePrograms[] = parameterManager.getExamplePrograms();

        //compile list of workspaces
        int choice = ToyPopup.getExampleChoice(
            this,
            exampleTitles,
            examplePrograms
            );

        if (choice >= 0 && choice < examplePrograms.length)
        {
            //make a new workspace unless our original untitled is still there
            if (workspace.length == 1 &&
                workspace[0].getName().equals("Untitled1") &&
                "".equals(workspace[0].getFileName()) &&
                workspace[0].isSaved())
            {
                workspace[0] = new ToyWorkspace(
                    examplePrograms[choice]
                    );

                workspaceMenu.getItem(0).setLabel(exampleTitles[choice]);

                changeWorkspace(0);
            }
            else {
                ToyWorkspace oldWorkspace[] = workspace;

                workspace = new ToyWorkspace[workspace.length + 1];

                for (int ctr = 0; ctr < oldWorkspace.length; ctr++)
                    workspace[ctr] = oldWorkspace[ctr];

                workspace[workspace.length - 1] = new ToyWorkspace(
                    examplePrograms[choice]
                    );

                MenuItem newMenuItem = new MenuItem(exampleTitles[choice]);
                newMenuItem.addActionListener(this);
                workspaceMenu.add(newMenuItem);

                //change the workspace
                changeWorkspace(workspace.length - 1);
            }
        }
    }

    /**
     * The function called when the "Close" menu item is selected.
     */
    public void closeRequest()
    {
        if (!workspace[currentWorkspace].isSaved())
        {
            if (ToyPopup.askUser(
                    this,
                    "Save Before Closing",
                    "Program \"" + workspace[currentWorkspace].getName() + "\" has been modified.\n" +
                    "\tDo you want to save these changes to disk?",
                    "Save",
                    "Don't Save"
                    )
                )
            {
                if (!saveRequest())
                    return;
            }
        }

        ToyWorkspace oldWorkspace[] = workspace;

        workspace = new ToyWorkspace[workspace.length - 1];

        for (int ctr = 0; ctr < currentWorkspace; ctr++)
            workspace[ctr] = oldWorkspace[ctr];

        for (int ctr = currentWorkspace + 1; ctr < oldWorkspace.length; ctr++)
            workspace[ctr - 1] = oldWorkspace[ctr];

        workspaceMenu.remove(currentWorkspace);

        mode = NULL;

        if (currentWorkspace >= workspace.length)
            changeWorkspace(workspace.length - 1);
        else
            changeWorkspace(currentWorkspace);
    }

    /**
     * The function called when the "Revert" menu item is selected.
     */
    public void revertRequest()
    {
        if (ToyPopup.askUser(
                this,
               "Revert Confirmation",
                "Are you sure you want revert to the last saved state of this program?\n" +
                "\tThis will discard all the changes you have made since your last save.",
                "Yes",
                "No"
                )
            )
        {
            workspace[currentWorkspace].revertToSaved();

            //change the mode to edit
            changeMode(EDIT);
        }
    }

    /**
     * The function called when the "Save" menu item is selected.
     */
    public boolean saveRequest()
    {
        FileWriter file;

        //if this document has not been saved before, treat this as a
        //"Save As..." command
        if (workspace[currentWorkspace].getFileName() == null)
            return saveAsRequest();

        if (mode == EDIT)
            editPanel.refresh();

        try
        {
            //ask the user about saving changes made in Sim mode, if relevant
            if (mode == SIM && workspace[currentWorkspace].memChanged())
                simSaveRequest();

            //dump the text area string into the file
            file = new FileWriter(workspace[currentWorkspace].getFileName());

            file.write(workspace[currentWorkspace].getText());

            file.close();
            workspace[currentWorkspace].workSaved();

            changeMode();

            return true;
        }
        catch (Exception e)
        {
            //if something goes wrong (like the file is read-only),
            //send it to "Save As..."
            return saveAsRequest();
        }
    }

    /**
     * The function called when the "Save As" menu item is selected.
     */
    public boolean saveAsRequest()
    {
        FileDialog fileDialog = new FileDialog(this, "Save Workspace As", FileDialog.SAVE);

        //ask the user about saving changes made in Sim mode, if relevant
        if (mode == SIM && workspace[currentWorkspace].memChanged())
            simSaveRequest();

        if (mode == EDIT)
            editPanel.refresh();

        if (lastDirectory != null)
            fileDialog.setDirectory(lastDirectory);

        //recommend a name
        fileDialog.setFile(
            workspace[currentWorkspace].getName().toLowerCase().replace(' ', '_') + ".toy");
        fileDialog.show();

        if (fileDialog.getFile() != null && fileDialog.getDirectory() != null)
        {
            lastDirectory = fileDialog.getDirectory();

            try
            {
                FileWriter file = new FileWriter(fileDialog.getDirectory() + fileDialog.getFile());
                String nameString;
                char nameCharArray[];

                //dump the program text string into the file
                file.write(workspace[currentWorkspace].getText());

                file.close();
                workspace[currentWorkspace].workSaved();

                workspace[currentWorkspace].setFileName(
                    fileDialog.getDirectory() + fileDialog.getFile()
                    );

                changeMode();

                return true;
            }
            catch (Exception e)
            {
                e.printStackTrace();

                ToyPopup.askUser(
                    this,
                    "File Writing Error",
                    "An error occured when writing the file\n" +
                    "\tAn error occured when reading the file.  This probably occured because " +
                    "your browser has a really strange security setting where it allows an " +
                    "applet to open a file dialog box, but doesn't allow it to write to the " +
                    "selected file.  Please follow the instructions on the launch page to " +
                    "give this program the appropriate permissions.",
                    "OK"
                    );

                return false;
            }
        }
        else
            return false;
    }

    /**
     * The function called when the "Quit" menu item is selected.
     */
    public void quitRequest()
    {
        boolean response = false;

        try
        {
            if (!ToyToolkit.hasFilePermissions())
            {
                response = ToyPopup.askUser(
                    this,
                    "Exit Confirmation",
                    "Are you sure you want to quit?\n" +
                    "\tSince the security features of Java prevent this program from saving " +
                    "all your work will be lost if you do not copy to disk, all of your " +
                    "code into Notepad/Emacs/SimpleText and save it!  If you forgot to " +
                    "save, please press \"Go Back\" now and save your work.",
                    "Go Back",
                    "Quit Anyway"
                    );
            }
            else
            {
                for (int ctr = 0; ctr < workspace.length; ctr++)
                    if (!workspace[ctr].isSaved())
                    {
                        if (ToyPopup.askUser(
                                this,
                                "Save Before Exit",
                                "Program \"" + workspace[ctr].getName() + "\" has been modified.\n" +
                                "\tDo you want to save these changes to disk?",
                                "Save",
                                "Don't Save"
                                )
                            )
                        {
                            changeWorkspace(ctr);
                            saveRequest();
                        }
                    }
            }


            if (ToyToolkit.hasFilePermissions() || !response)
            {
                //clipboard dump
                if (ToyToolkit.hasClipboardPermissions() &&
                    !"false".equals(parameterManager.getParameter("workspaceDump")))
                {
                    try
                    {
                        //put a spacial string a into the clipboard
                        String workspaceDump = "Visual X-TOY Clipboard Dump (can be used to restore workspaces)\n";

                        for (int ctr = 0; ctr < workspace.length; ctr++)
                        {
                            if (workspace[ctr].getFileName() == null)
                                workspaceDump += "\n@FILE@@END@\n";
                                else
                                workspaceDump += "\n@FILE@" + workspace[ctr].getFileName() + "@END@\n";

                            workspaceDump += "\n@INPUT@";
                            ToyWord stdin[] = workspace[ctr].getVirtualMachine().getStdin();
                            for (int ctr2 = 0; ctr2 < stdin.length; ctr2++)
                                workspaceDump += stdin[ctr2].toHexString();
                            workspaceDump += "@END@\n";

                            workspaceDump += "\n@TEXT@" + workspace[ctr].getText() + "@END@\n";
                        }

                        Clipboard clipboard = getToolkit().getSystemClipboard();
                        StringSelection copyData = new StringSelection(workspaceDump);
                        clipboard.setContents(copyData, copyData);
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }

                }

                //tell the parent that you're gone and destroy the window
                runner = null;
                dispose();
            }
        }
        catch (Exception e)
        {
            //Aaah!  Something bad happened!
            e.printStackTrace();

            //Must destroy window at all costs....
            runner = null;
            dispose();
        }
    }

    /**
     * The function called when the "Cut" menu item is selected.
     */
    public void cutRequest()
    {
        int start, end;

        //first copy the data
        copyRequest();

        //now if we're an editable text component, then delete the text
        if (focusManager.getFocusedComponent() instanceof TextComponent)
        {
            TextComponent temp = (TextComponent)(focusManager.getFocusedComponent());
            start = temp.getSelectionStart();
            end = temp.getSelectionEnd();

            if (start != end && temp.isEditable())
            {
                if (temp instanceof ToyTextArea)
                    ((ToyTextArea)temp).setText(
                        temp.getText().substring(0, start) + temp.getText().substring(end),
                        false
                        );
                else
                    temp.setText(
                        temp.getText().substring(0, start) + temp.getText().substring(end)
                        );
                temp.setCaretPosition(start);
                temp.select(start, start);
            }
        }
    }

    /**
     * The function called when the "Copy" menu item is selected.
     */
    public void copyRequest()
    {
        String copyString;
        StringSelection copyData;
        Clipboard clipboard;

        //try to get the clipboard
        try
        {
            clipboard = getToolkit().getSystemClipboard();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return;
        }

        //anonymously copy the data in a text component
        if (focusManager.getFocusedComponent() instanceof TextComponent)
        {
            TextComponent temp = (TextComponent)(focusManager.getFocusedComponent());

            if (temp.getSelectedText().length() > 0)
            {
                copyString = temp.getSelectedText();
                copyData = new StringSelection(copyString);
                clipboard.setContents(copyData, copyData);
            }
        }

        //anonymously copy the data in a list
        if (focusManager.getFocusedComponent() instanceof List)
        {
            List temp = (List)(focusManager.getFocusedComponent());

            if (temp.isMultipleMode())
            {
                String stringArray[] = temp.getSelectedItems();
                copyString = "";
                for (int ctr = 0; ctr < stringArray.length; ctr++)
                    copyString += stringArray[ctr] + "\n";
            }
            else
                copyString = temp.getSelectedItem();

            copyData = new StringSelection(copyString);
            clipboard.setContents(copyData, copyData);
        }
    }

    /**
     * The function called when the "Paste" menu item is selected.
     */
    public void pasteRequest()
    {
        String pasteString = "";
        int start, end;

        //attempt to get the clipboard
        try
        {
            Transferable t = getToolkit().getSystemClipboard().getContents(this);
            pasteString = (String) t.getTransferData(DataFlavor.stringFlavor);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return;
        }

        //only paste if we have an editable text component
        if (focusManager.getFocusedComponent() instanceof TextComponent)
        {
            TextComponent temp = (TextComponent)(focusManager.getFocusedComponent());

            if (temp.isEditable())
            {
                String text;
                start = temp.getSelectionStart();
                end = temp.getSelectionEnd();

                if (temp instanceof ToyTextArea)
                {
                    text = ((ToyTextArea)temp).getText(true);
                    ((ToyTextArea)temp).setText(
                        text.substring(0, start) + pasteString +
                            text.substring(end),
                        false
                        );
                }
                else {
                    text = temp.getText();
                    temp.setText(
                        text.substring(0, start) + pasteString +
                            text.substring(end)
                        );
                }

                //Make sure to put the cursor at the end of the recently
                //pasted text
                temp.setCaretPosition(start + pasteString.length());
                temp.select(start + pasteString.length(), start + pasteString.length());
            }
        }
    }

    /**
     * The function called when the "Select All" menu item is selected.
     */
    public void selectAllRequest()
    {
        //if we're a text component, then call the selectAll menthod
        if (focusManager.getFocusedComponent() instanceof TextComponent)
            ((TextComponent)(focusManager.getFocusedComponent())).selectAll();
    }

    /**
     * The function called when one of the menu items in the "Help" menu is
     * selected.
     * @param page the index of the menu item that was selected
     */
    public void helpRequest(int page)
    {
        try
        {
            //bring the browser to the front, send this to the back, and
            //open the page
            parentApplet.requestFocus();
            this.toBack();
            parentApplet.getAppletContext().showDocument(new URL(HELP_URLS[page]));
        }
        catch (Exception e)
        {
            ToyPopup.askUser(
                this,
                "Failed Help Request",
                "Visual X-TOY cannot open the site\n" +
                "\tPlease open up the Visual X-TOY site on your browser to view the " +
                "requested page.  (This happens if the applet doesn't have permissions " +
                "or if the launch page used to start this window isn't currently open)",
                "OK"
                );
        }
    }

    /**
     * Go through whatever steps are necessary to change from wone workspace to
     * another.
     * @param newWorkspace the index of the new workspace to switch to
     */
    public void changeWorkspace(int newWorkspace)
    {
        if (newWorkspace >= 0 && newWorkspace < workspace.length)
        {
            //save changes made in editing mode
            if (mode == EDIT)
                editPanel.refresh();

            //ask if the user wants to save changes made in sim mode
            if (mode == SIM)
                simSaveRequest();

            //update the menu items
            if (mode != NULL)
                workspaceMenu.getItem(currentWorkspace).setEnabled(true);
            workspaceMenu.getItem(newWorkspace).setEnabled(false);
            currentWorkspace = newWorkspace;

            if (mode != SIM)
                changeMode(EDIT);
            else
                changeMode(SIM);
        }
        else
            changeMode(NULL);
    }

    /**
     * Ask the user if he wants to save changes made in Sim mode.  This function
     * is called by changeWorkspace() and changeMode() if the relevant
     * conditions are satisfied.
     *
     * @see #changeWorkspace(int)
     * @see #changeMode(int)
     */
    public void simSaveRequest()
    {
        if (workspace[currentWorkspace].memChanged())
        {
            if (ToyPopup.askUser(
                    this,
                    "von Neumann Architecture Support",
                    "Changes to your program have been made in Sim mode\n" +
                    "\tYour program has somehow been modified in Sim mode (either by " +
                    "pressing the load button or by the execution of the \"store\" " +
                    "operatior).  Do you wish to use these changes?  Since coding " +
                    "is typically done in Edit mode, it is recommended that you " +
                    "answer \"No\" to this question.",
                    "Yes",
                    "No"
                    )
                )
                workspace[currentWorkspace].setText(
                    workspace[currentWorkspace].getModifiedText(),
                    false
                    );
        }
    }

    /**
     * This function is identical to a call to changeMode(mode).
     * @see #changeMode(int)
     */
    public void changeMode()
    {
        changeMode(mode);
    }

    /**
     * Changes the mode and updates all components accordingly.
     * @param newMode the index of the new mode to change to.
     * @see #changeMode()
     */
    public void changeMode(int newMode)
    {
        //save changes made in editing mode
        if (mode == EDIT && newMode != EDIT)
            editPanel.refresh();

        //ask if the user wants to save changes made in sim mode
        if (mode == SIM && newMode != SIM)
            simSaveRequest();

        //make sure that users can't go to any other mode but edit if the text
        //has a fatal error
        if (newMode != NULL && newMode != EDIT &&
            workspace[currentWorkspace].hasFatalError())
        {
            ToyPopup.askUser(
                this,
                "Error",
                "Visual X-TOY cannot parse your program.\n" +
                "\tBecause your program has fatal syntactical errors, Visual X-TOY is " +
                "unable to run or step through your program, please correct these " +
                "errors before continuing.",
                "OK"
                );

            //don't make sure that we stay in editing mode
            newMode = EDIT;
        }

        //make the correct button selected
        titlePanel.setSelectedIndex(newMode);

        //make the correct panel visible
        titlePanel.setVisible(newMode != NULL);
        cardPanel.setVisible(newMode != NULL);

        if (newMode == EDIT)
            cardLayout.show(cardPanel, "Edit Mode");
        if (newMode == DEBUG)
            cardLayout.show(cardPanel, "Debug Mode");
        if (newMode == SIM)
            cardLayout.show(cardPanel, "Sim Mode");

        //Now change the mode
        mode = newMode;

        //Enable/Disable the mode memnu items based on the mode
        fileMenu.getItem(3).setEnabled(newMode != NULL); //Close
        fileMenu.getItem(4).setEnabled(newMode != NULL); //Revert
        fileMenu.getItem(5).setEnabled(newMode != NULL && ToyToolkit.hasFilePermissions()); //Save
        fileMenu.getItem(6).setEnabled(newMode != NULL && ToyToolkit.hasFilePermissions()); //Save As

        editMenu.getItem(0).setEnabled(newMode == EDIT); //Undo
        editMenu.getItem(1).setEnabled(newMode == EDIT); //Redo

        modeMenu.getItem(0).setEnabled(newMode != EDIT  && newMode != NULL); //Edit
        modeMenu.getItem(1).setEnabled(newMode != DEBUG && newMode != NULL); //Debug
        modeMenu.getItem(2).setEnabled(newMode != SIM   && newMode != NULL); //Sim

        modeMenu.getItem(4).setEnabled(newMode == DEBUG || newMode == SIM); //Step
        modeMenu.getItem(5).setEnabled(newMode == DEBUG || newMode == SIM); //Run
        modeMenu.getItem(6).setEnabled(newMode == DEBUG || newMode == SIM); //Reset

        toolsMenu.getItem(0).setEnabled(newMode == EDIT); //insertFunctionComment
        toolsMenu.getItem(1).setEnabled(newMode == EDIT); //appendUpdateCommments
        toolsMenu.getItem(2).setEnabled(newMode == EDIT); //reformatCode

        switch (newMode)
        {
            case EDIT:
                editPanel.setWorkspace(workspace[currentWorkspace]);
                break;

            case DEBUG:
                debugPanel.setWorkspace(workspace[currentWorkspace]);
                break;

            case SIM:
                simPanel.setWorkspace(workspace[currentWorkspace]);
                break;
        }
    }

    /**
     * A function called by the constructor (just to split things up).
     * @see #ToyFrame(java.applet.Applet, toy.ToyParameterManager, toy.image.ToyImageManager)
     */
    private void initializeDialogClasses() throws Exception
    {
        //Set the colors and the layout for this frame
        setBackground(new Color(52, 64, 76));
        setForeground(new Color(255, 255, 255));
        setLayout(new BorderLayout());

        focusManager = new ToyFocusManager();

        ////////////////////////////////////////////////////////////////////////
        //The menu bar
        setMenuBar(new MenuBar());

        ////////////////////////////////////////////////////////////////////////
        //The file menu
        fileMenu = new Menu("File");
        getMenuBar().add(fileMenu);
        {
            fileMenu.add(
                new MenuItem(
                    "New",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_N)
                    )
                );
            fileMenu.getItem(0).addActionListener(this);

            fileMenu.add(
                new MenuItem(
                    "Open...",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_O)
                    )
                );
            fileMenu.getItem(1).addActionListener(this);
            fileMenu.getItem(1).setEnabled(ToyToolkit.hasFilePermissions());

            fileMenu.add(
                new MenuItem(
                    "Open Example Program...",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_E)
                    )
                );
            fileMenu.getItem(2).addActionListener(this);
            fileMenu.getItem(2).setEnabled(parameterManager.getExamplePrograms().length > 0);

            fileMenu.add(new MenuItem("Close"));
            fileMenu.getItem(3).addActionListener(this);

            fileMenu.add(new MenuItem("Revert"));
            fileMenu.getItem(4).addActionListener(this);

            fileMenu.add(
                new MenuItem(
                    "Save",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_S)
                    )
                );
            fileMenu.getItem(5).addActionListener(this);
            fileMenu.getItem(5).setEnabled(ToyToolkit.hasFilePermissions());

            fileMenu.add(
                new MenuItem(
                    "Save As...",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_S, true)
                    )
                );
            fileMenu.getItem(6).addActionListener(this);
            fileMenu.getItem(6).setEnabled(ToyToolkit.hasFilePermissions());

            fileMenu.addSeparator();

            fileMenu.add(
                new MenuItem(
                    "Quit",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_Q)
                    )
                );
            fileMenu.getItem(8).addActionListener(this);
        }

        ////////////////////////////////////////////////////////////////////////
        //Edit menu
        editMenu = new Menu("Edit");
        getMenuBar().add(editMenu);
        {
            editMenu.add(
                new MenuItem(
                    "Undo",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_Z)
                    )
                );

            editMenu.add(
                new MenuItem(
                    "Redo",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_Y)
                    )
                );

            editMenu.addSeparator();

            editMenu.add(
                new MenuItem(
                    "Cut",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_X)
                    )
                );
            editMenu.getItem(3).addActionListener(this);
            editMenu.getItem(3).setEnabled(ToyToolkit.hasClipboardPermissions());

            editMenu.add(
                new MenuItem(
                    "Copy",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_C)
                    )
                );
            editMenu.getItem(4).addActionListener(this);
            editMenu.getItem(4).setEnabled(ToyToolkit.hasClipboardPermissions());

            editMenu.add(
                new MenuItem(
                    "Paste",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_V)
                    )
                );
            editMenu.getItem(5).addActionListener(this);
            editMenu.getItem(5).setEnabled(ToyToolkit.hasClipboardPermissions());

            editMenu.addSeparator();

            editMenu.add(
                new MenuItem(
                    "Select All",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_A)
                    )
                );
            editMenu.getItem(7).addActionListener(this);
        }

        ////////////////////////////////////////////////////////////////////////
        //Mode menu
        modeMenu = new Menu("Mode");
        getMenuBar().add(modeMenu);
        {
            modeMenu.add(new MenuItem("Edit"));
            modeMenu.getItem(0).addActionListener(this);

            modeMenu.add(new MenuItem("Debug"));
            modeMenu.getItem(1).addActionListener(this);

            modeMenu.add(new MenuItem("Sim"));
            modeMenu.getItem(2).addActionListener(this);

            modeMenu.addSeparator();

            modeMenu.add(new MenuItem("Step"));

            modeMenu.add(new MenuItem("Run"));

            modeMenu.add(new MenuItem("Reset"));
        }

        ////////////////////////////////////////////////////////////////////////
        //Workspace menu
        workspaceMenu = new Menu("Workspace");
        getMenuBar().add(workspaceMenu);
        {
            for (int ctr = 0; ctr < workspace.length; ctr++)
            {
                workspaceMenu.add(workspace[ctr].getName());
                workspaceMenu.getItem(ctr).addActionListener(this);
            }
        }

        ////////////////////////////////////////////////////////////////////////
        //Tools menu
        toolsMenu = new Menu("Tools");
        getMenuBar().add(toolsMenu);
        {
            toolsMenu.add(new MenuItem("Insert Function Comment"));

            toolsMenu.add(
                new MenuItem(
                    "Append/Update Comments",
                    new MenuShortcut(java.awt.event.KeyEvent.VK_D)
                    )
                );

            toolsMenu.add(new MenuItem("Reformat Code"));

            autoCommentCheckbox = new CheckboxMenuItem("Auto-Comment");
            toolsMenu.add(autoCommentCheckbox);
            autoCommentCheckbox.setState(
                !"false".equals(parameterManager.getParameter("autoComment"))
                );

            toolsMenu.addSeparator();

            highlightingCheckbox = new CheckboxMenuItem("Syntax Highlighting");
            toolsMenu.add(highlightingCheckbox);
            highlightingCheckbox.setState(
                !"false".equals(parameterManager.getParameter("syntaxHighlighting"))
                );

            warningCheckbox = new CheckboxMenuItem("Compiler Warnings");
            toolsMenu.add(warningCheckbox);
            warningCheckbox.setState(
                !"false".equals(parameterManager.getParameter("compilerWarnings"))
                );

            toolsMenu.addSeparator();

            uninitializedErrorCheckbox = new CheckboxMenuItem("Uninitialized Variable Errors");
            toolsMenu.add(uninitializedErrorCheckbox);
            uninitializedErrorCheckbox.setState(
                !"false".equals(parameterManager.getParameter("uninitializedError"))
                );

            overflowErrorCheckbox = new CheckboxMenuItem("Overflow Errors");
            toolsMenu.add(overflowErrorCheckbox);
            overflowErrorCheckbox.setState(
                !"false".equals(parameterManager.getParameter("overflowError"))
                );

            outOfBoundsErrorCheckbox = new CheckboxMenuItem("Out of Bounds Errors");
            toolsMenu.add(outOfBoundsErrorCheckbox);
            outOfBoundsErrorCheckbox.setState(
                !"false".equals(parameterManager.getParameter("outOfBoundsError"))
                );

            closeExecutionCheckbox = new CheckboxMenuItem("Close Execution Dialog When Done");
            toolsMenu.add(closeExecutionCheckbox);
            closeExecutionCheckbox.setState(
                !"false".equals(parameterManager.getParameter("closeExecutionDialog"))
                );
        }

        ////////////////////////////////////////////////////////////////////////
        //Help menu
        helpMenu = new Menu("Help");
        getMenuBar().add(helpMenu);
        {
            helpMenu.add(new MenuItem("I. Before You Start"));
            helpMenu.getItem(0).addActionListener(this);
            helpMenu.getItem(0).setEnabled(parentApplet != null);

            helpMenu.add(new MenuItem("II. Applet Launch Page"));
            helpMenu.getItem(1).addActionListener(this);
            helpMenu.getItem(1).setEnabled(parentApplet != null);

            helpMenu.add(new MenuItem("III. The TOY Language"));
            helpMenu.getItem(2).addActionListener(this);
            helpMenu.getItem(2).setEnabled(parentApplet != null);

            helpMenu.add(new MenuItem("IV. The TOY Machine vs. the TOY IDE"));
            helpMenu.getItem(3).addActionListener(this);
            helpMenu.getItem(3).setEnabled(parentApplet != null);

            helpMenu.add(new MenuItem("V. The TOY Compiler vs. the TOY IDE"));
            helpMenu.getItem(4).addActionListener(this);
            helpMenu.getItem(4).setEnabled(parentApplet != null);

            helpMenu.add(new MenuItem("VI. Frequently Asked Questions"));
            helpMenu.getItem(5).addActionListener(this);
            helpMenu.getItem(5).setEnabled(parentApplet != null);
        }
        getMenuBar().setHelpMenu(helpMenu);

        ////////////////////////////////////////////////////////////////////////
        // Title Panel
        titlePanel = new ToyTitlePanel(
            focusManager,
            imageManager
            );
        titlePanel.addItemListener(this);
        add(
            titlePanel,
            "North"
            );


        ////////////////////////////////////////////////////////////////////////
        // The mode panels
        cardLayout = new CardLayout(5, 5);
        cardPanel = new Panel(cardLayout);
        cardPanel.setBackground(new Color(80, 100, 120));
        add(
            cardPanel,
            "Center"
            );
        {
            editPanel = new ToyEditPanel(
                focusManager,
                autoCommentCheckbox,
                highlightingCheckbox,
                warningCheckbox,
                editMenu.getItem(0),
                editMenu.getItem(1),
                toolsMenu.getItem(0),
                toolsMenu.getItem(1),
                toolsMenu.getItem(2)
                );
            cardPanel.add(editPanel, "Edit Mode");

            debugPanel = new ToyDebugPanel(
                focusManager,
                imageManager,
                uninitializedErrorCheckbox,
                overflowErrorCheckbox,
                outOfBoundsErrorCheckbox,
                closeExecutionCheckbox,
                modeMenu.getItem(4),
                modeMenu.getItem(5),
                modeMenu.getItem(6)
                );
            cardPanel.add(debugPanel, "Debug Mode");

            simPanel = new ToySimPanel(
                focusManager,
                imageManager,
                closeExecutionCheckbox,
                modeMenu.getItem(4),
                modeMenu.getItem(5),
                modeMenu.getItem(6)
                );
            cardPanel.add(simPanel, "Sim Mode");
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Implement ActionListener
    public void actionPerformed(ActionEvent e)
    {
        if (e.getSource() == fileMenu.getItem(0))
            newRequest();
        if (e.getSource() == fileMenu.getItem(1))
            openRequest();
        if (e.getSource() == fileMenu.getItem(2))
            openExampleRequest();
        if (e.getSource() == fileMenu.getItem(3))
            closeRequest();
        if (e.getSource() == fileMenu.getItem(4))
            revertRequest();
        if (e.getSource() == fileMenu.getItem(5))
            saveRequest();
        if (e.getSource() == fileMenu.getItem(6))
            saveAsRequest();
        if (e.getSource() == fileMenu.getItem(8))
            quitRequest();

        if (e.getSource() == editMenu.getItem(3))
            cutRequest();
        if (e.getSource() == editMenu.getItem(4))
            copyRequest();
        if (e.getSource() == editMenu.getItem(5))
            pasteRequest();
        if (e.getSource() == editMenu.getItem(7))
            selectAllRequest();

        if (e.getSource() == modeMenu.getItem(0))
            changeMode(EDIT);
        if (e.getSource() == modeMenu.getItem(1))
            changeMode(DEBUG);
        if (e.getSource() == modeMenu.getItem(2))
            changeMode(SIM);

        for (int ctr = 0; ctr < workspaceMenu.getItemCount(); ctr++)
            if (e.getSource() == workspaceMenu.getItem(ctr))
                changeWorkspace(ctr);

        for (int ctr = 0; ctr < helpMenu.getItemCount(); ctr++)
            if (e.getSource() == helpMenu.getItem(ctr))
                helpRequest(ctr);
    }

    /**
     * Implement the ItemListener interface to recieve events from the
     * titlePanel.
     */
    public void itemStateChanged(ItemEvent e)
    {
        if (e.getSource() == titlePanel)
            changeMode(((Integer)e.getItem()).intValue());
    }

    /**
     * Listen to window events so that WindowEvent.WINDOW_CLOSING can be
     * processed.
     */
    public void processWindowEvent(WindowEvent e)
    {
        //quit when the user wants to exit
        if (e.getID() == WindowEvent.WINDOW_CLOSING)
            quitRequest();

        super.processWindowEvent(e);
    }

    /**
     * Listen to component events so that we can enforce the minimum bounds of
     * the window.
     */
    public void processComponentEvent(ComponentEvent e)
    {
        //enforce a minimum size
        if (e.getID() == ComponentEvent.COMPONENT_RESIZED)
        {
            Dimension size = getSize();
            boolean resized = false;

            if (size.width < MIN_WIDTH)
            {
                size.width = MIN_WIDTH;
                resized = true;
            }

            if (size.height < MIN_HEIGHT)
            {
                size.height = MIN_HEIGHT;
                resized = true;
            }

            if (resized)
            {
                setSize(size);
                doLayout();
            }
        }

        super.processComponentEvent(e);
    }
}

