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

/**
 * ConfigureDemo brings up a simple button editor which allows 
 * the user to configure the appearance of a JPanel which is
 * passed as an argument to its constructor.  These changes are
 * for the session only, and will not be saved anywhere.  
 *
 * When the static method main() is run, an instance of ConfigureDemo
 * is created, as well as a SquarePuzzle and SquarePuzzleDisplay.
 * The SquarePuzzleDisplay is used in the construction of the ConfigureDemo
 * instance.  This code demonstrates several important features:
 *   (1) ConfigureDemo doesn't know anything about the internal structure
 *       of the JPanel being edited.  It simply listens for events
 *       generated by AbstractButtons on the JPanel.
 *   (2) When a user clicks on a button in the SquarePuzzle, the
 *       generated ActionEvent is heard both by the ConfigureDemo,
 *       which sets theComponent appropriately, and also by the
 *       Translation component of SquarePuzzle (which, in this case,
 *       consists of a single actionPerformed() method in 
 *       SquarePuzzleDisplay.java).  Consequently, the editing can
 *       potentially go on at the same time as the use of the JPanel.
 *   (3) ConfigureDemo doesn't notice when something else undoes
 *       its configurations.  For instance, the SquarePuzzle resets
 *       the Text fields of the TileButtons of the SquarePuzzleDisplay
 *       after each attempt to slide a tile.  This would be a drawback
 *       for many applications, and a feature for many others.
 *   (4) actionPerformed() is not careful about verifying the source of
 *       the ActionEvents it receives.  For example, any component
 *       which has an attached ActionCommand "Quit" will cause the 
 *       program to exit, not just the Quit menu.  This would cause
 *       problems if the given JPanel contains a Quit button, to
 *       which we wanted to attach an icon.
 *       Also, if an ActionEvent is generated which does not come
 *       from an AbstractButton, our program will generate errors.
 *       This is because our actionPerformed() function does not
 *       check to make sure every ActionEvent comes from an
 *       AbstractButton, but <b>assumes</b> so anyway.
 * Do not use this code as a model for good program design.  It is
 * intended to illustrate only the following:
 *   
 */

public class ConfigureDemo extends JFrame implements ActionListener {
    
    protected AbstractButton theComponent;  // most recently selected editable component.
    
    /**
     * newMI creates a new MenuItem with given Text string,
     * adds it to the given Menu, registers the ConfigureDemo
     * as ActionListener for the MenuItem, and returns the new
     * MenuItem (in case further customization is desired).
     */
    
    protected JMenuItem newMI(JMenu m, String newMenuItemText) {
        JMenuItem mi = new JMenuItem(newMenuItemText);
        mi.addActionListener(this);
        m.add(mi);
        return mi;
    }
    
    /**
     * A slight enhancement to the previous newMI.
     */

    protected JMenuItem newMI(JMenu m, String newMenuItemText, String iconFileName) {
        JMenuItem mi = newMI(m,newMenuItemText);
        mi.setIcon(new ImageIcon(iconFileName));
        return mi;
    }

    /**
     * Creates and configures the MenuBar.
     * Called by the ConfigureDemo constructor.
     * Note the use of this method and the newMI method
     * to reduce clutter in the source code.
     */

    protected void menuSetUp() {
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);
        
        JMenu menu = new JMenu("Configure");
        menuBar.add(menu);

        JMenu iconMenu = new JMenu("Icon");
        menu.add(iconMenu);
       
        newMI(iconMenu,"icon1.gif","images/icon1.gif");
        newMI(iconMenu,"icon2.gif","images/icon2.gif");
        newMI(iconMenu,"icon3.gif","images/icon3.gif");
        newMI(iconMenu,"icon4.gif","images/icon4.gif");

        newMI(menu,"Text").setAccelerator(KeyStroke.getKeyStroke(                                                 KeyEvent.VK_T, ActionEvent.ALT_MASK));

        JMenu bgMenu = new JMenu("Background");
        menu.add(bgMenu);
        
        newMI(bgMenu,"Color.blue").setBackground(Color.blue);
        newMI(bgMenu,"Color.blue").setBackground(Color.white);
        
        newMI(menu,"Quit").setAccelerator(KeyStroke.getKeyStroke(
                                KeyEvent.VK_Q, ActionEvent.ALT_MASK));
    }

    /**
     * Creates a new Frame with a configuration menu, and
     * a contentPane with contains targetPanel.  ConfigureDemo
     * registers as an ActionListener with targetPanel (which in 
     * turn should call the addActionListener() method
     * of each of targetPanel's GUI components). ConfigureDemo
     * uses the ActionEvents it receives to decide which
     * component is being edited.  
     */
    public ConfigureDemo(ActionPanel targetPanel) {
        menuSetUp();
        targetPanel.addActionListener(this);
        getContentPane().add(targetPanel);
        pack();
        setVisible(true);
    }
    
    /**
     * Creates a new ConfigureDemo with a SquarePuzzleDisplay
     * as its targetPanel.  The SquarePuzzleDisplay also actively
     * displays a SquarePuzzle backend, so that the user can
     * run the display and edit it at the same time.
     */
    static public void main(String[] args) {
        
        SquarePuzzle puzz = new SquarePuzzle(4,4);
        ActionPanel display = (ActionPanel)(new SquarePuzzleDisplay(puzz));
        JFrame f = new ConfigureDemo(display);
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }});
    }
    
    /*
     * Handle ActionEvents generated by the MenuItems established
     * by menuSetUp(), and also any events generated by targetPanel.
     * All such events are assumed to be generated by AbstractButtons
     * (a defect).
     */

    public void actionPerformed(ActionEvent e) {
        String s = e.getActionCommand();
        if (s != null) {
            if (s.equals("Text")) {
                String newText = JOptionPane.showInputDialog(this,"Enter new text for selected component.");
                if (newText != null) {
                    theComponent.setText(newText);
                    this.pack(); // make display reflect possible size change.
                }
            }
            else if (s.equals("Icon")) {
            }
            else if (s.equals("Component")) {}
            else if (s.equals("Quit")){System.exit(0);}
            else if (s.startsWith("icon")) {
                theComponent.setIcon(((JMenuItem)e.getSource()).getIcon());
                this.pack(); // make display reflect possible size change.
            }
            else if (s.startsWith("Color")) {
                theComponent.setBackground(((JMenuItem)e.getSource()).getBackground());
            }
            else // Not one of our menu items.  Must be from targetPanel.
                {
                    theComponent = (AbstractButton)e.getSource();
                }
        }
        else  // No ActionCommand.  Must be from targetPanel.
            {
                theComponent = (AbstractButton)e.getSource();
            }
    }
}


