/**
 *  AddressBookGUI.java
 *
 *  Copyright (c) 2000, 2001, 2005, 2006 - Russell C. Bjork
 *
 */
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.IOException;

/** An object of this class allows interaction between the program and the 
 *  human user.
 */
public class AddressBookGUI extends JFrame
{
    /** Constructor
     *
     *  @param controller the controller which performs operations in
     *         response to user gestures on this GUI
     *  @param addressBook the AddressBook this GUI displays
     */

    public AddressBookGUI(final AddressBookController controller,
                          AddressBook addressBook)
    {
        this.controller = controller;
        
         // Create and add file menu
        
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        newItem = new JMenuItem("New", 'N');
        fileMenu.add(newItem);
        openItem = new JMenuItem("Open...", 'O');
        fileMenu.add(openItem);
        fileMenu.addSeparator();
        saveItem = new JMenuItem("Save", 'S');
        fileMenu.add(saveItem);
        saveAsItem = new JMenuItem("Save As...");
        fileMenu.add(saveAsItem);
        fileMenu.addSeparator();
        printItem = new JMenuItem("Print", 'P');
        fileMenu.add(printItem);
        fileMenu.addSeparator();
        quitItem = new JMenuItem("Quit", 'Q');
        fileMenu.add(quitItem);
        menuBar.add(fileMenu);
        setJMenuBar(menuBar);
        
       // Create and add components for the main window
        
        nameList = new JList();
        nameList.setPrototypeCellValue("ABCDEFGHIJKLM, NOPQRSTUVWXYZ");
        nameList.setVisibleRowCount(10);
        JScrollPane listPane = new JScrollPane(nameList);
        listPane.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createEmptyBorder(10, 10, 10, 10), 
            BorderFactory.createLineBorder(Color.gray, 1)));
        getContentPane().add(listPane, BorderLayout.CENTER);
        JPanel buttonPanel = new JPanel();
        addButton = new JButton("     Add    ");
        buttonPanel.add(addButton);
        editButton = new JButton("    Edit    ");
        buttonPanel.add(editButton);
        deleteButton = new JButton("   Delete   ");
        buttonPanel.add(deleteButton);
        sortByNameButton = new JButton("Sort by name");
        buttonPanel.add(sortByNameButton);
        sortByZipButton = new JButton("Sort by ZIP ");
        buttonPanel.add(sortByZipButton);
        buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 10, 10));
        
        getContentPane().add(buttonPanel, BorderLayout.SOUTH);
        
        // Add the action listeners for the buttons, menu items, and close box,
        // and for double-clicking the list
        
        addButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                controller.doAdd(AddressBookGUI.this);
                // This will ensure that the person just added is visible in list
                int index = getAddressBook().size() - 1;
                nameList.invalidate();
                nameList.ensureIndexIsVisible(index);
                saveItem.setEnabled(AddressBookGUI.this.addressBook.
                	getChangedSinceLastSave());
            }
        });
          
        editButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                int index = nameList.getSelectedIndex();
                if (index < 0)
                    reportError("You must select a person");
                else
                {
                    controller.doEdit(AddressBookGUI.this, index);
                    saveItem.setEnabled(AddressBookGUI.this.addressBook.
                    	getChangedSinceLastSave());
                }               
            }
        });
          
        deleteButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            { 
                int index = nameList.getSelectedIndex();
                if (index < 0)
                    reportError("You must select a person");
                else
                {
                    controller.doDelete(AddressBookGUI.this, index);
                    nameList.repaint();
                    saveItem.setEnabled(AddressBookGUI.this.addressBook.
                    	getChangedSinceLastSave());
                }
            }
        });
        
        sortByNameButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            { 
                controller.doSortByName(AddressBookGUI.this);
                nameList.repaint();
                saveItem.setEnabled(AddressBookGUI.this.addressBook.
                	getChangedSinceLastSave());
            }
        });
              
        sortByZipButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            { 
                controller.doSortByZip(AddressBookGUI.this);
                nameList.repaint();
                saveItem.setEnabled(AddressBookGUI.this.addressBook.
                	getChangedSinceLastSave());
            }
        });
        
        newItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            { 
                try
                {
                    if (getAddressBook().getChangedSinceLastSave())
                        controller.doOfferSaveChanges(AddressBookGUI.this);
                
                    controller.doNew(AddressBookGUI.this);
                }
                catch(IOException exception)
                {
                    reportError("Problem writing the file: " +
                                 exception);
                }
                catch(InterruptedException exception)
                {
                    // Thrown if user cancels a save or a file dialog - can be ignored
                }
                catch(SecurityException exception)
                {
                    // Thrown if security manager disallows the operation -
                    // will always happen in an applet
                    
                    reportError("Operation disallowed: " + exception);
                }
            }
        });
            
        openItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                try
                {
                    if (getAddressBook().getChangedSinceLastSave())
                        controller.doOfferSaveChanges(AddressBookGUI.this);
                
                    controller.doOpen(AddressBookGUI.this);
                }
                catch(IOException exception)
                {
                    reportError("Problem reading or writing the file: " +
                                 exception);
                }
                catch(InterruptedException exception)
                {
                    // Thrown if user cancels a save or a file dialog - can be ignored
                }
                catch(SecurityException exception)
                {
                    // Thrown if security manager disallows the operation -
                    // will always happen in an applet
                    
                    reportError("Operation disallowed: " + exception);
                }
                catch(Exception exception)
                {
                    // Any other case means the file did not contain an
                    // address book

                    reportError("This file did not contain an address book");
                }   
            }
        });
            
       saveItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            { 
                try
                {
                    controller.doSave(AddressBookGUI.this);
                    saveItem.setEnabled(AddressBookGUI.this.addressBook.
                    	getChangedSinceLastSave());
                }
                catch(IOException exception)
                {
                    reportError("Problem writing the file: " +
                                 exception);
                } 
                catch(InterruptedException exception)
                {
                    // Thrown if user cancels a file dialog - can be ignored
                }
                catch(SecurityException exception)
                {
                    // Thrown if security manager disallows the operation -
                    // will always happen in an applet
                    
                    reportError("Operation disallowed: " + exception);
                }
            }
        });
            
        saveAsItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            { 
                try
                {
                    controller.doSaveAs(AddressBookGUI.this);
                    saveItem.setEnabled(AddressBookGUI.this.addressBook.
                    	getChangedSinceLastSave());
                }
                catch(IOException exception)
                {
                    reportError("Problem writing the file: " +
                                 exception);
                } 
                catch(InterruptedException exception)
                {
                    // Thrown if user cancels a file dialog - can be ignored
                }
                catch(SecurityException exception)
                {
                    // Thrown if security manager disallows the operation -
                    // will always happen in an applet
                    
                    reportError("Operation disallowed: " + exception);
                }
            }
        });
            
        printItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            { 
                controller.doPrint(AddressBookGUI.this);
            }
        });
            
        quitItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            { 
                AddressBookApplication.quitApplication();
            }
        });
            
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e)
            { 
                try
                {
                    if (getAddressBook().getChangedSinceLastSave())
                        controller.doOfferSaveChanges(AddressBookGUI.this);

                    dispose();
                    
                    if (Frame.getFrames().length == 0)
                        AddressBookApplication.quitApplication();
                }
                catch(IOException exception)
                {
                    reportError("Problem writing the file: " +
                                 exception);
                } 
                catch(InterruptedException exception)
                {
                    // Thrown if user cancels a file dialog - can be ignored
                }
                catch(SecurityException exception)
                {
                    // Thrown if security manager disallows the operation -
                    // will always happen in an applet
                    
                    reportError("Operation disallowed: " + exception);
                }
                
            }
        });
        
        // The following is adapted from an example in the documentation
        // for class JList.  It invokes the controller's doEdit method
        // if the user double clicks a name.
        
        nameList.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) 
            {
                if (e.getClickCount() == 2) 
                {
                    int index = nameList.locationToIndex(e.getPoint());
                    controller.doEdit(AddressBookGUI.this, index);
                }
            }
        });
        
        setAddressBook(addressBook);    
        
        pack();     
    }
    
    /** Accessor for the address book this GUI displays
     *
     *  @return the current address book for this GUI
     */
    public AddressBook getAddressBook()
    {
        return addressBook;
    }
    
    /** Mutator to change the address book this GUI displays
     *
     *  @param addressBook the new address book for this GUI
     */
    public void setAddressBook(AddressBook addressBook)
    {           
        this.addressBook = addressBook;
        setTitle(addressBook.getTitle());
        saveItem.setEnabled(addressBook.getChangedSinceLastSave());
        nameList.setListData(addressBook);
    }
    
    /** Report an error to the user
     *
     *  @param message the message to display
     */
    public void reportError(String message)
    {
        JOptionPane.showMessageDialog(this, message, "Error message",
                                      JOptionPane.ERROR_MESSAGE);
    }
                
    // The controller that performs operations in response to user gestures
    
    private AddressBookController controller;
    
    // The address book this GUI displays / operates on
    
    private AddressBook addressBook;
    
    // GUI components and menu items
    
    private JList nameList;
    private JButton addButton, editButton, deleteButton, sortByNameButton, sortByZipButton;
    private JMenuItem newItem, openItem, saveItem, saveAsItem, printItem, quitItem; 
}
