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

/**
 * ArrayDisplay provides a simple GUI for displaying an array of Objects
 * (such as Strings), and for displaying messages as appropriate.
 * 
 * @author David Matuszek
 * @version 2.1
 */
public class ArrayDisplay extends Frame {
    private Object[][] array;
    private Object[][] backgroundArray;
    private int rows;
    private int columns;
    private MyPanel mainPanel = new MyPanel();
    private Panel controlPanel = new Panel();
    private Button quitButton = new Button("Quit");
    private TextField messageField = new TextField();
    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(Object[][] 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(Object[][] array, Object[][] 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);
        
        // 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 Panel {
  
        /**
         * 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, Object[][] array) {
            int height = getHeight();
            int width = getWidth();
            for (int row = 0; row < rows; row++) {
                int y = ((row + 1) * height / (rows + 1)) + (FONT_SIZE / 2);
                for (int column = 0; column < columns; column++) {
                    int x = (column + 1) * width / (columns + 1);
                    if (array[row][column] != null) {
                        g.drawString(array[row][column].toString(), x, y);
                    }
                }
            }
        }
    }
    
    /**
     * No parameters necessary. This is just a unit test for the
     * ArrayDisplay class, and may be ignored.
     */
    public static void main(String[] args) {
        
        String[][] testArray = { {"A", "B", "C", "D"},
                                 {"E", "F", "G", "H"},
                                 {"I", "J", "K", "L"} };
                                 
        String[][] backArray = { {"a", "b", "c", "d"},
                                 {"e", "f", "g", "h"},
                                 {"i", "j", "k", "l"} };
                                 
//         testArray[1][1] = testArray[2][2] = null;
//         backArray[1][1] = backArray[1][2] = null;
        ArrayDisplay d = new ArrayDisplay(testArray, backArray);
        d.displayMessage("Running...");
        for (char c = 'A'; c <= 'Z'; c++) {
            testArray[0][0] = c + "";
            d.repaint();
        }
        d.displayMessage("Done.");
    }
}
