
/**
 * Object representing the marks on the game board.
 */
Mark = {
	EMPTY:0,
	CROSS:1,
	RING:2
}

/**
 * Object representing the game state.
 */
State = {
	RUNNING:0,
	END_WITH_WINNER:1,
	END_WITH_TIE:2
}

/**
 * Object representing the game board.
 */
Board = function()
{
	// Initialize the board.
	// We use a 4x4 matrix, so we can have 1-based indexes (rows and columns)
	this.board = [];
	for (var r = 1; r <= 3; r++)
		this.board[r] = [];
	
	// Add empty mark in all board slots
	this.reset();
}

/**
 * Return the mark contained in a board slot.
 */
Board.prototype.getMarkAt = function(row, col)
{
	return this.board[row][col];
}

/**
 * Set the mark in a board slot.
 */
Board.prototype.setMarkAt = function(row, col, mark)
{
	// Validate coordinates
	this._checkCoords(row, col);
	
	// Set mark
	this.board[row][col] = mark;
}

/**
 * Return the last winner:
 * - 0: no winner (tie or game still in progress)
 * - 1: player 1 was the winner
 * - 2: player 2 was the winner
 */
Board.prototype.getWinner = function()
{
	return this.winner;
}

/**
 * Get the current board state.
 */
Board.prototype.getState = function(moveCount)
{
	var allSolutions = this._getAllSolutions();
	var state = State.RUNNING;
	
	for (var i = 0; i < allSolutions.length; i++)
	{
		var sol = allSolutions[i];

		// Player 1 wins
		if (sol == "111")
		{
			state = State.END_WITH_WINNER;
			this.winner = 1;
			break;
		}
		
		else if (sol == "222")
		{
			state = State.END_WITH_WINNER;
			this.winner = 2;
			break;
		}
	}
	
	if (this.winner == 0 && moveCount == 9)
		state = State.END_WITH_TIE;
	
	return state;
}

/**
 * Reset the board adding an empty mark in all board slots.
 */
Board.prototype.reset = function()
{
	this.winner = 0;
	
	for (var r = 1; r <= 3; r++)
	{
		var boardRow = this.board[r];
		
		for (var c = 1; c <= 3; c++)
		{
			boardRow[c] = Mark.EMPTY;
		}
	}
}

/**
 * Validate the passed board slot coordinates.
 */
Board.prototype._checkCoords = function(row, col)
{
	if (row < 1 || row > 3)
		throw ("Mark row position out of range: " + row);
	
	if (col < 1 || col > 3)
		throw ("Mark column position out of range: " + col);
}

/**
 * Get all completed rows, columns and diagonals to check if the game ended.
 */
Board.prototype._getAllSolutions = function()
{
	var solutions = [];
	
	//--- All rows ------------------------------------------------
	for (var r = 1; r <= 3; r++)
		solutions.push("" + this.board[r][1] + this.board[r][2] + this.board[r][3]);

	//--- All cols ------------------------------------------------
	for (var c = 1; c <= 3; c++)
		solutions.push("" + this.board[1][c] + this.board[2][c] + this.board[3][c]);
	
	//--- All diagonals ------------------------------------------
	solutions.push("" + this.board[1][1] + this.board[2][2] + this.board[3][3]);
	solutions.push("" + this.board[1][3] + this.board[2][2] + this.board[3][1]);
	
	return solutions;
}

/**
 * Return the game board as a SFSArray.
 * As SFSArrays use 0-based indexes and we can't add entries starting from index 1,
 * the client receiving the data will need to transform it to rows/columns. 
 */
Board.prototype.toSFSArray = function()
{
	var sfsa = new SFSArray();
	
	for (var r = 1; r <= 3; r++)
	{
		var row = [];
		
		for (var c = 1; c <= 3; c++)
			row.push(this.board[r][c]);
		
		sfsa.addIntArray(asJavaList(row));
	}
	
	return sfsa;
}
