// TicTacToe.java, user-against-user, JavaFX GUI
// From http://www.cs.armstrong.edu/liang/intro10e/html/TicTacToe.html
// Mods by pmateti@wright.edu 2015
// compile and run: % javac TicTacToe.java; java TicTacToe
// Has at least one bug!

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Ellipse;

public class TicTacToe extends Application {

    private boolean gameOver = false;
    private int nFilled = 0;
    private char whoseTurn = 'X'; // 'X' or 'O'
    private Cell[][] cell =  new Cell[3][3];
    private Label statusLabel = new Label("X's turn to play");

    @Override
    public void start(Stage primaryStage) {
        GridPane pane = new GridPane(); 
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                pane.add(cell[i][j] = new Cell(), j, i);

        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(pane);
        borderPane.setBottom(statusLabel);
    
        Scene scene = new Scene(borderPane, 300.0f, 300.0f);
        primaryStage.setTitle("TicTacToe");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public boolean isFull() {
        return nFilled >= 9; // > should never happen
    }
    
    public boolean hasWon(char tkn) {
        for (int i = 0; i < 3; i++)
            if (cell[i][0].getToken() == tkn &&
                cell[i][1].getToken() == tkn &&
                cell[i][2].getToken() == tkn)
                return true;
        for (int j = 0; j < 3; j++)
            if (cell[0][j].getToken() == tkn &&
                cell[1][j].getToken() == tkn &&
                cell[2][j].getToken() == tkn)
                return true;
        if (cell[0][0].getToken() == tkn &&
            cell[1][1].getToken() == tkn &&
            cell[2][2].getToken() == tkn)
            return true;
        if (cell[0][2].getToken() == tkn &&
            cell[1][1].getToken() == tkn &&
            cell[2][0].getToken() == tkn)
            return true;
        return false;
    }

    public class Cell extends Pane {

        private char token = ' ';   // one of blank, X, or O

        public Cell() {
            setStyle("-fx-border-color: black"); 
            setPrefSize(100.0f, 100.0f);
            setOnMouseClicked(e -> handleMouseClick());
        }

        public char getToken() {
            return token;
        }

        public void drawX() {
            double w = getWidth(), h = getHeight();
            Line line1 = new Line(10.0f, 10.0f, w - 10.0f, h - 10.0f);
            Line line2 = new Line(10.0f, h - 10.0f, w - 10.0f, 10.0f);
            getChildren().addAll(line1, line2); 
        }

        public void drawO() {
            double w = getWidth(), h = getHeight();
            Ellipse ellipse = new Ellipse(w/2, h/2, w/2 - 10.0f, h/2 - 10.0f);
            ellipse.setStroke(Color.BLACK);
            ellipse.setFill(Color.WHITE);
            getChildren().add(ellipse);
        }

        public void setToken(char c) {
            if (c == 'X')
                drawX();
            else 
                drawO();
            token = c;
            nFilled ++;
        }

        private void handleMouseClick() {
            String s = "";
            if (!gameOver) {
                setToken(whoseTurn);
                if (hasWon(whoseTurn)) {
                    gameOver = true;
                    s = whoseTurn + " won! The game is over";
                }
                else if (isFull()) {
                    gameOver = true;
                    s = "Draw! The game is over";
                }
                else {
                    whoseTurn = (whoseTurn == 'X') ? 'O' : 'X';
                    s = whoseTurn + "'s turn";
                }
                statusLabel.setText(s);
            }
        }
    }
  
    public static void main(String[] args) {
        launch(args);
    }
}

// -eof-