import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ResourceBundle;


/**
 * Demo program to show many of the awt events that can be generated.
 *
 * Illustrates XXXListeners for consuming several types of events 
 * including semantic events (e.g., ActionEvent) and low-level events 
 * (e.g., FocusEvent)
 *
 * @author Owen Astrachan
 * @author Robert C. Duvall
 */
public class EventDemo extends JFrame
{
    // most GUI components will be temporary variables,
    // only store components you need to refer to later
    private JTextArea  myTextArea;
    private JFileChooser myChooser;
    
    // get strings from resource file
    private ResourceBundle myResources;

    // in this example, the listeners can be reused by many
    // components, so keep track of them
    private ActionListener myActionListener;
    private KeyListener myKeyListener;
    private MouseListener myMouseListener;
    private MouseMotionListener myMouseMotionListener;
    private FocusListener myFocusListener;


    /**
     * Construct the demo with a title that will appear in the 
     * Frame's title bar.
     *
     * Note, this constructor builds the entire GUI and displays
     * it --- leaving nothing for main.  Not necessarily the best
     * practice.
     */
    public EventDemo (String title, String language)
    {
        // set properties of frame
        setTitle(title);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        myChooser = new JFileChooser(".");

        // create and arrange sub-parts of the GUI
        myResources = ResourceBundle.getBundle("resources." + language);
        makeListeners();
        getContentPane().add(makeInput(), BorderLayout.NORTH);
        getContentPane().add(makeDisplay(), BorderLayout.CENTER);
        makeMenus();

        // size and display the GUI
        pack();
        show();
    }


    /**
     * Display any string message in the main text area.
     */
    public void showMessage (String s)
    {
        myTextArea.append(s + "\n");
        myTextArea.setCaretPosition(myTextArea.getText().length());
    }

    /**
     * Display any string message in a popup error dialog.
     */
    public void showError (String s)
    {
        JOptionPane.showMessageDialog(this, s, "Input Error",
                                      JOptionPane.ERROR_MESSAGE);
    }


    /**
     * Create all the listeners so they can be later assigned 
     * to specific components.
     *
     * Note, since these classes will not ever be used by any 
     * other class, make them inline (i.e., as anonymous inner 
     * classes) --- saves making a separate file for one line 
     * of actual code.
     */
    protected void makeListeners ()
    {
        // listener for "high-level" events, i.e., those made
        // up of a sequence of low-level events, like a button 
        // press (mouse down and up within a button object)
        myActionListener = new ActionListener()
            {
                public void actionPerformed (ActionEvent e)
                {
                    echo("action", e);
                }
            };
        // listener for low-level keyboard events
        myKeyListener = new KeyListener()
            {
                public void keyPressed (KeyEvent e)
                {
                    echo("pressed", e);
                }
                public void keyReleased (KeyEvent e)
                {
                    echo("released", e);
                }
                public void keyTyped (KeyEvent e)
                {
                    echo("typed", e);
                }
            };
        // listener for low-level mouse events
        myMouseListener = new MouseListener()
            {
                public void mouseClicked (MouseEvent e)
                {
                    echo("clicked", e);
                }
                public void mouseEntered (MouseEvent e)
                {
                    echo("enter", e);
                }
                public void mouseExited (MouseEvent e)
                {
                    echo("exit", e);
                }
                public void mousePressed (MouseEvent e)
                {
                    echo("pressed", e);
                }
                public void mouseReleased (MouseEvent e)
                {
                    echo("released", e);
                }
            };
        // listener for low-level mouse movement events
        myMouseMotionListener = new MouseMotionListener()
            {
                public void mouseDragged (MouseEvent e)
                {
                    echo("drag", e);
                }
                public void mouseMoved (MouseEvent e)
                {
                    echo("move", e);
                }
            };
        // listener for low-level focus events, i.e., the mouse
        // entering/leaving a component so you can type in it
        myFocusListener = new FocusListener()
            {
                public void focusGained (FocusEvent e)
                {
                    echo("gained", e);
                }
                public void focusLost (FocusEvent e)
                {
                    echo("lost", e);
                }
            };
    }

    /**
     * Create a menu to appear at the top of the frame, usually
     * File, Edit, App Specific Actions, Help
     */
    protected void makeMenus ()
    {
        JMenuBar bar = new JMenuBar();
        bar.add(makeFileMenu());
        setJMenuBar(bar);
    }

    /**
     * Create an input area for the user --- textfield for text,
     * buttons for starting actions
     */
    protected JComponent makeInput ()
    {
        JPanel result = new JPanel();
        result.add(makeTextField());
        result.add(makeButton());
        result.add(makeClear());
        return result;
    }

    /**
     * Create a display area for showing out to the user, since 
     * it may display lots of text, make it automatically scroll
     * when needed
     */
    protected JComponent makeDisplay ()
    {
        myTextArea = new JTextArea(30, 40); // rows and columns
        myTextArea.addMouseListener(myMouseListener);
        myTextArea.addMouseMotionListener(myMouseMotionListener);
        return new JScrollPane(myTextArea);
    }

    /**
     * Create a menu that will pop up when the menu button is
     * pressed in the frame.  File menu usually contains Open,
     * Save, and Exit
     *
     * Note, since these classes will not ever be used by any 
     * other class, make them inline (i.e., as anonymous inner 
     * classes) --- saves making a separate file for one line 
     * of actual code.
     */
    protected JMenu makeFileMenu ()
    {
        JMenu result = new JMenu(myResources.getString("FileMenu"));
        result.add(new AbstractAction(myResources.getString("OpenCommand"))
            {
                public void actionPerformed (ActionEvent e)
                {
                    try
                    {
                        int response = myChooser.showOpenDialog(null);
                        if (response == JFileChooser.APPROVE_OPTION)
                        {
                            echo(new FileReader(myChooser.getSelectedFile()));
                        }
                    }
                    catch (IOException io)
                    {
                        // let user know an error occurred, but keep going
                        showError(io.toString());
                    }
                }
            });
        result.add(new AbstractAction(myResources.getString("SaveCommand"))
            {
                public void actionPerformed (ActionEvent e)
                {
                    try
                    {
                        echo(new FileWriter("demo.out"));
                    }
                    catch (IOException io)
                    {
                        // let user know an error occurred, but keep going
                        showError(io.toString());
                    }
                }
            });
        result.add(new JSeparator());
        result.add(new AbstractAction(myResources.getString("QuitCommand"))
            {
                public void actionPerformed (ActionEvent e)
                {
                    // end program
                    System.exit(0);
                }
            });
        return result;
    }


    /**
     * Create a standard text field (a single line that respondes
     * to enter being pressed as an ActionEvent) that listens for 
     * a variety of kinds of events
     */
    protected JTextField makeTextField ()
    {
        JTextField result = new JTextField(30);
        result.addKeyListener(myKeyListener);
        result.addFocusListener(myFocusListener);
        result.addActionListener(myActionListener);
        return result;
    }

    /**
     * Create a standard button (a rectangular area that respondes
     * to mouse press and release within its bounds) that listens 
     * for a variety of kinds of events
     */
    protected JButton makeButton ()
    {
        JButton result = new JButton(myResources.getString("ActionCommand"));
        result.addActionListener(myActionListener);
        result.addKeyListener(myKeyListener);
        result.addMouseListener(myMouseListener);
        return result;
    }

    /**
     * Create a button whose action is to clear the display area
     * when pressed.
     *
     * Note, since this class will not ever be used by any 
     * other class, make it inline (i.e., as anonymous inner 
     * classes) --- saves making a separate file for one line 
     * of actual code.
     */
    protected JButton makeClear ()
    {
        JButton result = new JButton(myResources.getString("ClearCommand"));
        result.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    myTextArea.setText("");
                }
            });
        return result;
    }


    /**
     * Echo key presses by showing important attributes
     */
    private void echo (String s, KeyEvent e)
    {
        showMessage(s + " char:" + e.getKeyChar() + " mod: " +
                    KeyEvent.getKeyModifiersText(e.getModifiers()) +
                    " mod: " + KeyEvent.getKeyText(e.getKeyCode()));
    }

    /**
     * Echo action events including time event occurs
     */
    private void echo (String s, ActionEvent e)
    {
        showMessage(s + " = " + e.getActionCommand() + " " + e.getWhen());
    }

    /**
     * Echo mouse events (enter, leave, etc., including position and buttons)
     */
    private void echo (String s, MouseEvent e)
    {
        showMessage(s + " x = " + e.getX() + " y = " + e.getY() + " mod: "+
                    MouseEvent.getMouseModifiersText(e.getModifiers()) +
                    " button: "+e.getButton() + " clicks " + e.getClickCount());
    }

    /**
     * Echo other events (e.g., Focus)
     */
    private void echo (String s, AWTEvent e)
    {
        showMessage(s + " " + e);
    }

    /**
     * Echo data read from reader to display
     */
    private void echo (Reader r)
    {
        try
        {
            String s = "";
            BufferedReader input = new BufferedReader(r);
            while (true)
            {
                String line = input.readLine();
                if (line != null)   s += line + "\n";
                else                break;
            }
            showMessage(s);
        }
        catch (IOException e)
        {
            showError(e.toString());
        }
    }

    /**
     * Echo display to writer
     */
    private void echo (Writer w)
    {
        PrintWriter output = new PrintWriter(w); 
        output.println(myTextArea.getText());
        output.flush();
        output.close();
    }


    // Java starts the program here
    // program does not end until GUI goes away
    public static void main (String[] args)
    {
        new EventDemo("Event Demo", "Gibberish");
        System.out.println("Hello");
    }
}
