// The default game board.
var DEFAULT_BOARD = [];
DEFAULT_BOARD[0] = [5,7];
DEFAULT_BOARD[1] = [6];
DEFAULT_BOARD[2] = [5,7];
DEFAULT_BOARD[3] = [4,6,8];
DEFAULT_BOARD[4] = [3,5,7,9];
DEFAULT_BOARD[5] = [0,2,4,6,8,10,12];
DEFAULT_BOARD[6] = [1,11];

var messages = {
	FIRST : 'Triangle Solitaire is a peg game in which the player\'s objective i'
		+ 's to eliminate all the pegs with the exception of one.<br /><a href="ja'
		+ 'vascript:setupGame()">&gt;&gt;&gt; Click Here To Start &lt;&lt;&lt;</a>',
	FIRST_HOLE : 'Now it is time to pick which peg will be removed first.  To co'
		+ 'ntinue, please select the desired peg from above.',
	JUMPER : 'Select the peg that you would like to move. &nbsp;A peg may only m'
		+ 'ove if it can jump over a diagonally or horizontally adjacent peg and l'
		+ 'and in the next hole on that path. &nbsp;A peg may only jump over one p'
		+ 'eg at a time.',
	LANDING : 'Select the spot to where you want the peg to travel.  Possible sp'
		+ 'ots are highlighted in green.',
	WIN : 'Good job, you beat the game.<br /><a href="javascript:setupGame()">&g'
		+ 't;&gt;&gt; Click Here To Try Again &lt;&lt;&lt;</a>',
	LOSS : 'Unfortunately there are no more available moves.<br /><a href="javas'
		+ 'cript:setupGame()">&gt;&gt;&gt; Click Here To Try Again &lt;&lt;&lt;</a>'};

// Possible locations for the first empty peg.
var START_PEGS = [[2,0], [2,1], [3,1], [4,0], [4,1], [4,2], [4,3], [5,2], [5,4]];

// The different statuses and the current status.
var status = {
	current : 1,
	GAME_OVER : 1,
	PICKING_EMPTY_PEG : 2,
	PLAYING : 3};

var board, selected;

// After the page finally loads...
$(window).bind("load", function()
{
	// Display the first message.
	showMessage(messages.FIRST);
});

function setupGame()
{
	// Blank out all of the pegs on the board.
	$(".peg").set("src", "empty.gif");
	
	// Show the possible pegs that may start off blank.
	for(var i = 0; i < START_PEGS.length; i++)
		$("#row" + START_PEGS[i].join("pegI")).set("src", "peg.gif");

	// Display the message that says to pick the peg to start off empty.
	showMessage(messages.FIRST_HOLE);
	
	// Change the status accordingly.
	status.current = status.PICKING_EMPTY_PEG;
}

// Start the game off with the speicified peg being empty.
function startGame(emptyPegID)
{
	// Create the game board and show all pegs except for the one that was
	// specified by emptyPegID.
	board = [];
	for(var isFull, row = 0; row < DEFAULT_BOARD.length; row++)
	{
		board.push(new Object());
		for(var pegI = 0; pegI < DEFAULT_BOARD[row].length; pegI++)
		{
			pegID = "row" + row + "pegI" + pegI;
			isFull = (pegID != emptyPegID);
			board[row][DEFAULT_BOARD[row][pegI]] = isFull;
		}
	}
	
	// Show the board.
	updateBoardDisplay();

	// Tell the user what to do first.
	showMessage(messages.JUMPER);

	// Change the status accordingly.
	status.current = status.PLAYING;
}

function endGame()
{
}

function hover(elem)
{
	var pegImage = elem.src + "";

	$(elem).setCSS("cursor", /empty\.gif$/.test(pegImage) ? "default" : "pointer");
	if(/peg\.gif$/.test(pegImage))
		$(elem).set("src", "hover.gif");
}

function unhover(elem)
{
	var pegImage = elem.src + "";

	if(/hover\.gif$/.test(pegImage))
		$(elem).set("src", "peg.gif");
}

// When the user attempts to select the peg.
function select(elem)
{
	var pegImage = elem.src + "";
	var isPlaying = (status.current == status.PLAYING);

	if(/empty\.gif$/.test(pegImage))
		return;

	// Reset how the board looks.
	if(isPlaying)
		updateBoardDisplay();

	var matches = elem.id.match(/^row(\d+)pegI(\d+)$/);
	var row = parseInt(matches[1]);
	var pegI = matches[2];
	var peg = parseInt(DEFAULT_BOARD[row][pegI]);

	if(/hover\.gif$/.test(pegImage))
	{
		// The user is not playing.
		if(!isPlaying)
		{
			elem.src = "active.gif";
			// The user picks the first empty peg.
			if(status.current == status.PICKING_EMPTY_PEG)
			{
				showMessage(messages.JUMPER);
				startGame(elem.id);
			}
		}
		else if(checkAvailableMoves(row,peg).length > 0)
		{
			// The player picked a peg which can move to another place.
			elem.src = "active.gif";
			selected = [row, pegI, peg];
			showMessage(messages.LANDING);
			var viables = checkAvailableMoves(row, peg);
			for(var vI = 0; vI < viables.length; vI++)
				setAsPossible(viables[vI][0], viables[vI][1]);
		}
		else
			// The user is playing but there are no available moves.
			showMessage(messages.JUMPER);
	}
	else if(/active\.gif$/.test(pegImage))
	{
		// The user is deselecting the peg.
		elem.src = "hover.gif";
		if(isPlaying)
			showMessage(messages.JUMPER);
	}

	// The user picks a place to move the peg to.
	if(isPlaying && /possible\.gif$/.test(pegImage))
	{
		var midRow = parseInt((row + selected[0]) / 2);
		var midPeg = parseInt((peg + selected[2]) / 2);
		board[selected[0]][selected[2]] = false;
		board[midRow][midPeg] = false;
		board[row][peg] = true;
		updateBoardDisplay();
		elem.onload = new Function("", 'reselectJumper($("#' + elem.id + '")[0]);');
		elem.src = "hover.gif";
	}
}

// Reselects the peg after it jumps to a new hole.
function reselectJumper(elem)
{
	var pegImage = elem.src + "";

	if(/hover\.gif$/.test(pegImage))
	{
		elem.onload = null;
		select(elem);

		// See if there are any other moves that can be had by any single peg on
		// the board.  If not, then end the game.
		var pegsLeft = 0;
		for(var row = 0; row < DEFAULT_BOARD.length; row++)
		{
			for(var peg, pegI = 0; pegI < DEFAULT_BOARD[row].length; pegI++)
			{
				peg = DEFAULT_BOARD[row][pegI];
				if(board[row][peg])
				{
					if(checkAvailableMoves(row, peg).length > 0)
						return;
					else
						pegsLeft++;
				}
			}
		}

		// If there is only one peg left, show the winning message, otherwise show
		// show the losing message.
		showMessage(messages[pegsLeft == 1 ? "WIN" : "LOSS"]);
		status.current = status.GAME_OVER;
	}
}

// Determines where a peg may move to based on the given coordinates.
// Returns a list of coordinates indicating where the peg may move to.
function checkAvailableMoves(row, peg)
{			
	var viables = [[row-2,peg-2], [row-2,peg+2], [row,peg-4], [row,peg+4],
		[row+2,peg-2], [row+2,peg+2]];
	for(var rGoal, pGoal, rMid, pMid, vI = 0; vI < viables.length; vI++)
	{
		rGoal = viables[vI][0];
		pGoal = viables[vI][1];
		rMid = parseInt((rGoal + row) / 2);
		pMid = parseInt((pGoal + peg) / 2);
		// If peg can't jump to viables[vI], remove it and decrement vI.
		if(!(board[rGoal] && board[rGoal][pGoal] == false && board[rMid][pMid]))
			viables.splice(vI--, 1);
	}
	return viables;
}

function updateBoardDisplay()
{
	for(var row = 0; row < DEFAULT_BOARD.length; row++)
	{
		for(var pegI = 0; pegI < DEFAULT_BOARD[row].length; pegI++)
		{
			isFull = (board[row][DEFAULT_BOARD[row][pegI]] == true);
			pegID = "row" + row + "pegI" + pegI;
			$("#" + pegID).set("src", isFull ? "peg.gif" : "empty.gif");
		}
	}
}

function setAsPossible(row, peg)
{
	for(var pegI = 0; pegI < DEFAULT_BOARD[row].length; pegI++)
	{
		if(DEFAULT_BOARD[row][pegI] == peg)
		{
			$("#row" + row + "pegI" + pegI).set("src", "possible.gif");
			return pegI;
		}
	}
}

// Show the specified message below the game board.
function showMessage(msg)
{
	$("#tdMessage").setHTML(msg.replace(/ {2}/g, " &nbsp;"));
}
