/* @(#)CheckerBoard.java   2.4.0   25 August 2005
 *
 * Copyright 2005
 * College of Computer Science
 * Northeastern University
 * Boston, MA  02115
 *
 * This software may be used for educational purposes as long as
 * this copyright notice is retained intact at the top of all files.
 *
 * To discuss commercial use of this software, contact 
 * Prof. Richard Rasala or Prof. Viera Proulx at the Northeastern 
 * University College of Computer Science: 617-373-2462.
 *
 * The principal software developer on this project is Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either in whole
 * or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.gui;

import edu.neu.ccs.*;
import edu.neu.ccs.gui.*;
import edu.neu.ccs.util.*;

import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * <p>Class <code>CheckerBoard</code> is a standalone utility that permits
 * a user to interactively compare two colors.   The user may pick a pair
 * colors using two <code>ColorView</code> panes and the utility will show
 * these colors in a checkerboard pattern that enables comparison.</p>
 *
 * <p>Colors may be entered in the following ways:</p>
 *
 * <ul>
 *   <li>Using named colors in the <code>ColorView</code> dropdown list.</li>
 *   <li>Using R, G, B values in decimal.</li>
 *   <li>Using R, G, B, Alpha values in decimal.</li>
 *   <li>Using hexadecimal values entered as #rRgGbB or #rRgGbBaA.</li>
 *   <li>Using hexadecimal shorthand #rgb = #rrggbb and #rgba = #rrggbbaa.</li>
 * </ul>
 *
 * <p>The default constructor creates a checkerboard with default settings
 * and installs the checkerboard in a frame.</p>
 *
 * <p>Using the general constructor, one can control settings, choose whether
 * to show the interactive controls, and whether to frame the panel.</p>
 *
 * <p>Since the checkerboard is painted on the bit map layer of a
 * <code>BufferedPanel</code>, one may add <code>Paintable</code> objects to
 * the paintable sequence layer that is painted above the bit map.  In this
 * way, it is possible to add "game pieces" such as checkers or chess pieces
 * to this panel and use external code to control these game pieces.</p>
 */
public class CheckerBoard extends TablePanel
{
    /** The pixel gap between items in this panel. */
    public static final int gap = 10;
    
    /** The maximum checkerboard block size = 80. */
    public static final int MAXIMUM_BLOCK = 80;
    
    /** The default checkerboard block size = 48. */
    public static final int BLOCK = 48;
    
    /** The minimum checkerboard block size = 16. */
    public static final int MINIMUM_BLOCK = 16;
    
    /**
     * The default color for checkerboard blocks whose
     * (row + column) sum is even: black.
     */
    public static final Color COLOR0 = Colors.black;
    
    /**
     * The default color for checkerboard blocks whose
     * (row + column) sum is odd: white.
     */
    public static final Color COLOR1 = Colors.white;
    
    
    /** The checkerboard graphics window. */
    private BufferedPanel window = null;
    
    /** The size of a checkerboard block. */
    private int block = BLOCK;
    
    /** The array of checkerboard blocks. */
    private Rectangle2D[][] blocks = new Rectangle2D[8][8];
    
    
    /** Color view 0. */
    private ColorView view0 = null;
    
    /** Color view 1. */
    private ColorView view1 = null;
    
     
    /** The action to make a checkerboard patten. */
    private SimpleAction colorCheckerBoard =
        new SimpleAction("Make Checker Board") {
            public void perform() { colorCheckerBoard(); }
        };
    
    /** The action to reset the colors to their original settings. */
    private SimpleAction resetColorViews =
        new SimpleAction("Reset Color Views") {
            public void perform() { resetColorViews(); }
        };
    
    
    /**
    * <p>The constructor that opens the checkerboard application in a frame
    * using the default block size and default colors.</p>
    *
    * <p>Since this constructor opens the checkerboard in a frame, the panel
    * cannot be inserted into another GUI component.  To obtain only a panel
    * and to control all parameters, use the other constructor.</p>
    */
    public CheckerBoard() {
        this(BLOCK, null, null, true, true);
    }
    
    
    /**
     * <p>The constructor that permits the caller to control the size of the
     * checkerboard block (within limits), the initial block colors, whether
     * to show the interactive color controls, and whether to automatically
     * put the checkerboard into a <code>JPTFrame</code>.</p>
     *
     * @param block the size of a checkerboard block
     * @param color0 color for blocks with (row + column) sum even
     * @param color1 color for blocks with (row + column) sum odd
     * @param showColorViews whether to show the interactive color controls
     * @param autoFrame whether to automatically frame the checkerboard
     */
    public CheckerBoard
        (int block,
         Color color0,
         Color color1,
         boolean showColorViews,
         boolean autoFrame)
    {
        super(4, 1, gap, gap, CENTER);
        
        createCheckerBoard(block);
        createColorViews(color0, color1);
        
        colorCheckerBoard();
        
        installContents(showColorViews);
        autoFramePanel(autoFrame);
    }
    
    
    /**
     * <p>Returns a reference to the checkerboard <code>BufferedPanel</code>
     * on which the checkerboard is painted.</p>
     *
     * <p>This permits the user to add <code>Paintable</code> objects such as
     * "game pieces" to the paintable sequence layer of the checkerboard.</p>
     */
    public final BufferedPanel getCheckerboard() {
        return window;
    }
    
    
    /**
     * <p>Returns the checkerboard block size.</p>
     *
     * <p>The checkerboard panel has size equal to 8 times the block size.</p>
     */
    public final int getBlockSize() {
        return block;
    }
    
    
    /**
     * <p>Returns the checkerboard <code>BufferedPanel</code> size.</p>
     *
     * <p>The checkerboard panel has size equal to 8 times the block size.</p>
     *
     * <p>The caller should not modify the <code>BufferedPanel</code> size
     * using calls from the <code>BufferedPanel</code> class.</p>
     */
    public final int getCheckerBoardSize() {
        return 8 * block;
    }
    
    
    /** Returns the color for blocks with (row + column) sum even. */
    public final Color getColor0() {
        return view0.getColor();
    }
    
    
    /** Returns the color for blocks with (row + column) sum odd. */
    public final Color getColor1() {
        return view1.getColor();
    }
    
    
    /**
     * <p>Sets the color for blocks with (row + column) sum even
     * to the given color.</p>
     *
     * <p>Does nothing if the given color is <code>null</code.</p>
     *
     * @param color0 color for blocks with (row + column) sum even
     */
    public final void setColor0(Color color0) {
        if (color0 != null)
            view0.setColor(color0);
    }
    
    
    /**
     * <p>Sets the color for blocks with (row + column) sum odd
     * to the given color.</p>
     *
     * <p>Does nothing if the given color is <code>null</code.</p>
     *
     * @param color1 color for blocks with (row + column) sum odd
     */
    public final void setColor1(Color color1) {
        if (color1 != null)
            view1.setColor(color1);
    }
    
    
    /** Resets the colors to their original settings. */
    public final void resetColorViews() {
        view0.reset();
        view1.reset();
    }
    
    
    /** Adjust the block size to lie between the minimum and maximum. */
    private final int adjustBlock(int block) {
        if (block < MINIMUM_BLOCK)
            return MINIMUM_BLOCK;
        else
        if (block > MAXIMUM_BLOCK)
            return MAXIMUM_BLOCK;
        else
            return block;
    }
    
    
    /** Create the checker board and the blocks data structure. */
    private final void createCheckerBoard(int block) {
        block = adjustBlock(block);
        this.block = block;
        
        int size = 8 * block;
        
        window = new BufferedPanel(size, size);
        
        for (int row = 0; row < 8; row++)
            for (int col = 0; col < 8; col++)
                blocks[row][col] =
                    new Rectangle2D.Double
                        (col * block, row * block, block, block);
    }
    
    
    /**
     * Create the color views with the given original colors.
     *
     * @param color0 color for blocks with (row + column) sum even
     * @param color1 color for blocks with (row + column) sum odd
     */
    private final void createColorViews(Color color0, Color color1) {
        if (color0 == null)
            color0 = COLOR0;
        
        if (color1 == null)
            color1 = COLOR1;
        
        view0 = new ColorView(color0);
        view1 = new ColorView(color1);
        
        view0.addAction(colorCheckerBoard);
        view1.addAction(colorCheckerBoard);
    }
    
    
    /** Install the contents in this panel. */
    private final void installContents(boolean showColorViews) {
        addObject(window, 0, 0);
        
        if (showColorViews) {
            addObject(view0, 1, 0);
            addObject(view1, 2, 0);
            addObject(resetColorViews, 3, 0);
        }
    }
    
    
    /** Auto frame if desired. */
    private final void autoFramePanel(boolean autoFrame) {
        if (autoFrame)
            frame("Checker Board");
    }
    
    
    /** The method to color the checkerboard patten. */
    protected final void colorCheckerBoard() {
        window.clearPanel();
        
        Graphics2D graphics = window.getBufferGraphics();
        
        Color[] colors = new Color[] { view0.getColor(), view1.getColor() };
        
        for (int row = 0; row <= 7; row++)
            for (int col = 0; col <= 7; col++) {
                graphics.setPaint(colors[(row + col) % 2]);
                graphics.fill(blocks[row][col]);
            }
        
        window.repaint();
    }
    
}
