/** A graphical component to display an array of colored tiles.
 *
 * @author Jim Grundy
 * @version $Revision: 1.7 $ */

import java.awt.Color;		// Colors
import java.awt.Canvas;		// A Canvas for drawing on the screen.
import java.awt.Graphics;	// Generic drawing functionality.

public class PlayingField extends Canvas
{
    private int width;		// The width of the playing field.
    private int height;		// The height of the playing field.
    private int edge;		// The size of a tile on the playing field.
    private Color background;	// The background color of the playing field.
    private Color[][] tiles;	// The state of the playing field.
    /* INVARIANT: (0 < width) && (0 < height) && (0 < edge) */ 
    
    /** Make a playing field of width by height, made up of colored
     * tiles of edge by edge.
     *
     * PRE: (0 < width) && (0 < height) && (0 < edge)
     * 
     * @param width The width (tiles) of the playing field to create.
     * @param height The height (tiles) of the playing field to create.
     * @param edge The edge length (pixels) of a tile on the field.  */
    public PlayingField(int width, int height, int edge, Color background)
    {
	/* Check these parameters satisfy the precondition. */
	Assert.check((0 < width) && (0 < height) && (0 < edge),
		     "Can't create a playing field with a dimension < 1.");
	
	/* Set the dimensions of the playing field and its tiles. */
	this.width = width;
	this.height = height;
	this.edge = edge;
	
	/* Create the array of tiles, and set all tiles to background color. */
	this.background = background;
	tiles = new Color[width][height];
	for(int col=0; col<width; col=col+1){
	    for(int row=0; row<height; row=row+1){
		/* INVARIANT:
		 *   "all c < col and r < row, tiles[c][r] = background." */
		tiles[col][row]=background;
	    }
	}
	
	/* Resize the canvas to fit the playing field. */
	setSize(width*edge,height*edge);
    }
    
    /** Get the width of the playing field.
     * 
     * @return The width of the playing field. */
    public int getWidth()
    {
	return width;
    }
    
    /** Get the height of the playing field.
     *
     * @return The height of the playing field. */
    public int getHeight()
    {
	return height;
    }
    
    /** Get the area of the playing field.
     *
     * @return The area of the playing field. */
    public int getArea()
    {
	return width * height;
    }

    public Color getBackground()
    {
	return background;
    }

    /** Set the color of a tile on the playing field.
     * 
     * PRE: (0 <= col < width()) && (0 <= row < height())
     *
     * @param col	The column of the tile to color.
     * @param row	The row of the tile to color.
     * @param color The color to paint the tile. */
    public void setTile(int col, int row, Color color)
    {
	/* Check these parameters satisfy the precondition. */
	Assert.check((0 <= col) && (col < width) &&
		     (0 <= row) && (row < height),
		     "Can't set tile ("+col+","+row+"):off playing field.");
	
	tiles[col][row] = color;
    }
    
    /** Get the color of a tile on the playing field.
     * 
     * PRE: (0 <= col < width()) && (0 <= row < height())
     *
     * @param col	The column index of the tile to check.
     * @param row	The row index of the tile to check.
     * @return The color of the indexed tile. */
    public Color getTile(int col, int row)
    {
	/* Check these parameters satisfy the precondition. */
	Assert.check((0 <= col) && (col < width) &&
		     (0 <= row) && (row < height),
		     "Can't get tile ("+col+","+row+"): off playing field.");
	
	return tiles[col][row];
    }
    
    /** Update the canvas depiction of the playing field.
     *
     * @param fieldGraph The graphics component to update. */
    public void update(Graphics fieldGraph)
    {
	/* This method overwrites the default update method which first
	 * clears the canvas to the background color, and then calls
	 * paint.  Since paint will redraw the entire canvas anyway,
	 * clearing to the background color first just causes
	 * unnecessary flicker. */
	paint(fieldGraph);
    }
    
    /** Paint a depiction of the playing field onto the canvas.
     *
     * @param fieldGraph The graphics component to update. */
    public void paint(Graphics fieldGraph)
    {
	/* For each tile on the playing field, paint a square on the
	 * canvas in that color.  If the square is background, just
	 * paint it that color, otherwise make it appear slightly
	 * raised.  Note that playing fields use standard Cartesian
	 * coordinates (i.e. the point (0,0) is at the bottom left
	 * corner), while canvases use a nonstandard coordinate system
	 * with (0,0) at the top left.  */
	for(int col=0; col<width; col=col+1){
	    for(int row=0; row<height; row=row+1){
		/* INVARIANT: 
		 *  "all c < col and r < row, tiles[c][r] has been
		 *  painted onto the canvas." */
		fieldGraph.setColor(tiles[col][row]);
		if (tiles[col][row] == background){
		    fieldGraph.fillRect(col*edge,(height-1-row)*edge,
					edge,edge);
		} else {
		    fieldGraph.fill3DRect(col*edge,(height-1-row)*edge,
					  edge,edge,true);
		}
	    }
	}
    }
    
}

