/*
Othello app by Emmett Nicholas
February 2008 -- version 1.0
emmett nicholas at gmail dot com
*/

var Oth = {};

Oth.START_STATE = '--------|--------|--------|---wb---|---bw';
Oth.IMAGE_FOLDER = 'images/';
Oth.NEXT_ID_SUFFIX = '_next';
Oth.PREV_ID_SUFFIX = '_prev';
Oth.RESET_ID_SUFFIX = '_reset';
Oth.BLACK_SCORE_ID_SUFFIX = '_black';
Oth.WHITE_SCORE_ID_SUFFIX = '_white';

Oth.COLOR = {
	'empty': '-',
	'black': 'b',
	'white': 'w'
};

Oth.IMAGES = {
	'-': 'green.png',
	'b': 'black.png',
	'w': 'white.png',
	'top': 'edge_top.png',
	'leftPrefix': 'edge_left',
	'leftSuffix': '.png',
	'right': 'edge_right.png',
	'bottom': 'edge_bottom.png'
};

Oth.Grid = function(id, state, nextColor, initMoves, nextMoves)
{
	var cells;
	var container = document.getElementById(id);
	var stateHistory = [];
	var stateIndex = -1;
	var stateProgress = -1;
	var phantomButton = document.createElement('button');
	var nextButton = document.getElementById(id + Oth.NEXT_ID_SUFFIX) || phantomButton;
	var prevButton = document.getElementById(id + Oth.PREV_ID_SUFFIX) || phantomButton;
	var resetButton = document.getElementById(id + Oth.RESET_ID_SUFFIX) || phantomButton;
	var blackScoreElem = document.getElementById(id + Oth.BLACK_SCORE_ID_SUFFIX) || phantomButton;
	var whiteScoreElem = document.getElementById(id + Oth.WHITE_SCORE_ID_SUFFIX) || phantomButton;
	var imoves = !initMoves ? [] : initMoves.split(' ');
	var nmoves = !nextMoves ? [] : nextMoves.split(' ');
	var i;
	
	container.innerHTML = '';
	createBoard();
	loadState(state || Oth.START_STATE);
	pushState();
	nextColor = !nextColor ? Oth.COLOR.black : nextColor;
	
	for (i = 0; i < imoves.length; i++)
	{
		move(imoves[i]);
	}
	
	showScore();
	resetButtons();
	
	prevButton.onclick =
		function(event)
		{
			loadState(stateHistory[--stateIndex]);
			nextButton.disabled = false;
			prevButton.disabled = (stateIndex === 0);
		};
	
	nextButton.onclick =
		function(event)
		{
			if (stateIndex < stateProgress)
			{
				loadState(stateHistory[++stateIndex]);
			}
			else
			{
				move(nmoves[stateIndex - imoves.length]);
			}
			prevButton.disabled = false;
			nextButton.disabled = (stateIndex === imoves.length + nmoves.length);
		};
	
	resetButton.onclick =
		function(event)
		{
			loadState(stateHistory[stateIndex = imoves.length]);
			resetButtons();
		};
	
	function resetButtons()
	{
		prevButton.disabled = (imoves.length === 0);
		nextButton.disabled = (nmoves.length === 0);
	}
	
	function createBoard()
	{
		var i, j;
		var img;
		
		appendImage(Oth.IMAGE_FOLDER + Oth.IMAGES.top);
		container.appendChild(document.createElement('br'));
		
		cells = [];
		for (i = 0; i < 8; i++)
		{
			appendImage(Oth.IMAGE_FOLDER + Oth.IMAGES.leftPrefix + (i+1) + Oth.IMAGES.leftSuffix);
			
			cells[i] = [];
			for (j = 0; j < 8; j++)
			{
				cells[i][j] = new Oth.Cell();
				container.appendChild(cells[i][j].getSpan());
			}
			
			appendImage(Oth.IMAGE_FOLDER + Oth.IMAGES.right);
			container.appendChild(document.createElement('br'));
		}
		
		appendImage(Oth.IMAGE_FOLDER + Oth.IMAGES.bottom);
		
		function appendImage(src)
		{
			var img = document.createElement('img');
			img.src = src;
			container.appendChild(img);
		}
	}
	
	function loadState(state)
	{
		var i;
		var s = 0;
		for (i = 0; i < state.length || s < 64; i++)
		{
			switch (state.charAt(i))
			{
				case Oth.COLOR.empty:
				case '':
					cells[Math.floor(s/8)][s%8].setColor(Oth.COLOR.empty);
					break;
				case Oth.COLOR.black:
					cells[Math.floor(s/8)][s%8].setColor(Oth.COLOR.black);
					break;
				case Oth.COLOR.white:
					cells[Math.floor(s/8)][s%8].setColor(Oth.COLOR.white);
					break;
				default:
					continue;
			}
			s++;
		}
		showScore();
	}
	
	function pushState()
	{
		var s = [];
		var i, j;
		for (i = 0; i < 8; i++)
		{
			for (j = 0; j < 8; j++)
			{
				s.push(cells[i][j].getColor());
			}
		}
		stateHistory.push(s.join(''));
		stateIndex++;
		stateProgress += (stateIndex > stateProgress) ? 1 : 0;
	}
	
	function move(position)
	{
		var row = parseInt(position.substring(1,2)) - 1;
		var col = position.substring(0,1).toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0);
		var otherColor = (nextColor === Oth.COLOR.black) ? Oth.COLOR.white : Oth.COLOR.black;

		cells[row][col].setColor(nextColor);
		
		couldFlip(nextColor, row, col, -1, -1, true);
		couldFlip(nextColor, row, col, -1, 0, true);
		couldFlip(nextColor, row, col, -1, 1, true);
		couldFlip(nextColor, row, col, 0, -1, true);
		couldFlip(nextColor, row, col, 0, 1, true);
		couldFlip(nextColor, row, col, 1, -1, true);
		couldFlip(nextColor, row, col, 1, 0, true);
		couldFlip(nextColor, row, col, 1, 1, true);
			
		pushState();
		nextColor = hasMove(otherColor) ? otherColor : nextColor;
		showScore();
		
		function couldFlip(color, r, c, x, y, shouldFlip)
		{
			var i, j, k;
			var other = (color === Oth.COLOR.black) ? Oth.COLOR.white : Oth.COLOR.black;
			var flippable = [];
			for (i = r + y, j = c + x; i >= 0 && i < 8 && j >= 0 && j < 8; i += y, j += x)
			{
				switch (cells[i][j].getColor())
				{
					case Oth.COLOR.empty:
						return false;
					case other:
						flippable.push(cells[i][j]);
						break;
					case color:
						if (shouldFlip)
						{
							for (k = 0; k < flippable.length; k++)
							{
								flippable[k].setColor(nextColor);
							}
						}
						return flippable.length > 0;
				}					
			}
			return false;
		}
		
		function hasMove(color)
		{
			var i, j;
			for (i = 0; i < 8; i++)
			{
				for (j = 0; j < 8; j++)
				{
					if (cells[i][j].getColor() === Oth.COLOR.empty &&
							(couldFlip(color, i, j, -1, -1, false) || couldFlip(color, i, j, -1, 0, false) || couldFlip(color, i, j, -1, 1, false) ||
							couldFlip(color, i, j, 0, -1, false) || couldFlip(color, i, j, 0, 1, false) ||
							couldFlip(color, i, j, 1, -1, false) || couldFlip(color, i, j, 1, 0, false) || couldFlip(color, i, j, 1, 1, false)))
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	
	function showScore()
	{
		blackScoreElem.innerHTML = compute(Oth.COLOR.black);
		whiteScoreElem.innerHTML = compute(Oth.COLOR.white);
		
		function compute(color)
		{
			var i, j;
			var score = 0;
			for (i = 0; i < 8; i++)
			{
				for (j = 0; j < 8; j++)
				{
					score += (cells[i][j].getColor() === color) ? 1 : 0;
				}
			}
			return score;
		}
	}
};

Oth.Cell = function()
{
	var span = document.createElement('span');
	var color;
	
	this.getSpan = function()
	{
		return span;
	};
	
	this.getColor = function()
	{
		return color;
	};
	
	this.setColor = function(clr)
	{
		if (color === clr)
		{
			return;
		}
		color = clr;
		span.innerHTML = '<img src="' + Oth.IMAGE_FOLDER + Oth.IMAGES[clr] + '">';
	};
};
