package arrayDisplay;

import java.awt.*;
import java.awt.event.*;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
 * ArrayDisplay provides a simple GUI for displaying an array of Objects
 * (such as Strings), and for displaying messages as appropriate.
 * <p>
 * To use this class, do the following:
 * <ol><li>Define any number of classes that implement <code>Paintable</code>; each
 *         such class must define a
 *         <nobr><code>public void paint(Graphics g, int x, int y,
 *                                       int width, int height)</code></nobr>
 *         method.</li>
 *     <li>Create a two-dimensional array of <code>Paintable</code>, or of some type
 *         that implements <code>Paintable</code>.</li>
 *     <li>Create an <code>ArrayDisplay</code> object, using your array as an argument
 *         to the constructor.</li>
 *     <li>Put some objects (ones that implement Paintable) into your array.
 *         "Empty" locations in the array should be <code>null</code>.</li>
 *     <li>Tell your <code>ArrayDisplay</code> object to <code>repaint()</code>.</li>
 *     <li>Whenever you make changes to the array, and you want it painted again,
 *         call <code>repaint()</code> again.</li>
 * </ol>
 * Example:
 * <pre>class Monster implements Paintable {
 *    public void paint(Graphics g, int x, int y, int width, int height) { ... }
 * ...
 * }
 * class SomeOtherClass {
 *     Monster[][] monsterLand = new Monster[10][10];
 *     ArrayDisplay view = new ArrayDisplay(monsterLand);
 *     ...
 *     monsterLand[i][j] = new Monster(Color.GREEN);
 *     view.repaint();</pre>
 *     
 * 
 * @author David Matuszek
 * @version 3.0
 */
public class ArrayDisplay extends JFrame {

    private static final long serialVersionUID = 1L;
    private Paintable[][] array;
    private Paintable[][] backgroundArray;
    private int rows;
    private int columns;
    private MyPanel mainPanel = new MyPanel();
    private JPanel controlPanel = new JPanel();
    private JButton quitButton = new JButton("Quit");
    private JTextField messageField = new JTextField();
    private final int FONT_SIZE = 18;
    private Font bigFont = new Font("SansSerif", Font.PLAIN, FONT_SIZE);
    private Font plainFont = new Font("Dialog", Font.PLAIN, 12);
    private int ROW_SPACING = FONT_SIZE + 4;
    private int COLUMN_SPACING = FONT_SIZE;

    /**
     * Creates a Frame for displaying the contents of the given array.
     * 
     * @param array The array that is to be displayed.
     */
    public ArrayDisplay(Paintable[][] array) {
        this(array, null);
    }
    
    /**
     * Creates a Frame for displaying the contents of the two given arrays.
     * A "background array" will be painted first, in a lighter color, then
     * the "main" array will be painted on top of it.
     * 
     * @param array The array that is to be displayed in front.
     * @param backgroundArray The array that will be displayed behind
     *                        the first array, in a lighter color.
     */
    public ArrayDisplay(Paintable[][] array, Paintable[][] backgroundArray) {
        this.array = array;
        this.backgroundArray = backgroundArray;
        this.rows = array.length;
        this.columns = array[0].length;
        
        // Create and display GUI
        setTitle("Array Display");
        setSize(COLUMN_SPACING * columns, ROW_SPACING * rows + 50);
        setFont(bigFont);
        messageField.setFont(plainFont);
        quitButton.setFont(plainFont);
        setLayout(new BorderLayout());
        add(mainPanel, BorderLayout.CENTER);
        add(controlPanel, BorderLayout.SOUTH);
        controlPanel.setLayout(new BorderLayout());
        controlPanel.add(messageField, BorderLayout.CENTER);
        controlPanel.add(quitButton, BorderLayout.EAST);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        // Quit gracefully when Quit button is clicked
        quitButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                dispose();
                System.exit(0);
        }});
    }
        
    /**
     * Pauses for one second, then repaints the array.
     */
    public void repaint() {
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        mainPanel.repaint();
    }
    
    /**
     * Displays the given message in the TextField.
     * 
     * @param message The message to be displayed.
     */
    public void displayMessage(String message) {
        messageField.setText(message);
    }
    
    /**
     * An inner class to implement the actual drawing.
     */
    private class MyPanel extends JPanel {
  
        /**
         * Clears this Panel, draws the backgroundArray in light gray
         * then draws the main array on top of it, in black.
         * 
         * @param g The graphics on which the drawing is done.
         */
        public void paint(Graphics g) {
            g.setColor(Color.white);
            g.fillRect(0, 0, getWidth(), getHeight());
            if (backgroundArray !=  null) {
                g.setColor(Color.gray);
                paintArray(g, backgroundArray);
            }
            g.setColor(Color.black);
            paintArray(g, array);
        }
        
        /**
         * Draws the given array in this panel, in the current color.
         */
        public void paintArray(Graphics g, Paintable[][] array) {
            int height = getHeight();
            int width = getWidth();
            for (int row = 0; row < rows; row++) {
                int topEdge = (row * height) / array.length;
                for (int column = 0; column < columns; column++) {
                    int leftEdge = (column * width) / array[0].length;
                    if (array[row][column] != null) {
                        Paintable thing = array[row][column];
                        thing.paint(g, leftEdge, topEdge, width / columns, height / rows);
                    }
                }
            }
        }
    }
}
