import java.awt.*;
import java.awt.event.*;

public class ChessBoard extends Canvas
    implements MouseListener, MouseMotionListener
{
    public final static int NUMSQUARES = 64;
    private final static int ROWS = 8, COLUMNS = ROWS;
    private ChessPiece [] [] squares;
    private ChessSet chessSet;
    private ChessPiece pieceDragging;
    
    public ChessBoard ()
    {
	squares = new ChessPiece [ROWS] [COLUMNS];
	clearPieces ();

	addMouseListener (this);
	addMouseMotionListener (this);

    }

    public void setPieces (ChessSet cs)
    {
	chessSet = cs;
	for (int i = 0; i < COLUMNS; i ++) {
	    chessSet.getPiece (i).setHome (i, 0);
	    chessSet.getPiece (i+COLUMNS).setHome (i, 1);
	    chessSet.getPiece (i+COLUMNS+COLUMNS).setHome (i, 6);
	    chessSet.getPiece (i+COLUMNS*3).setHome (i, 7);
	    /*
	    placePiece (chessSet.getPiece (i+COLUMNS), i, 1);
	    placePiece (chessSet.getPiece (i+COLUMNS*2), i, 6);
	    placePiece (chessSet.getPiece (i+COLUMNS*3), i, 7);
	    */
	}
    }

    public void clearPieces ()
    {
	for (int x = 0; x < COLUMNS; x ++) {
	    for (int y = 0; y < ROWS; y ++) {
		squares [x] [y] = null;
	    }
	}
    }

    public void newGame ()
    {
	clearPieces ();
	/*
	for (int i = 0; i < COLUMNS; i ++) {
	    placePiece (chessSet.getPiece (i), i, 0);
	    placePiece (chessSet.getPiece (i+COLUMNS), i, 1);
	    placePiece (chessSet.getPiece (i+COLUMNS*2), i, 6);
	    placePiece (chessSet.getPiece (i+COLUMNS*3), i, 7);
	}
	*/
	for (int i = 0; i < chessSet.NUMPIECES; i ++) {
	    sendPieceHome (chessSet.getPiece (i));
	}
	chessSet.newGame ();
    }

    public void placePiece (ChessPiece piece, int x, int y)
    {
	if (validSquare (x, y) && piece != null) {
	    int oldX = piece.getX (), oldY = piece.getY ();
	    if (getPieceAt (oldX, oldY) == piece) {
		squares [oldX] [oldY] = null;
	    }
	    squares [x] [y] = piece;
	    piece.setSquare (x, y);
	    adjustPiece (piece);
	}
    }

    public void sendPieceHome (ChessPiece piece)
    {
	placePiece (piece, piece.getHomeX (), piece.getHomeY ());
    }

    public void adjustPiece (ChessPiece piece)
    {
	Dimension d = getSize ();
	int sWidth = d.width / 8, sHeight = d.height / 8;
	piece.moveTo ((sWidth) * (piece.getX ()) + (sWidth/2),
		      (sHeight) * (piece.getY ()) + (sHeight/2));
    }

    Image offscr = null;
    Graphics gOffscr = null;
    
    public void paintOffscreenImage ()
    {
	Dimension boardSize = getSize ();
	if (offscr == null) {
	    offscr = createImage (boardSize.width, boardSize.height);
	    gOffscr = offscr.getGraphics ();
	}

	Graphics g = gOffscr;
	int a = 10, b = 30;
	Dimension d = getSize ();
	int sWidth = d.width / COLUMNS, sHeight = d.height / ROWS;
	for (int x = 0; x < COLUMNS; x ++) {
	    for (int y = 0; y < ROWS; y ++) {
		if ((x+y) % 2 == 0)
		    g.setColor (Color.lightGray);
		else
		    g.setColor (Color.darkGray);
		g.fillRect (x*sWidth, y*sHeight, sWidth, sHeight);
	    }
	}

	for (int x = 0; x < COLUMNS; x ++) {
	    for (int y = 0; y < ROWS; y ++) {
		//draw the chess piece at this square
		if (squares [x] [y] != null) {
		    squares [x] [y].draw (g);
		}
	    }
	}
	if (pieceDragging != null) {
	    pieceDragging.draw (g);
	}
    }

    public void paint (Graphics g)
    {
	paintOffscreenImage ();
	g.drawImage (offscr, 0, 0, null);
	//notifyAll ();
    }

    public final void update (Graphics g)
    {
	paint (g);
    }

    public ChessPiece getPieceAt (int x, int y)
    {
	if (validSquare (x, y)) {
	    return squares [x] [y];
	} else {
	    return null;
	}
    }

    public ChessPiece getPieceAt (ChessBoardSquare cbs)
    {
	return getPieceAt (cbs.getX (), cbs.getY ());
    }

    public ChessBoardSquare whatSquare (int pixelX, int pixelY)
    {
	Dimension d = getSize ();
	int sWidth = d.width / 8, sHeight = d.height / 8;
	return new ChessBoardSquare (pixelX / sWidth, pixelY / sHeight);
    }

    public ChessPiece clickedOn (int pixelX, int pixelY)
    {
	Dimension d = getSize ();
	int sWidth = d.width / 8, sHeight = d.height / 8;
	int squareX = pixelX / sWidth, squareY = pixelY / sHeight;
	System.out.println ("clicked on square " + squareX +
			    ", " + squareY + "!!");
	return getPieceAt (squareX, squareY);
    }

    public boolean validSquare (int x, int y)
    {
	return (x >= 0 && x < COLUMNS && y >= 0 && y < ROWS);
    }

	//////////////////////////////////////////
	//	MouseListener actions
	//////////////////////////////////////////
    public void mouseEntered (MouseEvent e)
    {
    }
    public void mouseExited (MouseEvent e)
    {
    }
    public void mousePressed (MouseEvent e)
    {
	pieceDragging = getPieceAt (whatSquare (e.getX (), e.getY ()));
    }
    public void mouseReleased (MouseEvent e)
    {
	if (pieceDragging != null) {
	    ChessBoardSquare cbs = whatSquare (e.getX (), e.getY ());
	    int x = cbs.getX (), y = cbs.getY ();
	    if (validSquare (x, y) &&
		pieceDragging.legalMove (this, x, y)) {
		placePiece (pieceDragging, x, y);
		pieceDragging.setMoved (true);
	    } else {
		//return dragged piece to original square
		adjustPiece (pieceDragging);
	    }
	    pieceDragging = null;
	    repaint ();
	}
    }
    public void mouseClicked (MouseEvent e)
    {
    }

	//////////////////////////////////////////
	//	MouseEventListener actions
	//////////////////////////////////////////
    public void mouseMoved (MouseEvent e)
    {
    }
    public void mouseDragged (MouseEvent e)
    {
	if (pieceDragging != null) {
	    pieceDragging.moveTo (e.getX (), e.getY ());
	    repaint ();
	}
    }

    private class ChessBoardSquare
    {
	int locX, locY;

	public ChessBoardSquare (int x, int y)
	{
	    locX = x; locY = y;
	}
	public int getX ()
	{
	    return locX;
	}
	public int getY ()
	{
	    return locY;
	}
    };
}

