import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.awt.Image;
import javax.swing.*;


/**
 * n-puzzle with sliding images
 * 
 * @author Owen Astrachan
 */
public class PuzzleApplet extends JApplet implements PuzzleView
{
    private static final int OUR_WIDTH = 500;
    private static final int OUR_HEIGHT = 500;
    private static final String OUR_DEFAULT_IMAGE = "ola.gif";
    private static final int OUR_DEFAULT_GRID = 5;

    private PuzzleController myControl;
    private PuzzleModel myModel;
    private JTextField myText;
    private ButtonPanel myButtonPanel;
    private JButton myUndo;

    
    public void init ()
    {
        myControl = new PuzzleController();
        doInitialize(new PuzzleModel(myControl, getNumDivisions()),
                     getImageName());
    }


    /**
     * Create a gui with a model and an image (image optional)
     * 
     * @param imageSource is null or the url/file for an image
     * @param model is the model for this view
     */
    public void doInitialize (PuzzleModel model, String imageSource)
    {
        JPanel panel = new JPanel(new BorderLayout());

        myControl.addView(this);
        myModel = model;
        myUndo = new JButton("undo");
        myUndo.addActionListener(new ActionListener()
            {
                public void actionPerformed (ActionEvent e)
                {
                    myControl.undoMove();
                }
            });
        setEnabledUndo(false);

        myText = new JTextField(20);
        myButtonPanel = new ButtonPanel(myModel.getSize(), imageSource);
        panel.add(myButtonPanel, BorderLayout.CENTER);
        panel.add(myText, BorderLayout.SOUTH);
        panel.add(myUndo, BorderLayout.NORTH);

        setContentPane(panel);
        setVisible(true);
    }

    public void showText (String text)
    {
        myText.setText(text);
    }

    public void setEnabledUndo (boolean value)
    {
        myUndo.setEnabled(value);
    }

    public void showGrid (int[] list)
    {
        myButtonPanel.setGrid(list);
    }

    private String getImageName ()
    {
        // allow user to give puzzle image in HTML file
        String puzzleName = getParameter("image");
        if (puzzleName == null)
        {
            puzzleName = OUR_DEFAULT_IMAGE;
        }
        return puzzleName;
    }

    private int getNumDivisions ()
    {
        // allow user to give puzzle image in HTML file
        int gridSize = 2;
        try
        {
            gridSize = Integer.parseInt(getParameter("divisions"));
        }
        catch (Exception e)
        {
            gridSize = OUR_DEFAULT_GRID;
        }
        return gridSize;
    }


    class ButtonPanel extends JPanel
    {
        private JButton myButtons[];

        /**
         * Create a button panel consisting of nButtons per side of a square
         * (total # buttons is nButtons*nButtons) using the designated
         * imageSource (if not null).
         * 
         * @param nButtons is the number of buttons PER SIDE
         * @param imageSource is the source of the image for this panel
         */

        ButtonPanel (int nButtons, String imageSource)
        {
            // construct superclass and make button array
            super(new GridLayout(nButtons, nButtons));
            myButtons = new JButton[nButtons * nButtons];

            // load the image if one is specified
            Image image = null;
            if (imageSource != null)
            {
                image = ImageFactory.getImage(this, imageSource);
            }

            // make listeners for buttons in panel
            // first one to show text in this GUI
            ActionListener textDisplayer = new ActionListener()
                {
                    public void actionPerformed (ActionEvent e)
                    {
                        showText(e.getActionCommand());
                    }
                };

            // make listener to do the move chosen by user
            ActionListener moveMaker = new ActionListener()
                {
                    public void actionPerformed (ActionEvent e)
                    {
                        int val = Integer.parseInt(e.getActionCommand());
                        myControl.makeMove(new PuzzleMove(val));
                    }
                };

            makeButtons(image, textDisplayer, moveMaker);
        }

        /**
         * Makes the buttons for this GUI/view. The number of buttons is
         * determined my the size of the array myButtons. This helper function
         * takes some of the busy work out of the ButtonPanel constructor.
         */
        private void makeButtons (Image image,
                                  ActionListener textDisplayer,
                                  ActionListener moveMaker)
        {
            for (int k = 0; k < myButtons.length; k++ )
            {
                String label = "" + k;
                String iLabel = label;
                if (k == myButtons.length - 1)
                {
                    iLabel = PuzzleConsts.BLANK;
                }
                Icon icon;
                if (image == null)
                {
                    icon = new PlainPuzzleIcon(iLabel, myControl.getModelSize());
                }
                else
                {
                    icon = new ImagePuzzleIcon(image, iLabel,
                                               myControl.getModelSize());
                }
                // create button with icon
                myButtons[k] = new JButton(icon);
                myButtons[k].setActionCommand(label);
                myButtons[k].addActionListener(textDisplayer);
                myButtons[k].addActionListener(moveMaker);
                add(myButtons[k]);
            }
        }

        /**
         * Set all the buttons by re-displaying them all in the right order.
         * First we remove all the components in this panel (that's the
         * buttons). Then we add the buttons to this panel in the right order
         * based on what the ordering of the buttons in the model is. Finally,
         * we revalidate so the buttons are shown (GUI will redraw as a result
         * of the revalidate).
         */
        public void setGrid (int list[])
        {
            removeAll();
            for (int k = 0; k < list.length; k++ )
            {
                add(myButtons[list[k]]);
            }
            revalidate();
        }
    }
}