package sfs3.extensions.examples.tictactoe.game

import com.smartfoxserver.entities.data.ISFSArray
import com.smartfoxserver.entities.data.SFSArray

class Board
{
    private var board = Array(4) {Array<Mark>(4) { Mark.EMPTY } }
    private var winner:Int = 0;

    fun getMarkAt(row:Int, col:Int): Mark
    {
        return board[row][col]
    }

    fun setMarkAt(row: Int, col: Int, mark: Mark)
    {
        // Validate coordinates
        checkCoords(row, col)

        // Set mark
        board[row][col] = mark
    }

    fun getWinner():Int
    {
        return winner
    }

    fun getState(moveCount: Int): State
    {
        val iter = getAllSolutions().iterator()
        var state = State.RUNNING

        while (iter.hasNext())
        {
            val solution = iter.next()
            iter.remove()

            // Player 1 wins
            if (solution == "111") {
                state = State.END_WITH_WINNER
                winner = 1
                break
            } else if (solution == "222") {
                state = State.END_WITH_WINNER
                winner = 2
                break
            }
        }

        if (winner == 0 && moveCount == 9) state = State.END_WITH_TIE

        return state
    }

    fun reset()
    {
        winner = 0;
        board = Array(4) {Array<Mark>(4) { Mark.EMPTY } }
    }

    private fun checkCoords(row: Int, col: Int) {
        if (row in 1..3) {
            require(!(col < 1 || col > 3)) { "Mark column position out of range: $col" }
        } else {
            throw IllegalArgumentException("Mark row position out of range: $row")
        }
    }

    fun toSFSArray(): ISFSArray
    {
        val sfsa: ISFSArray = SFSArray()

        for (r in 1..3) {
            sfsa.addIntArray(this.getRowAsList(r))
        }

        return sfsa
    }

    private fun getAllSolutions(): MutableList<String> {
        val solutions = ArrayList<String>()

        for (r in 1..3) {
            solutions.add(
                String.format(
                    "%s%s%s",
                    board[r][1].id.toString(),
                    board[r][2].id.toString(),
                    board[r][3].id.toString()
                )
            )
        }

        for (c in 1..3) {
            solutions.add(
                String.format(
                    "%s%s%s",
                    board[1][c].id.toString(),
                    board[2][c].id.toString(),
                    board[3][c].id.toString()
                )
            )
        }

        solutions.add(
            String.format(
                "%s%s%s",
                board[1][1].id,
                board[2][2].id,
                board[3][3].id)
            )

        solutions.add(
            String.format(
                "%s%s%s",
                board[1][3].id,
                board[2][2].id,
                board[3][1].id)
        )

        return solutions
    }

    private fun getRowAsList(r: Int): List<Int>
    {
        val row = ArrayList<Int>()

        for (c in 1..3)
        {
            row.add(board[r][c].id)
        }

        return row
    }
}