import java.awt.Color;

import objectdraw.*;

/*
 * TicTacToe game to demonstrate 2D arrays.
 */

public class TicTacToe extends WindowController {
    // Top, left corner of grid
    private static final int TOP = 40;
    private static final int LEFT = 40;

    // Number of rows in the grid
    private static final int NUM_ROWS = 3;
    private static final int NUM_COLS = NUM_ROWS;

    // Size of each grid square
    private static final int CELL_SIZE = 40;

    // Size of the marks to draw in the grid and offset from square edge
    private static final int MARK_SIZE = CELL_SIZE * 3 / 4;
    private static final int MARK_OFFSET = (CELL_SIZE - MARK_SIZE) / 2;

    // Length of the lines making up the grid
    private static final int LINE_LENGTH = CELL_SIZE * NUM_ROWS;

    // Denote value of a square to show who has played there.
    private static final int EMPTY = 0;
    private static final int X_MARK = 1;
    private static final int O_MARK = 2;

    // The grid contents
    private int[][] marks = new int[NUM_ROWS][NUM_COLS];

    // Whose turn it is next
    private int nextMark = X_MARK;

    // Whether the game has been won or not
    private boolean gameOver = false;

    // Draw an empty grid
    public void begin() {
        for (int i = 1; i < NUM_ROWS; i++) {
            new Line(LEFT, TOP + i * CELL_SIZE,
                     LEFT + LINE_LENGTH, TOP + i * CELL_SIZE, canvas);
            new Line(LEFT + i * CELL_SIZE, TOP,
                     LEFT + i * CELL_SIZE, TOP + LINE_LENGTH, canvas);
        }
    }

    // Draw an X with the given upper left hand corner
    private void drawX(int left, int top) {
        new Line(left, top, left + MARK_SIZE, top + MARK_SIZE, canvas);
        new Line(left + MARK_SIZE, top, left, top + MARK_SIZE, canvas);
    }

    // Draw an O with the given upper left hand corner
    private void drawO(int left, int top) {
        new FramedOval(left, top, MARK_SIZE, MARK_SIZE, canvas);
   }
   
    private void drawMark(int row, int col, int mark) {
        if (mark == X_MARK) {
            drawX(LEFT + col * CELL_SIZE + MARK_OFFSET,
                  TOP + row * CELL_SIZE + MARK_OFFSET);
        } else {
            drawO(LEFT + col * CELL_SIZE + MARK_OFFSET,
                  TOP + row * CELL_SIZE + MARK_OFFSET);
        }
    }

    // Place the next piece and check for a win
    public void onMouseClick(Location point) {
        double x = point.getX();
        double y = point.getY();

        // Ignore clicks outside the grid
        if (x > LEFT && x < LEFT + LINE_LENGTH && 
            y > TOP && y < TOP + LINE_LENGTH) {

            // Figure out which cell in the grid was clicked in
            int col = (int) ((x - LEFT) / CELL_SIZE);
            int row = (int) ((y - TOP) / CELL_SIZE);

            // Make sure the grid is empty before adding a mark.
            // Also make sure the game is not already over
            if (marks[row][col] == EMPTY && !gameOver) {
                // Add the mark
                marks[row][col] = nextMark;
               
                drawMark(row, col, nextMark);

                // See if the game is over
                if (checkGameOver(row, col, nextMark)) {
                     if (nextMark == X_MARK) {
                         new Text("X Wins!", LEFT, 
                                  (NUM_ROWS + 2) * CELL_SIZE, canvas).setFontSize(32);
                     } else {
                         new Text("O Wins!", LEFT, 
                                  (NUM_ROWS + 2) * CELL_SIZE, canvas).setFontSize(32);
                     }
                     gameOver = true;
                }
                
                // switch players
                if (nextMark == X_MARK) {
                    nextMark = O_MARK;
                } else {
                    nextMark = X_MARK;
                }
            }
        }
    }
    
  
    
    // The game is over if an entire row, column, or diagonal has the same pieces
    private boolean checkGameOver(int row, int col, int matchMark) {
        return checkForRowWin(row, matchMark)
                || checkForColWin(col, matchMark)
                || checkForDiagWin(matchMark)
                || checkForDiag2Win(matchMark); 
    }

    
    // See if this row has all the same pieces
    private boolean checkForRowWin(int row, int matchMark) {
        for (int col = 0; col < NUM_COLS; ++col) {
            if (marks[row][col] != matchMark) {
                return false;
            }
        }
        return true;
    }

    // See if there is a column with all the same pieces
    private boolean checkForColWin(int col, int matchMark) {
        for (int row=0; row < NUM_ROWS; ++row) {
            if (marks[row][col] != matchMark) {
                return false;
            }   
        }
        return true;
    }

    // See if the diagonal from top-left to bottom-right has all the same pieces
    private boolean checkForDiagWin(int matchMark) {
        for (int i = 0; i < NUM_COLS; ++i) {
            if (marks[i][i] != matchMark) {
                return false;   
            }
        }
        return true;
    }

    // See if the diagonal from top-right to bottom-left has all the same pieces.
    private boolean checkForDiag2Win(int matchMark) {
        for (int i = 0; i < NUM_ROWS; ++i) {
            if (marks[i][NUM_ROWS-i-1] != matchMark) {
                return false;   
            }
        }
        return true;
    }

}
