// TaylorChess, modified by Mr.Fixit (MrFixit@MrFixitOnline.com) and buti-oxa
// Source based upon http://www.taylor.org/~patrick/chess/client/v0.9/
// Original author email, address not available (if you know it, let me know!)

// [Fixit:] Modified heavily to support online play between 2 players and a TON of code fixes for 
// enpassant, promotions, king in check analysis, etc.

// [buti_oxa]: Lots of further changes over the years, making it a further mess. Sorry, reader.
// My biggest gripe with the original design is the lack of separation between content and presentation.
// Array document.images IS the place where the current game state is stored (in names of images). 
// Yes, that means that when a user flips the board, the state changes. 
// Virtual board I added is not there to replace the model, only to complement it in situations
// where the old model cannot work. I never tried to rewrite the code changing underlining model.


var javascriptMfoChessVersion = '13/5/5';

var rootPath;
var basePath;
var capturepiecepath;
var pieceSet = 'classic/';	

var viewpoint;
var playerColor;

var touchNum = 1;		// 0-position is not current, 1-it is, 2-piece chosen, 3-move chosen

var curMove = 0;		// Dynamic
var newMove = 0;
var iMoveShown = 0;
var fCommentsUpdated = false;

var numWcaptures = 0; // Track number of piece captures (Fixit)
var numBcaptures = 0;
var scoreWcaptures = 0; 
var scoreBcaptures = 0;

var BoardMode = 'actual';			// Virtual for checkmate checking.
var VirtualBoardColor = new Array();
var VirtualBoardRank = new Array();

var strWhitePlayerName;
var strBlackPlayerName;
var rgWhiteComments = new Array();
var rgBlackComments = new Array();

var pgnGameText;

var NumberOfChanges;
var ChangeSaved = new Array();

var Moves = new Array();
var piece = new Array();	// Filled with images of current piece style

var strPossibleCastles;		// list of still possible castlings. For normal (non-random) chess it is
							// 		"<Ke1-g1:Rh1-f1> <Ke1-c1:Ra1-d1> <Ke8-g8:Rh8-f8> <Ke8-c8:Ra8-d8>"

var lastMove = '';
var playerMove = '';		// the move that is being prepared for submission (if present)
var fScrollIntoView = false;
var iCommentHighlighted;


// Game Constant Converter Arrays
var ctoi = new Array();
var itoc = new Array();
var fullname = new Array();
var fullcolor = new Array();
var KRNcode = new Array('NNRKR','NRNKR','NRKNR','NRKRN','RNNKR','RNKNR','RNKRN','RKNNR','RKNRN','RKRNN');

/* list of global variables that should be set outside

var thisName;			// game title
var fPostedGame;
var fIAmPlaying;		// viewer is playing
var fMyMove;			// viewer is playing and it is his move
var my_id;				// id of the viewer 
var white_id;			// white player or challenger
var black_id;			// black player or challenger
var white_name;
var black_name;
var oldMoves;			// moves from the db

// gamestate - 299=challenge made, 200=white to move, 201=black to move
// 300=white won, 301=black won, 302=tie (stalemate/draw) 303-challenge rejected
var gamestate;

var iRandomChess;
var iRandomSeedWhite;
var iRandomSeedBlack;
var strStartingFen;

var challengecolor = 1 for random, 2 for white, 3 for black

*/

// touchNum, playerMove are hidden inputs

function setMoveButtons() {
	var fx, fy;

	if (!fMyMove) return;
	
	if (touchNum == 0) {
		document.getElementById("CurrentInstruction").innerHTML = '';
		document.getElementById("btnCancel").disabled = true;
		document.getElementById("btnCancel").value = "Cancel move";
		document.getElementById("btnSubmit").disabled = true;
		document.getElementById("btnSubmit").value = "Submit move";
		document.getElementById("btnSubmitDraw").disabled = true;
		HighlightOff();
	} 
	if (touchNum == 1) {
		document.getElementById("CurrentInstruction").innerHTML = 'Choose piece to move';
		document.getElementById("btnSubmit").disabled = true;
		document.getElementById("btnCancel").value = "Cancel move";
		document.getElementById("btnSubmit").value = "Submit move";
		document.getElementById("btnCancel").disabled = true;
		document.getElementById("btnSubmitDraw").disabled = true;
		HighlightOff();
	}
	if (touchNum == 2) {
		document.getElementById("CurrentInstruction").innerHTML = 'Select target square';
		document.getElementById("btnCancel").disabled = false;
		document.getElementById("btnCancel").value = "Cancel " + playerMove;
		document.getElementById("btnSubmit").disabled = true;
		document.getElementById("btnSubmit").value = "Submit move";
		document.getElementById("btnSubmitDraw").disabled = true;

		fx = ctoi[playerMove.charAt(0)];
		fy = parseInt(playerMove.charAt(1), 10);
		
		Highlight(fx, fy);
	}
	if (touchNum == 3) {
		
		var pieceRank;
		var tx = ctoi[playerMove.charAt(3)];
		var ty = parseInt(playerMove.charAt(4), 10);
		
		if (isNaN(ty))
			{
			// it must be a promotion

			if (parseInt(playerMove.charAt(1), 10) == 2)
				{
				ty = 1;
				}
			else
				{
				ty = 8;
				}
			
			pieceRank = '';
			}
		else 
			{
			pieceRank = extractPieceRank(tx,ty);

			if (pieceRank == 'P') pieceRank = '';
			}
		
		if (playerMove.substr(0,4) == 'oo-g')
			{
			movePrettied = 'O-O';
			}
		else if (playerMove.substr(0,4) == 'oo-c')
			{
			movePrettied = 'O-O-O';
			}
		else 
			{
			movePrettied = pieceRank + playerMove;
			}
		
		document.getElementById("CurrentInstruction").innerHTML = 'Move ' + movePrettied + ' is ready to submit';
		document.getElementById("btnCancel").disabled = false;
		document.getElementById("btnCancel").value = "Cancel " + movePrettied;
		document.getElementById("btnSubmit").disabled = false;
		document.getElementById("btnSubmit").value = "Submit "+movePrettied;
		document.getElementById("btnSubmitDraw").disabled = false;
		
		Highlight(tx, ty);
	}
}


///////////////////////////////////
/*	
	-------------------------
	INSTANTANEOUS BOARD ACTIONS:
		invertGameBoard()
		changeStyle(newStyle)
	-------------------------
*/


function invertGameBoard() {

	if (viewpoint == 'white') {viewpoint = 'black';} else {viewpoint = 'white';}
	
	alignIndices();
	FlipBoard();
	setPlayerNames();
	
	return;
}


function setPlayerNames() {
	// Function to set the names on the table (Fixit)
	// challengecolor = 1 for random, 2 for white, 3 for black

	var strPlayer1NameDecorated = white_name;
	var strPlayer2NameDecorated = black_name;
	var strArrow = '<img src="chess/your_move.gif" height=15 width=15 alt="player to move"> ';

	// add arrow before the name of the player to make move

	if (gamestate == 200) {
		// white to move	
		strPlayer1NameDecorated = strArrow+white_name;
	}

	if (gamestate == 201) {
		// black to move	
		strPlayer2NameDecorated = strArrow+black_name;
	}

	if (viewpoint == 'white') {
		if ( gamestate == 299 && challengecolor == 3 ) {
			document.getElementById("topplayername").innerHTML = strPlayer1NameDecorated; // p1 is black and on top
			document.getElementById("botplayername").innerHTML = strPlayer2NameDecorated; // p2 is white and on bot
			strWhitePlayerName = black_name;
			strBlackPlayerName = white_name;
		} else {
			document.getElementById("topplayername").innerHTML = strPlayer2NameDecorated; // p2 is black and on top
			document.getElementById("botplayername").innerHTML = strPlayer1NameDecorated; // p1 is white and on bot
			strWhitePlayerName = white_name;
			strBlackPlayerName = black_name;
		}
	} else {
		if ( gamestate == 299 && challengecolor == 3 ) {
			document.getElementById("topplayername").innerHTML = strPlayer2NameDecorated; // p2 is white and on top
			document.getElementById("botplayername").innerHTML = strPlayer1NameDecorated; // p1 is black and on bot
			strWhitePlayerName = black_name;
			strBlackPlayerName = white_name;
		} else {
			document.getElementById("topplayername").innerHTML = strPlayer1NameDecorated; // p1 is white and on top
			document.getElementById("botplayername").innerHTML = strPlayer2NameDecorated; // p2 is black and on bot
			strWhitePlayerName = white_name;
			strBlackPlayerName = black_name;
		}
	}
	if (gamestate == 299) {
		if (challengecolor == 1) {
			document.getElementById("botplayername").innerHTML = white_name + ' OR ' + black_name;
			document.getElementById("topplayername").innerHTML = white_name + ' OR ' + black_name;
		}
	}
}

function changeStyle(newStyle) {
	
	pieceSet = newStyle + '/';
	
	preloadPieces();

	for (x = 1; x < 9; x++) {
		for (y = 1; y < 9; y++) {
			il = 'p'+ x + y;
			imgName = document.images[il].src;
			gif = imgName.indexOf('.gif');
			
			imgName = pieceSet + imgName.substring(gif - 5,gif);

			document.images[il].src	= piece[imgName].src;
		}
	}
	
	return;
}


function FlipBoard() {

	bp = new Array();
	
	for (x = 1; x < 9; x++) {
		for (y = 1; y < 9; y++) {
			i = 'p' + y + x;
			bp[i] = document.images[i].src;
		}
	}
	
	for (x = 1; x < 9; x++) {
		for (y = 1; y < 9; y++) {
			py = 9 - y;
			px = x;

			i = 'p' + perspective(py) + perspective(px);
			pieceColor = extractPieceColorActual(bp[i]);
			pieceRank = extractPieceRankActual(bp[i]);
			drawPiece( pieceColor, pieceRank, y, x );
		}
	}
	
	bp = null;

	FlipCaptured();
	
	return;
}



///////////////////////////////////
/*	
	-------------------------
	PLAYED ACTIONS:
		retraceMove(toMove)
		nextMove()
		drawMove(move)
	-------------------------
*/


function retraceMove(toMove) {

	if (toMove == 'all') {
		toMove = Moves[0];
		touchNum = 1;
	} else {
		touchNum = 0;
	}
	
	setMoveButtons();
	
	curMove = toMove - 1;

	if (toMove == 0)
		{
		document.controlPanel.moveHistory.selectedIndex = toMove;	// let the first move show
		}

	document.controlPanel.moveHistory.selectedIndex = curMove;

	playerMove = '';

	touchNum = 1;
	
	drawStartingBoard();
	initCaptured();

	if (toMove > 0) {
		for (x = 1; x <= toMove; x++) {
			lastMove = Moves[x - 1];
			drawMove(Moves[x]);
		}
	}
	
	alignIndices();
	showComments(toMove);
}


function nextMove() {

	newMove = document.controlPanel.moveHistory.selectedIndex + 1;
	
	if ((curMove + 1) == (newMove)) {
		curMove = newMove;
	} else {
		if ((curMove + 1) < Moves[0]) {
			retraceMove(newMove);
		}
		curMove = newMove;
	} 
	
	if (curMove < Moves[0]) {
		lastMove = Moves[curMove];
		drawMove(Moves[curMove + 1]);
		document.controlPanel.moveHistory.selectedIndex = curMove;  
	}

	showComments(curMove+1);
}

function prevMove() {

	newMove = document.controlPanel.moveHistory.selectedIndex;
	
	curMove = newMove;
	retraceMove(newMove);
	showComments(newMove);
}

function tyFromTo(to, fy) {
	var charLast = to.charAt(1);
	var ty = parseInt(charLast, 10);
	
	// Special case, pawn on 1st or 8th rank defines the piece to promote to
	
	if ( charLast.match(/[QRNB]/)) {
		ty = (fy == 2) ? 1 : 8;
	}

	return ty;
}


function drawMove(move) {

	if (move.charAt(0).match(/[rtm]/))		// Resign or Draw or Mate
		{
		return;								// Do nothing if the game has ended already
		}
	
	var from = move.substring(0,move.indexOf('-'));
	var to = move.substring(move.indexOf('-') + 1);
	var fx = ctoi[from.charAt(0)];
	var fy = parseInt(from.charAt(1), 10);
	var tx = ctoi[to.charAt(0)];
	var ty = tyFromTo(to, fy);

	// Take away enpassant pawn if any
	
	enpassant(fx,fy,tx,ty,lastMove);
			
	if (fx == 'o') {   // Castling move

		executeCastling(to);		// execute and prohibit further castling
	} 
	else {           // Normal move

		px = fx;
		py = 9 - fy;
		
		if (viewpoint == 'black') {
			px = 9 - px;
			py = 9 - py;
		}
			
		pieceLoc = 'p' + py + px;
		
		pieceName = document.images[pieceLoc].src;

		pieceColor = extractPieceColor(fx,fy);
		pieceRank = extractPieceRank(fx,fy);

		// see if this move prohibits castling

		// this regular expression will match all castling that use this piece at this position
		// 		example: move="Ke1-f5 ==> we search for '<' + nonSpaces + 'Ke1' + nonSpaces + '>'

		var re = new RegExp('<\\S*' + pieceRank + from + '\\S*>', 'g'); 
		
		strPossibleCastles = strPossibleCastles.replace(re, '');

		if (BoardMode == 'actual') {
			// Track captured pieces 
			CapturedPiece = extractPieceRank(tx,ty);	
			CapturedPiece = CapturedPiece.toLowerCase();
				
			if (CapturedPiece != 'x') {
				CapturedPieceColor = (pieceColor == 'W') ? 'B' : 'W';
				AddPieceToCaptured(CapturedPiece, CapturedPieceColor);
			}
		}
		
		drawPiece( 'X', 'X', fy, fx );
		
		// Allow for promotions other than just Queen (Fixit)
		
		if ((pieceRank == 'P') && 
				(((ty == 1) && (pieceColor == 'B')) || 
				((ty == 8) && (pieceColor == 'W')))) 
			{
			drawPiece( pieceColor, to.charAt(1), ty, tx );
			} 
		else 
			{
			drawPiece( pieceColor, pieceRank, ty, tx );
			}
	}

	return;
}

// strTo can be "g1" or "g8" or "c1" or "c8"
//	Find castle string using strTo as a key, perform castling, prohibit further castlings of same color

function executeCastling(strTo)
{
var re = new RegExp('<\\S*-' + strTo + '\\S*>');	// non-spaces, -, g1, non-spaces
var match = re.exec(strPossibleCastles); 			// should be successful
var strCastle = match[0];					 		// strCastle may contain <Ke1-g1:Rh1-f1>
var xKingFrom = ctoi[strCastle.charAt(2)];
var xKingTo = ctoi[strCastle.charAt(5)];
var xRookFrom = ctoi[strCastle.charAt(9)];
var xRookTo = ctoi[strCastle.charAt(12)];
var y = parseInt(strCastle.charAt(3), 10);
var pieceColor = (y == 1) ? 'W' : 'B';

// order of operation is important, as one of the two can go to previously occupied by other place.

drawPiece('X', 'X', y, xKingFrom);				// remove king
drawPiece('X', 'X', y, xRookFrom);				// remove rook
			
drawPiece(pieceColor, 'K', y, xKingTo);				// put king
drawPiece(pieceColor, 'R', y, xRookTo);				// put rook

// this regular expression will match all castling on rank ty
// 		example: move="oo-g1 ==> we search for '<' + nonSpaces + '1' + nonSpaces + '>'

re = new RegExp('<\\S*' + y + '\\S*>', 'g');

strPossibleCastles = strPossibleCastles.replace(re, '');
}

///////////////////////////////////
/*	?
	-------------------------
	ACTIVE PLAYER PIECE MOVEMENT:
		touchPiece(ip)
	-------------------------
*/


function touchPiece(ip) {
	if ((curMove+1) < Moves[0]) {
		//	Have to go to the end before making new moves
		retraceMove('all'); 
		return;
	}
	
	if ((gamestate < 200) || (gamestate > 299)) {
		alert('Game is not active!');
		return;
	} 
	
	if (!fMyMove) {
		alert('Not your move!');
		return;
	}		
	
	if (touchNum == 3) {
		alert('You have made a move.  Use "Submit" to finish the move or "Cancel" to make a different move.');
		return;
	}
	
	if (document.controlPanel) {

		// Get Game position
		ty = 9 - Math.floor(ip/10);
		tx = ip%10;	
		if (viewpoint == 'black') {
			tx = 9 - tx;
			ty = 9 - ty;
		}

		tp = document.images['p' + ip].src;
	
		pr = extractPieceRankActual(tp);
		pc = extractPieceColorActual(tp);
		
		if (touchNum == 1) {
			if (pr != 'X') {
				if (pc == playerColor) {
					touchNum = 2;
					playerMove = '' + itoc[tx] + ty + '-';
					setMoveButtons();
				}
			} 
		
		} else if (touchNum == 2) {
			nm = playerMove + '' + itoc[tx] + ty;
			mr = checkMove(nm);		

			if (mr.substr(0,5) == 'Error')
				{
				alert(mr);
				}
			else
				{
				drawMove(mr);
				touchNum = 3;
				playerMove = mr;
				setMoveButtons();
				} 
		} 
	
	} else {
		alert('You must first finish what you are doing.');
	}

	return;
}


// returns false if move is not possible, move notation otherwise

function checkMove(move) {

	var from = move.substring(0,move.indexOf('-'));
	var to = move.substring(move.indexOf('-') + 1);
	var fx = ctoi[from.charAt(0)];
	var fy = parseInt(from.charAt(1), 10);
	var tx = ctoi[to.charAt(0)];
	var ty = parseInt(to.charAt(1), 10);

	var pieceTouched = extractPieceRank(fx,fy);
	var checkResult = 'No piece to move';
	
	if ((fx == tx) && (fy == ty)) {return 'Error: No movement';}

	// next two are special because of possibility of castling

	if (pieceTouched == 'K') {
		return checkKingMove(fx,fy,tx,ty,move);
		}
		
	if (pieceTouched == 'R') {
		return checkRookMove(fx,fy,tx,ty, move);
		}
				
	if (pieceTouched == 'P') 
		{
		// REVIEW Is next assignment needed? Can it be moved to a better place?
		// I moved it already from inside legalPawnMove
		lastMove = Moves[Moves[0]];	

		checkResult = legalPawnMove(fx,fy,tx,ty);
		
		if (checkResult != "OK") 
			{
			return 'Error: ' + checkResult;
			}
		else
			{
			if (ty == 1 || ty == 8) 
				{  
				// Pawn promotion
			
				if (BoardMode == 'virtual')
					{
					// We only get here in virtual mode while checking if the move saves king 
					// from checkmate. For that purpose one promotion is as good as another.
					
					return move.substring(0,4) + 'Q';
 					}
				else
					{
					var pcNew = prompt("Promote to what piece? (Q = queen, R = rook, B = bishop, N = knight)","");
					
					if (pcNew != 'Q' && pcNew != 'R' && pcNew != 'B' && pcNew != 'N') 
						{
						return 'Error: Invalid key pressed ' + pcNew;
						}
					else 
						{
						return move.substring(0,4) + pcNew;
						}
					}
				}
			else
				{
				return move;
				}
			}
		}
		
	if (pieceTouched == 'B') {
		checkResult = legalBishopMove(fx,fy,tx,ty);
		
	} else if (pieceTouched == 'N') {
		checkResult = legalKnightMove(fx,fy,tx,ty);
			
	} else if (pieceTouched == 'Q') 
		{
		if (fx == tx || fy == ty) {
			checkResult = legalRookMove(fx,fy,tx,ty);
			}
		else {
			checkResult = legalBishopMove(fx,fy,tx,ty);
			}
		}

	// Rook, knight, bishop and queen come here. Remaining check is for taking your own piece.

	if (checkResult == "OK" && extractPieceColor(fx,fy) == extractPieceColor(tx,ty)) {
		checkResult = error_suicide();
		}

	if (checkResult == "OK") {return move;} 

	return 'Error: ' + checkResult;
}


// returns move notation if the move is OK, or "Error: error message" otherwise
//	move notation is different from input one in case of castling

function checkKingMove(fx,fy,tx,ty,move) {

	var dx = Math.abs(tx - fx);
	var dy = Math.abs(ty - fy);

	if (dx <= 1 && dy <= 1)
		{
		// Need to check that new square is not in check
		
		if (isbeingattacked(tx,ty,extractPieceColor(fx,fy)) == true) {

			return 'Error: Cannot move into check!';
		}
		
		// distance is right - check if the square is occupied
		
		if (extractPieceColor(fx,fy) != extractPieceColor(tx,ty))
			{
			return move;
			}
		}

	// Getting here means that the move is invalid unless it is a castling move
	// See if our move is amongst still possible castlings.

	// search for <Ke1-g1 + non-spaces + > (in case of white short castle)
	
	var re = new RegExp('<K' + move + '\\S*>');		
	var match = re.exec(strPossibleCastles); 			

	if (!match) 
		{
		return 'Error: ' + error_illegalMove(fx,fy);
		}
	
	var strCastle = match[0];					 		// strCastle may contain <Ke1-g1:Rh1-f1>

	strCastleMessage = CanCastle(strCastle);

	if (strCastleMessage == 'Y') 
		{
			return 'oo-' + strCastle.substr(5, 2);
		}

	return 'Error: ' + strCastleMessage;	
}

// returns move notation if the move is OK, error message otherwise

function checkRookMove(fx,fy,tx,ty,move) {

	var checkResult = legalRookMove(fx,fy,tx,ty);

	if (checkResult == 'OK' && extractPieceColor(fx,fy) == extractPieceColor(tx,ty)) {
		checkResult = error_suicide();
		}

	if (checkResult == 'OK') {
		return move;
		}
	
	// Getting here means that the move is invalid unless it is a castling move
	// See if our move is amongst still possible castlings.

	// search for < + non-spaces + Rh1-f1> (in case of white short castle)
	
	var re = new RegExp('<\\S*' + move + '>');		
	var match = re.exec(strPossibleCastles); 			

	if (!match) 
		{
		return 'Error: ' + checkResult;
		}
	
	var strCastle = match[0];					 		// strCastle may contain <Ke1-g1:Rh1-f1>

	strCastleMessage = CanCastle(strCastle);

	if (strCastleMessage == 'Y') 
		{
			return 'oo-' + strCastle.substr(5, 2);
		}

	return 'Error: ' + strCastleMessage;	
}

// Checks if the castling described in strCastle is possible, returns "Y" or error message
// Example of strCastle: "<Ke1-g1:Rh1-f1>"

function CanCastle(strCastle) {

	var strKingStart = strCastle.substr(2,2);
	var strKingEnd = strCastle.substr(5,2);
	var strRookStart = strCastle.substr(9,2);
	var strRookEnd = strCastle.substr(12,2);

	// first check if the rook's path is obstructed (ignore king's initial position)

	if (fPathObstructed(strRookStart, strRookEnd, strKingStart))
		{
		return "Rook's path is obstructed";
		}
	
	// same for the king

	if (fPathObstructed(strKingStart, strKingEnd, strRookStart))
		{
		return "King's path is obstructed";
		}
	
	// check for checks along king's way
	
	if (fCheckedAlongPath(strKingStart, strKingEnd))
		{
		return "Check prevents castling";
		}

	return 'Y';
}

function fPathObstructed(sqStart, sqEnd, sqIgnore) {
	
	var xFrom = ctoi[sqStart.charAt(0)];
	var xTo = ctoi[sqEnd.charAt(0)];
	var xIgnore = ctoi[sqIgnore.charAt(0)];
	var y = parseInt(sqStart.charAt(1), 10);
	var xStep = (xTo > xFrom) ? 1 : -1;
	var xStop = xTo + xStep;
	var x; 

	x = xFrom + xStep;

	while (x != xStop )
		{
		if (x != xIgnore)
			{
			if (extractPieceColor(x,y) != 'X')
				{
				return true;
				}
			}
		
		x += xStep;
		}

	return false;
}

function fCheckedAlongPath(sqStart, sqEnd) {
	
	var xFrom = ctoi[sqStart.charAt(0)];
	var xTo = ctoi[sqEnd.charAt(0)];
	var y = parseInt(sqStart.charAt(1), 10);
	var piece_color = (y == 1) ? 'W' : 'B';
	var xStep = (xTo > xFrom) ? 1 : -1;
	var xStop = xTo + xStep;
	var x; 

	x = xFrom;

	while (x != xStop )
		{
		if (isbeingattacked(x,y,piece_color))
			{
			return true;
			}
		
		x += xStep;
		}

	return false;
}

// Do en passant check (and zap the passed pawn) 

function enpassant(fx,fy,tx,ty,lastMove)
{
	if ( (ty != 3 && ty != 6) || lastMove == '' ) {
		return false;				
	}
	
	if (extractPieceRank(fx,fy) == 'P') {
		fc = extractPieceColor(fx,fy);
		tc = extractPieceColor(tx,ty);
		
		wMove = '';
		bMove = '';
		if (tx == 1) { wMove = 'a2-a4'; bMove = 'a7-a5'; }
		if (tx == 2) { wMove = 'b2-b4'; bMove = 'b7-b5'; }
		if (tx == 3) { wMove = 'c2-c4'; bMove = 'c7-c5'; }
		if (tx == 4) { wMove = 'd2-d4'; bMove = 'd7-d5'; }
		if (tx == 5) { wMove = 'e2-e4'; bMove = 'e7-e5'; }
		if (tx == 6) { wMove = 'f2-f4'; bMove = 'f7-f5'; }
		if (tx == 7) { wMove = 'g2-g4'; bMove = 'g7-g5'; }
		if (tx == 8) { wMove = 'h2-h4'; bMove = 'h7-h5'; }
	
		if ( (ty == 3) && (fc == 'B') &&
			(extractPieceColor(tx,4) == 'W') &&
			(extractPieceRank(tx,4) == 'P') &&
			(lastMove == wMove) ) 
		{
	
			AddPieceToCaptured('p', 'W');
			drawPiece( 'X', 'X', 4, tx );
			return true;
		} else {
			if ( (ty == 6) && (fc == 'W') &&
				(extractPieceColor(tx,5) == 'B') &&
				(extractPieceRank(tx,5) == 'P') &&
				(lastMove == bMove) ) 
			{
				AddPieceToCaptured('p', 'B');
				drawPiece( 'X', 'X', 5, tx );
				return true;
			}
		}
	}
	return false;
}

function isbeingattacked(piece_x,piece_y,piece_color) {
	// Function to check if a piece is under attack by the opponent (use to see if the King is in check, for example) (Fixit)
	isattacked = false;

	// Check rank and file attacks (rook, queen, king) (14 possible attack squares - can be blocked)
	temp_x = piece_x + 1; isblocked = false; // check north
	while ((temp_x < 9) && (isblocked == false)) {
		checkrank = extractPieceRank(temp_x,piece_y)
		if (checkrank != 'X') {
			isblocked = true;
			if ((extractPieceColor(temp_x,piece_y) != piece_color) && 
				( (checkrank == 'Q') || (checkrank == 'R') || (checkrank == 'K') ) ) 
				{ if ((checkrank != 'K') || ((temp_x - piece_x) == 1)) {isattacked = true; } }
		}
		temp_x = temp_x + 1;
	}
	
	temp_x = piece_x - 1; isblocked = false; // check south
	while ((temp_x > 0) && (isblocked == false)) {
		checkrank = extractPieceRank(temp_x,piece_y);
		if (checkrank != 'X') {
			isblocked = true;
			if ((extractPieceColor(temp_x,piece_y) != piece_color) && 
				( (checkrank == 'Q') || (checkrank == 'R') || (checkrank == 'K') ) ) 
				{ if ((checkrank != 'K') || ((piece_x - temp_x) == 1)) {  isattacked = true; } }
		}
		temp_x = temp_x - 1;
	}
	
	temp_y = piece_y + 1; isblocked = false; // check east
	while ((temp_y < 9) && (isblocked == false)) {
		checkrank = extractPieceRank(piece_x,temp_y)
		if (checkrank != 'X') {
			isblocked = true;
			if ((extractPieceColor(piece_x,temp_y) != piece_color) && 
				( (checkrank == 'Q') || (checkrank == 'R') || (checkrank == 'K') ) ) 
				{ if ((checkrank != 'K') || ((temp_y - piece_y) == 1)) {  isattacked = true; } }
		}
		temp_y = temp_y + 1;
	}	
	
	temp_y = piece_y - 1; isblocked = false; // check west
	while ((temp_y > 0) && (isblocked == false)) {
		checkrank = extractPieceRank(piece_x,temp_y)
		if (checkrank != 'X') {
			isblocked = true;
			if ((extractPieceColor(piece_x,temp_y) != piece_color) && 
				( (checkrank == 'Q') || (checkrank == 'R') || (checkrank == 'K') )) 
				{ if ((checkrank != 'K') || ((piece_y - temp_y) == 1)) {  isattacked = true; } }
		}
		temp_y = temp_y - 1;
	}	
	
	
	// Check diagonal attacks (queen, bishop, pawn, king) (13 possible attack squares - can be blocked)
	temp_x = piece_x + 1; temp_y = piece_y + 1; isblocked = false; // check north-east
	while ((temp_y < 9) && (temp_x < 9) && (isblocked == false)) {
		checkrank = extractPieceRank(temp_x,temp_y)
		if (checkrank != 'X') {
			isblocked = true;
			numspaces = temp_x - piece_x;
			if ( (checkrank == 'P') && (piece_color == 'B') ) { numspaces = 0; } // NE P check suspended for Black
			if ((extractPieceColor(temp_x,temp_y) != piece_color) && 
				( (checkrank == 'Q') || (checkrank == 'B') || (checkrank == 'P') || (checkrank == 'K') )) 
				{ if (((checkrank != 'P') && (checkrank != 'K')) || (numspaces == 1)) {  isattacked = true; } }
		}
		temp_x = temp_x + 1; temp_y = temp_y + 1;
	}	

	temp_x = piece_x + 1; temp_y = piece_y - 1; isblocked = false; // check south-east
	while ((temp_y > 0) && (temp_x < 9) && (isblocked == false)) {
		checkrank = extractPieceRank(temp_x,temp_y)
		if (checkrank != 'X') {
			isblocked = true;
			numspaces = temp_x - piece_x;
			if ( (checkrank == 'P') && (piece_color == 'W') ) { numspaces = 0; } // SE P check suspended for White
			if ((extractPieceColor(temp_x,temp_y) != piece_color) && 
				( (checkrank == 'Q') || (checkrank == 'B') || (checkrank == 'P') || (checkrank == 'K') )) 
				{ if (((checkrank != 'P') && (checkrank != 'K')) || (numspaces == 1)) {  isattacked = true; } }
		}
		temp_x = temp_x + 1; temp_y = temp_y - 1;
	}	

	temp_x = piece_x - 1; temp_y = piece_y - 1; isblocked = false; // check south-west
	while ((temp_y > 0) && (temp_x > 0) && (isblocked == false)) {
		checkrank = extractPieceRank(temp_x,temp_y)
		if (checkrank != 'X') {
			isblocked = true;
			numspaces = piece_x - temp_x;
			if ( (checkrank == 'P') && (piece_color == 'W') ) { numspaces = 0; } // SW P check suspended for White
			if ((extractPieceColor(temp_x,temp_y) != piece_color) && 
				( (checkrank == 'Q') || (checkrank == 'B') || (checkrank == 'P') || (checkrank == 'K') )) 
				{ if (((checkrank != 'P') && (checkrank != 'K')) || (numspaces == 1)) {  isattacked = true; } }
		}
		temp_x = temp_x - 1; temp_y = temp_y - 1;
	}	

	temp_x = piece_x - 1; temp_y = piece_y + 1; isblocked = false; // check north-west
	while ((temp_y < 9) && (temp_x > 0) && (isblocked == false)) {
		checkrank = extractPieceRank(temp_x,temp_y)
		if (checkrank != 'X') {
			isblocked = true;
			numspaces = piece_x - temp_x;
			if ( (checkrank == 'P') && (piece_color == 'B') ) { numspaces = 0; } // NW P check suspended for Black
			if ((extractPieceColor(temp_x,temp_y) != piece_color) && 
				( (checkrank == 'Q') || (checkrank == 'B') || (checkrank == 'P') || (checkrank == 'K') )) 
				{ if (((checkrank != 'P') && (checkrank != 'K')) || (numspaces == 1)) {  isattacked = true; } }
		}
		temp_x = temp_x - 1; temp_y = temp_y + 1;
	}	
	
	// Check horse attacks (8 possible attack squares)
	opp_color = 'W';
	if (piece_color == 'W') { opp_color = 'B'; }
	if (isOppHorse(piece_x - 2,piece_y - 1,opp_color) == true) {isattacked = true; }
	if (isOppHorse(piece_x - 1,piece_y - 2,opp_color) == true) {isattacked = true; }
	if (isOppHorse(piece_x - 2,piece_y + 1,opp_color) == true) {isattacked = true; }
	if (isOppHorse(piece_x - 1,piece_y + 2,opp_color) == true) {isattacked = true; }
	if (isOppHorse(piece_x + 2,piece_y - 1,opp_color) == true) {isattacked = true; }
	if (isOppHorse(piece_x + 1,piece_y - 2,opp_color) == true) {isattacked = true; }
	if (isOppHorse(piece_x + 2,piece_y + 1,opp_color) == true) {isattacked = true; }
	if (isOppHorse(piece_x + 1,piece_y + 2,opp_color) == true) {isattacked = true; }

	return isattacked;
}

function isOppHorse(hx,hy,hc) {
	// Return true if this square is an opponent horse (Fixit)
	if ((hx > 0) && (hy > 0) && (hx < 9) & (hy < 9)) {
		if ( (extractPieceColor(hx,hy) == hc) &&
				(extractPieceRank(hx,hy) == 'N') ) {
			return true;
		} else {
			return false;
		}
	} else {
		return false;
	}
}

function kingInCheck(piece_color) {
	// Return true if King of this color is in check (Fixit)
	kingFound = false; kx = 1; 
	while ((kingFound != true) && (kx < 9)) {
		ky = 1;
		while ((kingFound != true) && (ky < 9)) {
			if ((extractPieceColor(kx,ky) == piece_color) 
				&&  (extractPieceRank(kx,ky) == 'K') ) {
				kingFound = true; 
			} else {
				ky = ky + 1;
			}
		}
		if (kingFound != true) { kx = kx + 1; }
	}

	return isbeingattacked(kx,ky,piece_color);
}

function legalPawnMove(fx,fy,tx,ty) {

	var fc = extractPieceColor(fx,fy);
	var tc = extractPieceColor(tx,ty);
	var dx = Math.abs(tx - fx);
	var dy = Math.abs(ty - fy);
		
	var legalDir = (fc == 'W') ? (1) : (-1);

	if (tc != 'X') 
		{	
		// pawn takes

		if (fc == tc) return error_suicide();
		
		if ((ty - fy) != legalDir || dx != 1 || dy != 1) 
			{
			return error_illegalMove(fx,fy);
			}

		return "OK";
		}
	
	// Disallow x-based movement on a non-capture and to allow for en passant moves
	
	if (dx != 0) {
		if (enpassant(fx,fy,tx,ty,lastMove) == true) {
			return "OK";
		} else {
			return error_illegalMove(fx,fy);
		}
	}
	
	if ((ty - fy) == (2 * legalDir)) {   // Check for first move
		sp = (fc == 'W') ? (2) : (7);
		if ((sp == fy) && (extractPieceColor(fx,(fy + legalDir)) == 'X') && (tc == 'X')) {
			return "OK";
		} else {
			return error_illegalMove(fx,fy);
		}
		
	} else if (((ty - fy) != legalDir) || (dx != 0)) {
		return error_illegalMove(fx,fy);
	}

	return "OK";
}


function legalKnightMove(fx,fy,tx,ty) {

	dx = Math.abs(tx - fx);
	dy = Math.abs(ty - fy);

	if (((dy + dx) != 3) || (dx < 1) || (dx > 2) || (dy < 1) || (dy > 2)) {
		return error_illegalMove(fx,fy);
	}

	return 'OK';
}


function legalBishopMove(fx,fy,tx,ty) {

	if (Math.abs(tx - fx) != Math.abs(ty - fy)) {
		return error_illegalMove(fx,fy);
	}
	
	xinc = (fx < tx) ? (1) : (-1);
	yinc = (fy < ty) ? (1) : (-1);
	dist = Math.abs(tx - fx);
	
	for (z = 1; z < dist; z++) {
		dx = fx + (z * xinc);
		dy = fy + (z * yinc);

		if (extractPieceColor(dx,dy) != 'X') {
			return error_blockedPath(dx,dy);
		}		
	}

	return 'OK';
}


function legalRookMove(fx,fy,tx,ty) {

	if ((fx != tx) && (fy != ty )) {
		return error_illegalMove(fx,fy);
	}
	
	if (fx != tx) {
		start = !(fx < tx) ? tx : fx;
		end = (fx < tx) ? tx : fx;
			
		for (z = (start+1); z < end; z++) {				
			if (extractPieceColor(z,fy) != 'X') {
				return error_blockedPath(z,fy);
			}
		}
					
	} else {
		start = !(fy < ty) ? ty : fy;
		end = (fy < ty) ? ty : fy;
			
		for (z = (start+1); z < end; z++) {
			if (extractPieceColor(fx,z) != 'X') {
				return error_blockedPath(fx,z);
			}
		}	
	}

	return 'OK';
}



///////////////////////////////////
/*	
	MOVE ERROR RESULTS
*/
		
function error_blockedPath(x,y) {
	colored = fullcolor[extractPieceColor(x,y)];
	pc = fullname[extractPieceRank(x,y)];
	return 'There is a ' + colored + ' ' + pc + ' blocking the path at ' + itoc[x] + y;
}

function error_illegalMove(x,y) {
	return 'A ' + fullname[extractPieceRank(x,y)] + ' cannot be moved like that.';
}

function error_suicide() {
	return 'You cannot take your own piece.';
}


///////////////////////////////////
/*	
	-------------------------
	GAME PIECE DATA CONVERSION ROUTINES:
		extractPieceColor(str)
		extractPieceRank(str)
		imageLocation(x,y)
		convertCartesianToAlgebraic(mv)
		perspective(val)
		
buti_oxa: extract functions changed so they work either with real board, or with my copy of it.

	-------------------------
*/

		

		
function extractPieceColorActual(str) {
	
	tokenLoc = str.lastIndexOf('.gif');
	return str.charAt(tokenLoc-3);
}
		
function extractPieceColor(x, y) {
	if (BoardMode == 'actual') {
		return extractPieceColorActual(document.images[imageLocation(x,y)].src)
	}

	return VirtualBoardColor['p' + y + x];
}


function extractPieceRankActual(str) {
	
	tokenLoc = str.lastIndexOf('.gif');
	return str.charAt(tokenLoc-1);
}

function extractPieceRank(x, y) {

	if (BoardMode == 'actual') {
		return extractPieceRankActual(document.images[imageLocation(x,y)].src)
	}

	return VirtualBoardRank['p' + y + x];
}


function imageLocation(x,y) {	// Cartesian -> Physical
	y = 9 - y;
	if (viewpoint == 'black') {
		x = 9 - x;
		y = 9 - y;	
	}
	return 'p' + y + x;
}


function perspective(val) {

	/*  This function's usage is somewhat muddled.
	
		It is only used in lower-level conversion
		operations between internal data conventions
		and the bizarre case of a Cartesian-ordered
		set of screen image names.
	
		The names in the document.images Array are all
		named p11 - p88, expanding rows before columns.
		But after the intuitive conversion to Cartesian,
		the default view of a chess board is inherently
		bottom-left-centric.  The 'a' rank is supposed
		to be found at bottom=white (reversed y from Cartesian)
		or at bottom=black (standard Cartesian).
	*/
	
	if (viewpoint == 'white') {
		return (9 - val);
	} else {
		return (val);
	}
}



///////////////////////////////////
/*	
	-------------------------
	DRAW ROUTINES:
		drawPiece(pieceColor,pieceRank,y,x)
		alignIndices()
		displayStatus(stat)
		drawStartingBoard()

	-------------------------
*/

		
// buti_oxa: drawPiece now works either with real board, or with my copy of it.

function drawPiece(pieceColor,pieceRank,y,x) { // eg. W_X_X.gif
	var p;

	if (BoardMode == 'virtual') {
		p = 'p' + y + x;

		ChangeSaved[NumberOfChanges] = VirtualBoardColor[p]+VirtualBoardRank[p]+p;
			
		VirtualBoardColor[p] = pieceColor;
		VirtualBoardRank[p] = pieceRank;

		NumberOfChanges++;

		return;
	}

	y = 9 - y;	
	if (viewpoint == 'black') {
		x = 9 - x;
		y = 9 - y;
	}
	p = 'p' + y + x;
	
	if ( ((x + y) / 2) == Math.floor((x + y) / 2) ) {  // Is sum of digits an even number?
		tileColor = 'W';
	} else {
		tileColor = 'B';
	}
	
	loc = pieceSet + tileColor + '_' + pieceColor + '_' + pieceRank;
	
	if (piece[loc]) {
		document.images[p].src = piece[loc].src;
	} 
	
	return;
}

function initCaptured() {

	numWcaptures = 0; // Track number of piece captures (Fixit)
	scoreWcaptures = 0;
	numBcaptures = 0;
	scoreBcaptures = 0;
	
	document.getElementById("title_captured").style.visibility = "hidden";
	document.getElementById("topcaptured").innerHTML = "";
	document.getElementById("botcaptured").innerHTML = "";
	
	for (x = 1; x <= 15; x++) {
		// Set captured piece to blank
		document.getElementById("topcaptured" + x).src = "b.gif";
		document.getElementById("botcaptured" + x).src = "b.gif";
	}
		
	return;
}

function AddPieceToCaptured(piece, pieceColor) {

	document.getElementById("title_captured").style.visibility = "visible";
	
	targetscore = 1;
	
	if (piece == 'q') { targetscore = 9; }
	if (piece == 'r') { targetscore = 5; }
	if ((piece == 'n') || (piece == 'b')) { targetscore = 3; }

	if (pieceColor == 'B') {
		numWcaptures = numWcaptures + 1;
		scoreWcaptures = scoreWcaptures + targetscore;
		
		if (viewpoint == 'black') {
			myPlace = "top";
		}
		else {
			myPlace = "bot";
		}
		
		document.getElementById(myPlace + 'captured' + numWcaptures).src = capturepiecepath + 'b_' + piece + '.gif';
		document.getElementById(myPlace + 'captured').innerHTML = "By White<br>Points: " + scoreWcaptures;

	} else {
		numBcaptures = numBcaptures + 1;
		scoreBcaptures = scoreBcaptures + targetscore;
		
		if (viewpoint == 'black') {
			myPlace = "bot";
		}
		else {
			myPlace = "top";
		}
		
		document.getElementById(myPlace + 'captured' + numBcaptures).src = capturepiecepath + 'w_' + piece + '.gif';
		document.getElementById(myPlace + 'captured').innerHTML = "By Black<br>Points: " + scoreBcaptures;
	}
}


function FlipCaptured() {

	// flip the images
	
	for (i = 1; i < 16; i++) {
		imageName = 'topcaptured' + i;
		objTop = document.images[imageName];
		srcTop = objTop.src;
		imageName = 'botcaptured' + i;
		objBot = document.images[imageName];
		srcBot = objBot.src;

		objTop.src = srcBot;
		objBot.src = srcTop;
	}

	// redraw the scores 
	
	objTop = document.getElementById("topcaptured");
	textTop = objTop.innerHTML;
	objBot = document.getElementById("botcaptured");
	textBot = objBot.innerHTML;

	objTop.innerHTML = textBot;
	objBot.innerHTML = textTop;
	
	return;
}

function alignIndices() {
	document.images.aIndex.src = basePath + 'l_' + viewpoint + '.gif';
	document.images.nIndex.src = basePath + 'n_' + viewpoint + '.gif';
	return;
}


function displayStatus(stat) {
	document.images['gameStatus'].src = basePath + stat + '.gif';
	return;
}

// global strStartingFen is the hidden input

function drawStartingBoard() {

	var x, y;

	// draw empty squares

	for (y=3; y<7; y++) {
		for (x=1; x<9; x++) {
			drawPiece( 'X', 'X', y, x );
		}	
	}

	// draw pawns

	for (x=1; x<9; x++) {
		drawPiece( 'W', 'P', 2, x );
		drawPiece( 'B', 'P', 7, x );
	}	

	// draw pieces, init castle string (setPiecesRandomly writes into strPossibleCastles)

	strPossibleCastles = '';

	if (iRandomChess == '1')
		{
		setPiecesRandomly('W', 1, iRandomSeedWhite);
		setPiecesRandomly('B', 8, iRandomSeedWhite);
		}
	else if (iRandomChess == '2')
		{
		setPiecesRandomly('W', 1, iRandomSeedWhite);
		setPiecesRandomly('B', 8, iRandomSeedBlack);
		}
	else if (iRandomChess == 'F' && strStartingFen != '')
		{
		setPiecesGivenFen(strStartingFen);
		}
	else
		{
		drawPiece( 'W', 'R', 1, 1 );
		drawPiece( 'W', 'N', 1, 2 );
		drawPiece( 'W', 'B', 1, 3 );
		drawPiece( 'W', 'Q', 1, 4 );
		drawPiece( 'W', 'K', 1, 5 );
		drawPiece( 'W', 'B', 1, 6 );
		drawPiece( 'W', 'N', 1, 7 );
		drawPiece( 'W', 'R', 1, 8 );
		drawPiece( 'B', 'R', 8, 1 );
		drawPiece( 'B', 'N', 8, 2 );
		drawPiece( 'B', 'B', 8, 3 );
		drawPiece( 'B', 'Q', 8, 4 );
		drawPiece( 'B', 'K', 8, 5 );
		drawPiece( 'B', 'B', 8, 6 );
		drawPiece( 'B', 'N', 8, 7 );
		drawPiece( 'B', 'R', 8, 8 );
		
		strPossibleCastles = "<Ke1-g1:Rh1-f1> <Ke1-c1:Ra1-d1> <Ke8-g8:Rh8-f8> <Ke8-c8:Ra8-d8>";
		}

	return;
}


function setPiecesGivenFen(strFen) {

	// extract initial posision from FEN

	var re = new RegExp('^([qrkbn]+)\/');		
	var match = re.exec(strFen); 	
	fenBlack = match[1].toUpperCase();

	re = new RegExp('\/([KQRBN]+)\\s');		
	match = re.exec(strFen); 	
	fenWhite = match[1];

	setSideGivenLayout(fenBlack, 8, 'B');
	setSideGivenLayout(fenWhite, 1, 'W');
}

function setSideGivenLayout(sPiecesLayout, rank, sColor) {

	var fileRook1 = 0;
	var fileKing, fileRook2;

	// set pieces, find rooks and king
	
	for (var x=1; x<9; ++x)	
		{
		sPiece = sPiecesLayout.substr(x-1,1);
		drawPiece( sColor, sPiece, rank, x );

		if (sPiece == 'K')
			fileKing = itoc[x];

		if (sPiece == 'R')
			{
			if (fileRook1 == 0)
				fileRook1 = itoc[x];
			else
				fileRook2 = itoc[x];
			}
		}

	// set possible castles global
	
	strPossibleCastles += 
		'<K' + fileKing + rank + '-g' + rank + ':R' + fileRook2 + rank + '-f' + rank + '> ' +
		'<K' + fileKing + rank + '-c' + rank + ':R' + fileRook1 + rank + '-d' + rank + '> ';
}

// Places pieces one by one, strFreeFiles contains remaining free places.

function setPiecesRandomly(color, rank, cSeed) {

	var seed1, seed2;
	var index, iFile, cFile, cPiece;
	var strFreeFiles = '12345678';		// list of free squares
	var strKRN;
	var fileRook1, fileKing, fileRook2;

	if (gamestate == 299)
		{
		// challenge is not accepted yet, draw impossible position instead
		for (iFile = 1; iFile < 9; iFile++)
			{
			drawPiece( color, 'N', rank, iFile);
			}

		return;
		}

	// random seed must be between 0 and 960. BTW, 518 generates standard initial position.

	seed2 = parseInt(cSeed, 10) % 960;

	// placing light-squared (for white) bishop
	// seed 1 gives one of the 4 possible positions.

	seed1 = seed2 % 4;
	seed2 = Math.floor(seed2 / 4);

	iFile = 2 + seed1 * 2;

	drawPiece( color, 'B', rank, iFile);
	
	strFreeFiles = DeleteNumber(strFreeFiles, iFile.toString());

	// placing black-squared (for white) bishop

	seed1 = seed2 % 4;
	seed2 = Math.floor(seed2 / 4);

	iFile = 1 + seed1 * 2;
	
	drawPiece( color, 'B', rank, iFile);
	
	strFreeFiles = DeleteNumber(strFreeFiles, iFile.toString());

	// placing queen on one of five remaining places

	seed1 = seed2 % 6;
	seed2 = Math.floor(seed2 / 6);

	cFile = strFreeFiles.substr(seed1, 1)

	drawPiece( color, 'Q', rank, parseInt(cFile, 10));
	
	strFreeFiles = DeleteNumber(strFreeFiles, cFile);
	
	// Placing the rest of the pieces
	// Knights, rooks are interchangeable. King must be placed between the two rooks.
	// That leaves 10 variants, enumerated in static KRNcode array

	// Notice where rooks and king go to initialize castle string
	
	strKRN = KRNcode[seed2];

	fileRook1 = 'still empty';
	
	for (index = 0; index < 5; index++) 
		{
		iFile = parseInt(strFreeFiles.substr(index, 1), 10);
		cPiece = strKRN.substr(index, 1);

		if (cPiece == 'R')
			{
			if (fileRook1 == 'still empty')
				{
				fileRook1 = itoc[iFile];
				}
			else
				{
				fileRook2 = itoc[iFile];
				}
			}

		if (cPiece == 'K')
			{
			fileKing = itoc[iFile];
			}

		drawPiece( color, cPiece, rank, iFile);
		}

	strPossibleCastles += 
		'<K' + fileKing + rank + '-g' + rank + ':R' + fileRook2 + rank + '-f' + rank + '> ' +
		'<K' + fileKing + rank + '-c' + rank + ':R' + fileRook1 + rank + '-d' + rank + '> ';

	return;
}

function DeleteNumber(strFiles, strNumber) {
	re = new RegExp(strNumber)
	return strFiles.replace(re, '');
}

function addStartingPosition2PGN() {

	strFen = getdiagramdata(1);

	pgnGameText += ' [Variant "fischerandom"] [SetUp "1"] [FEN "' + 
		strFen.substr(0, strFen.length-1) + '- - 0 1"]';		
}


function strComments2rgComments(strInput, rgComments) {

var rgInput = strInput.split('|');
var nCurrentMove = 0;
var fMoveRecord;

for (i = 0; i < rgInput.length; i++) 
	{
	strInputPiece = rgInput[i];

	fMoveRecord = false;
	
	// see if the current piece is move number - format mNN

	if (strInputPiece.charAt(0) == 'm')
		{
		strAfterM = strInputPiece.substr(1);
		nMoveMaybe = parseInt(strAfterM, 10);
		
		strMoveMaybe = nMoveMaybe.toString();

		if (strAfterM == nMoveMaybe.toString())
			{
			// looks like move number

			nCurrentMove = nMoveMaybe;
			fMoveRecord = true;
			}
		}

	if (!fMoveRecord)
		{
		rgComments[nCurrentMove] = strInputPiece;
		}
	}

	return;
}

function rgComments2strComments(rgComments) {

	var strOutput = "";

	for (i = 0; i < rgComments.length; i++) 
		{
		if (rgComments[i])
			{
			if (i != 0)
				{
				strOutput += "|m" + i.toString() + "|";
				}
				
			strOutput += rgComments[i];
			}
		}

	return strOutput;
}

// Hidden input - document.forms.pcomments, global thisName

function loadComments() {

	var strMove;
	var strWhiteComments;
	var strBlackComments;
	var strWhiteComment;
	var strBlackComment;
	var i, len;
	var iCurrentMove;
	var strTableContents;
	var nbsp = "&nbsp";		// nbsp assigned
	var cColumns = 3;

	
	strWhiteComments = document.forms.pcomments.strWhiteComments.value;
	strBlackComments = document.forms.pcomments.strBlackComments.value;
	
	strComments2rgComments(strWhiteComments, rgWhiteComments);
	strComments2rgComments(strBlackComments, rgBlackComments);

	if (strWhiteComments == '')
		{
		cColumns = 2;
		}

	// Start with banner that is as high as the height of the viewing div (100 now)
	// That prevents window from jumping when scrollIntoView aligns current comment with bottom
	// of the screen. Bottom of current comment is always at the bottom of the div now.
	
	strTableContents = '<table id=CommentsTable border="1" width="100%">' +
				'<tr><td colspan=' + cColumns + '>' + 
				'<table width="100%">' +
				'<tr>' + 
					'<td align=left>' + strWhitePlayerName + '</td>' +
				'</tr>' +
				'<tr>' + 
					'<td align=center><b>' + thisName + '</b></td>' +
				'</tr>' +
				'<tr>' + 
					'<td align=right>' + strBlackPlayerName + '</td>' +
				'</tr>' +
				'<tr>' + 
					'<td height=20> </td>' +
				'</tr>' +
				'</table>' +
				'</td></tr>';

	len = Math.max(rgWhiteComments.length, rgBlackComments.length);

	for (i = 0; i < len; i++) 
		{
		if (rgWhiteComments[i] || rgBlackComments[i] )
			{
			if (i == 0)
				{
				strMove = nbsp;
				}
			else
				{
				strMove = i.toString();
				}

			if (rgWhiteComments[i])
				{
				strWhiteComment = rgWhiteComments[i];
				}
			else
				{
				strWhiteComment = nbsp;
				}
			
			if (rgBlackComments[i])
				{
				strBlackComment = rgBlackComments[i];
				}
			else
				{
				strBlackComment = nbsp;
				}
			
			strTableContents = strTableContents + "<tr id=CommentsForMove" + i + ">" + 
				((cColumns == 3) ? '<td> ' + strWhiteComment + ' </td>': '') + 
				"<td class=CommentMoveNumber onclick='GoToMove(this)'> " + strMove + " </td>" + 
				"<td>" + strBlackComment + " </td>" + 
				"</tr>";
			}
		}
	
	document.getElementById("divComments").innerHTML = strTableContents + '</table>';

	// nothing else to do unless one of the players is playing this game.

	if (!document.getElementById("WhiteCommentsOutput"))
		{
		return;
		}

	// copy current comments into output field for submission
	
	obj = document.getElementById("WhiteCommentsOutput");
	obj.value = strWhiteComments;
	
	obj = document.getElementById("BlackCommentsOutput");
	obj.value = strBlackComments;
	
	return;
}

function GoToMove(el) {

	var iMove = parseInt(el.innerHTML);

	if (iMove > 0)
		{
		retraceMove(2*iMove - 1);
		}
}

function showComments(iHalfMove) {

	var i, len, iBefore;
	var fFound = false;
	var elRow;

	iMoveShown = Math.floor((iHalfMove + 1) / 2);


	if (document.getElementById("CurrentMoveNumber"))
		{
		document.getElementById("CurrentMoveNumber").innerHTML = '' + iMoveShown;
		}

	len = Math.max(rgWhiteComments.length, rgBlackComments.length);

	iBefore = 0;

	for (i = 0; i < len; i++) 
		{
		if (rgWhiteComments[i] || rgBlackComments[i] )
			{
			if (i < iMoveShown)
				{
				iBefore = i;
				}
			else if (i == iMoveShown)
				{
				fFound = true;

				if (document.getElementById("CurrentComments"))
					{
					if (playerColor == 'W')
						{
						if (rgWhiteComments[i])
							{
							document.getElementById("CurrentComments").value = rgWhiteComments[i];
							}
						}
					else
						{
						if (rgBlackComments[i])
							{
							document.getElementById("CurrentComments").value = rgBlackComments[i];
							}
						}
					}

				break;
				}
			}
		}

	elRow = null;

	if (fFound)
		{	
		elRow = document.getElementById("CommentsForMove"+i);
		}
	else
		{
		if (document.getElementById("CurrentComments"))
			{
			document.getElementById("CurrentComments").value = '';
			}
		
		elRow = document.getElementById("CommentsForMove"+iBefore);
		}

	if (iCommentHighlighted > 0)
		{
		UnhighlightComment(iCommentHighlighted);
		iCommentHighlighted = 0;
		}

	if (fFound && elRow != null)			// make top or bottom visible
		{			
		elRow.scrollIntoView(iHalfMove == 0 ? false : fScrollIntoView); 

		if (i > 0)
			{
			HighlightComment(i);
			iCommentHighlighted = i;
			}
		}
}

function HighlightComment(iMove) {

	var elRow = document.getElementById("CommentsForMove"+iMove);
	var elCell = elRow.getElementsByTagName('td')[0];
	elCell.className = 'CommentMoveNumber highlighted';
}

function UnhighlightComment(iMove) {

	var elRow = document.getElementById("CommentsForMove"+iMove);
	var elCell = elRow.getElementsByTagName('td')[0];
	elCell.className = 'CommentMoveNumber';
}


function UpdateComment(strNewComment) {

	if (playerColor == 'W')
		{
		rgWhiteComments[iMoveShown] = strNewComment;

		document.forms.pcomments.strWhiteComments.value = rgComments2strComments(rgWhiteComments);
		}
	else
		{
		rgBlackComments[iMoveShown] = strNewComment;

		document.forms.pcomments.strBlackComments.value = rgComments2strComments(rgBlackComments);
		}

	fCommentsUpdated = true;

	loadComments();
}


// parseGameData fills Moves[] array, document.controlPanel.moveHistory and pgnGameText with
//		the pgn notation of the game from oldMoves in Show Item.

function parseGameData() {

	document.getElementById("CurrentInstruction").innerHTML = 'ParsingGameData';

	pgnGameText = '[White "' + strWhitePlayerName + '"][Black "' + strBlackPlayerName + '"]';

	// real board is set to initial position now
	// relying on initGameStuff() and preloadPieces() being called before parseGameData()

	drawStartingBoard();

	if (iRandomChess == '1' || iRandomChess == '2'
			|| (iRandomChess == 'F' && strStartingFen != '')) 
		{ addStartingPosition2PGN(); }

	CopyRealBoardToVirtualBoard();				
	
	BoardMode = 'virtual';

	moveIndex = 0;
	
	if (document.controlPanel.moveHistory.options[0]) {
		document.controlPanel.moveHistory.options[0] = null;
	}

	var strMoves = oldMoves;

	while (strMoves.indexOf(':') > -1) {
		moveIndex++;
		Moves[moveIndex] = strMoves.substring(0,strMoves.indexOf(':'));
		strMoves = strMoves.substring(strMoves.indexOf(':') + 1);

		fWhiteMoves = false;
		
		if ((moveIndex/2) != Math.floor(moveIndex/2))
			{
			fWhiteMoves = true;
			}
			
		mv = Moves[moveIndex];

		if (mv.indexOf('oo') > -1) {		// Castle move
			if (mv.indexOf('g') > -1) {
				mvHistory = 'O-O';
				pgnmv = 'O-O';
			} else {
				mvHistory = 'O-O-O';
				pgnmv = 'O-O-O';
			}
			
			drawMove(mv);
			
		} else if (mv.indexOf('r') > -1) {  // Retires
			mvHistory = 'Resigns';
			pgnmv = (fWhiteMoves) ? '0-1' : '1-0';
			
		} else if (mv.indexOf('t') > -1) {  // Draw
			mvHistory = 'Draw';
			pgnmv = '1/2-1/2';
			
		} else if (mv.indexOf('m') > -1) {  // Checkmate win
			mvHistory = 'Checkmate';
			pgnmv = (fWhiteMoves) ? '0-1' : '1-0';

		} else {							// Normal Move
			pgnmv = convert2pgn(mv, fWhiteMoves);
			
			drawMove(mv);

			nextKingColor = (fWhiteMoves) ? 'B' : 'W';

			if (kingInCheck(nextKingColor))
				{
				pgnmv = pgnmv + '+';
				}
			
			mvHistory = pgnmv;
		}

		if (fWhiteMoves) {
			mi = (moveIndex + 1) / 2;
			if (mi < 10) {mi = ' ' + mi;}
			t = '\u2002' +  + mi + '. ' + mvHistory;
			
			pgnmv = mi + '. ' + pgnmv;
		} else {
			t = '\u2003' + '\u2002' + mvHistory;
		}
			
		t = t + '     ';
		v = Moves[moveIndex];
		
		n = new Option(t,t);
		with (document.controlPanel.moveHistory) {
			options[moveIndex-1] = n;

		pgnGameText = pgnGameText + ' ' + pgnmv;

		lastMove = mv;
		}
	}

	Moves[0] = moveIndex;
	
	document.controlPanel.moveHistory.selectedIndex = moveIndex - 1;

	BoardMode = 'actual';
	
	document.getElementById("CurrentInstruction").innerHTML = '';

	return;
}


function convert2pgn(move, fWhite) {
	
	var from = move.substring(0,move.indexOf('-'));
	var to = move.substring(move.indexOf('-') + 1);
	var fx = ctoi[from.charAt(0)];
	var fy = parseInt(from.charAt(1), 10);
	var tx = ctoi[to.charAt(0)];
	var ty = tyFromTo(to, fy);
	var fromNotationForm = 'None';
	var fEnpassant = false;
	
	var posArray = findOtherPiecesOfSameColor(fx,fy, fWhite);

	var piece2move = extractPieceRank(fx,fy);
	var fPieceTaken;

	if (extractPieceRank(tx,ty) == 'X')
		{
		fPieceTaken = false;
		}
	else
		{
		fPieceTaken = true;
		}
	
	// Disambiguate if necessary
	
	if(posArray.length == 0 && piece2move != 'P')
		{
		// there is only one piece of that color - no need for the "from" square coordinates.
		// Have to visit pawn block always because of en passant
		
		// do nothing fromNotationForm = 'None'; 
		}
	else if (piece2move == 'R') 
		{
		for (i = 0; i < posArray.length; i++) 
			{
			strMove = posArray[i];

			fx2 = parseInt(strMove.charAt(1), 10);
			fy2 = parseInt(strMove.charAt(2), 10);

			if (legalRookMove(fx2,fy2,tx,ty) == 'OK')
				{
				fromNotationForm = UpdateFromNotation(fx,fy,fx2,fy2,fromNotationForm);
				}
			}
		}
	else if (piece2move == 'B') 
		{
		for (i = 0; i < posArray.length; i++) 
			{
			strMove = posArray[i];

			fx2 = parseInt(strMove.charAt(1), 10);
			fy2 = parseInt(strMove.charAt(2), 10);

			if (legalBishopMove(fx2,fy2,tx,ty) == 'OK')
				{
				fromNotationForm = UpdateFromNotation(fx,fy,fx2,fy2,fromNotationForm);
				}
			}
		}
	else if (piece2move == 'N') 
		{
		for (i = 0; i < posArray.length; i++) 
			{
			strMove = posArray[i];

			fx2 = parseInt(strMove.charAt(1), 10);
			fy2 = parseInt(strMove.charAt(2), 10);

			if (legalKnightMove(fx2,fy2,tx,ty) == 'OK')
				{
				fromNotationForm = UpdateFromNotation(fx,fy,fx2,fy2,fromNotationForm);
				}
			}
		}
	else if (piece2move == 'Q') 
		{
		for (i = 0; i < posArray.length; i++) 
			{
			strMove = posArray[i];

			fx2 = parseInt(strMove.charAt(1), 10);
			fy2 = parseInt(strMove.charAt(2), 10);

			if (legalBishopMove(fx2,fy2,tx,ty) == 'OK' || 
					legalRookMove(fx2,fy2,tx,ty) == 'OK')
				{
				fromNotationForm = UpdateFromNotation(fx,fy,fx2,fy2,fromNotationForm);
				}
			}
		}
	else if (piece2move == 'P') 
		{
		for (i = 0; i < posArray.length; i++) 
			{
			strMove = posArray[i];

			fx2 = parseInt(strMove.charAt(1), 10);
			fy2 = parseInt(strMove.charAt(2), 10);

			// legalPawnMove (or rather enpassant called inside it) has an unpleasant side effect
			// of "making part of the move" - deleting the pawn taken en passant.
			// Until this is changed undoing here is necessary
			
			NumberOfChanges = 0;			// record the move
			
			if (legalPawnMove(fx2,fy2,tx,ty) == 'OK')
				{
				fromNotationForm = UpdateFromNotation(fx,fy,fx2,fy2,fromNotationForm);
				}

			UndoTheMove();
			}

		fEnpassant = enpassant(fx,fy,tx,ty,lastMove)

		if (fEnpassant)
			{
			fPieceTaken = true;
			}
		}

	// (else it must be king and there is no way we have more than one!)

	if (fPieceTaken)
		{
		take_sign = 'x';
			
		if (piece2move == 'P' && fromNotationForm == 'None')
		 	{
		 	fromNotationForm = 'Rank Or File'
		 	}
		}
	else
		{
		take_sign = '';
		}

	if (fromNotationForm == 'None')
		{
		fromNotation = '';
		}
	else if (fromNotationForm == 'Rank Only')
		{
		fromNotation = from.charAt(1);
		}
	else if (fromNotationForm == 'Rank and File')
		{
		fromNotation = from;
		}
	else 
		{
		// File Only or Rank Or File
		fromNotation = from.charAt(0);
		}

	if (piece2move == 'P')
		{
		piece2move = '';

		var charLast = to.charAt(1);
		if ( charLast.match(/[QRNB]/)) 
			{ 
			to = to.charAt(0) + ty + '=' + charLast; 
			}
		}

	return piece2move + fromNotation + take_sign + to;
}

function getpgndata() {	
	if (window.clipboardData)
		{
		// Firefox cannot do that, and hates when you try.
		
		window.clipboardData.setData("Text", pgnGameText);
		}

	return(pgnGameText);
}

// Return data for a MFO Chess Diagram (Fixit)

function getdiagramdata(cHalfMoves) {
	var bp = new Array();

	for (y = 1; y < 9; y++) {
		for (x = 8; x > 0; x--) {
			i = 'p' + y + x;
			bp[i] = document.images[i].src;
		}
	}
	
	var boarddata = '';
	
	for (y = 1; y < 9; y++) {
		if (y > 1) boarddata += '/';
		
		for (x = 8; x > 0; x--) {
			py = 9 - y;
			px = x;

			i = 'p' + perspective(py) + perspective(px);
			pieceColor = extractPieceColorActual(bp[i]);
			pieceRank = extractPieceRankActual(bp[i]);
			
			if (pieceRank != 'X' && pieceColor == 'B') pieceRank = pieceRank.toLowerCase();
		
			boarddata += pieceRank;
		}
	}
	
	bp = null;
	
	boarddata = boarddata.replace(/XXXXXXXX/g,'8');
	boarddata = boarddata.replace(/XXXXXXX/g,'7');
	boarddata = boarddata.replace(/XXXXXX/g,'6');
	boarddata = boarddata.replace(/XXXXX/g,'5');
	boarddata = boarddata.replace(/XXXX/g,'4');
	boarddata = boarddata.replace(/XXX/g,'3');
	boarddata = boarddata.replace(/XX/g,'2');
	boarddata = boarddata.replace(/X/g,'1');

	// add move indicator
	
	if (cHalfMoves % 2 == 0)
		{
		boarddata += ' b';
		}
	else
		{
		boarddata += ' w';
		}

	// add FEN for still existing castling possibilites

	boarddata += ' ' + fenCastle();

	// add FEN for en passant

	boarddata += ' ' + fenEnpassant();
	
	return(boarddata);
}

function fenCastle() {

	var match; 
	var re = /R(.)([18])/;		
	var rgCastle = strPossibleCastles.split( / /g ) ;
	var strOut = '';
	var fileRook;

	for ( var i = 0 ; i < rgCastle.length ; i++ )
		{
		match = re.exec(rgCastle[i]);

		if (match) 
			{
			fileRook = match[1];

			if (match[2] == '1')
				{
				// Up the case for white

				fileRook = fileRook.toUpperCase(); 
				}

			strOut += fileRook;
			}
		}

	return strOut;
}

function fenEnpassant() {

	var re = /([abcdefgh])([27])-[abcdefgh]([45])/;	
	var match = re.exec(Moves[curMove+1]);
		
	if (!match) 
		{
		return '-';
		}
	
	return match[1] + ((parseInt(match[2], 10) + parseInt(match[3], 10)) / 2) ;
}


//
// fromNotation describes the needed level of disambiguation
// 		Possible values: None, Rank Or File, Rank Only, File Only, Rank and File

function UpdateFromNotation(fx,fy,fx2,fy2,fromNotationForm)
{
	if (fromNotationForm == 'None')
		{
		fromNotationForm = 'Rank Or File';
		}
	
	if (fx == fx2)
		{
		if (fromNotationForm == 'Rank Or File' || fromNotationForm == 'Rank Only')
			{
			return 'Rank Only';
			}
		else
			{
			return 'Rank and File';
			}
		}
	
	if (fy == fy2)
		{
		if (fromNotationForm == 'Rank Or File' || fromNotationForm == 'File Only')
			{
			return 'File Only';
			}
		else
			{
			return 'Rank and File';
			}
		}
	
	return fromNotationForm;
}

function findOtherPiecesOfSameColor(fx,fy, fWhite)
{
	var matches = new Array();
	var piece_rank = extractPieceRank(fx,fy);
	var piece_color = (fWhite) ? 'W' : 'B';
	var count = 0;
	
	// Sweep board looking for pieces 
	
	for(x=1; x<9; ++x)
		{	
		for(y=1; y<9; ++y)
			{	
			if((extractPieceColor(x,y) == piece_color) &&
					(extractPieceRank(x,y) == piece_rank) &&
					(x != fx || y != fy))
				{
				// another piece found
				matches[count++] = 'p' + x + y;
				}
			}
		}
	
	return matches;
}



function preloadPieces() {

	document.getElementById("CurrentInstruction").innerHTML = 'LoadingPieces';

	var allPieces = new Array('_X_X','_W_K','_W_Q','_W_R','_W_B','_W_N','_W_P','_B_K','_B_Q','_B_R','_B_B','_B_N','_B_P');
	
	for (x = 0; x < allPieces.length; x++) {
	
		fpn = pieceSet + 'W' + allPieces[x];
		piece[fpn] = new Image();
		piece[fpn].src = basePath + fpn + '.gif';
	
		fpn = pieceSet + 'B' + allPieces[x];
		piece[fpn] = new Image();
		piece[fpn].src = basePath + fpn + '.gif';

	}
	
	document.getElementById("CurrentInstruction").innerHTML = '';
	
	return;
}


///////////////////////////////////
/*	
	-------------------------
	buti_oxa Checkmate checking ROUTINES:
	
		IsCheckmated()
		MovingPieceCanSaveTheKing
		UndoTheMove
		CopyRealBoardToVirtualBoard
	-------------------------
*/


function IsCheckmated(playerColor) {

	if (kingInCheck(playerColor) == false) {
		return false;
	} 

	CopyRealBoardToVirtualBoard();
	
	BoardMode = 'virtual';

	for (x0 = 1; x0 < 9; x0++) {
		for (y0 = 1; y0 < 9; y0++) {
			if (extractPieceColor(x0,y0) == playerColor) {
				if (MovingPieceCanSaveTheKing(x0,y0,playerColor) == true) {
					BoardMode = 'actual';
					return false;
				} 
			} 
		}
	}
	
	BoardMode = 'actual';
	
	return true;
}

function MovingPieceCanSaveTheKing(x0, y0, playerColor) {

	fKingSaved = false;

	move_start = '' + itoc[x0] + y0 + '-';

	for (x1 = 1; x1 < 9; x1++) {
		for (y1 = 1; y1 < 9; y1++) {
			move = move_start + '' + itoc[x1] + y1;

			if (checkMove(move).substr(0,5) != 'Error') {

				// record the move
				
				NumberOfChanges = 0;

				drawMove(move);

				if (kingInCheck(playerColor) == false) {
					fKingSaved = true;
				}

				UndoTheMove();

				if (fKingSaved == true) {
					return fKingSaved;
					}

				CopyRealBoardToVirtualBoard();
				} 
			} 
		}
	
	return fKingSaved;
}


function UndoTheMove() {

	for (n = 0; n < NumberOfChanges; n++) {
		str = ChangeSaved[n];

		OldColor = str.charAt(0);
		OldRank = str.charAt(1);
		p = str.substring(2);

		VirtualBoardColor[p] = OldColor;
		VirtualBoardRank[p] = OldRank;
	}
	return;
}
function CopyRealBoardToVirtualBoard() {

	for (x = 1; x < 9; x++) {
		for (y = 1; y < 9; y++) {
			VirtualBoardColor['p' + y + x] = extractPieceColor(x,y);
			VirtualBoardRank['p' + y + x] = extractPieceRank(x,y);
		}
	}

	return;
}

function HighlightOff() {
	objHighlighter = document.images["selector"];
	objHighlighter.style.visibility = "hidden";
}

function Highlight(x, y) {

var elementReference = document.images[imageLocation(x,y)];
var nMyElementsTrueXPosition = DL_GetElementLeft(elementReference);
var nMyElementsTrueYPosition = DL_GetElementTop(elementReference);

	objHighlighter = document.images["selector"];
	objHighlighter.style.visibility = "visible";
	
	objHighlighter.style.left = nMyElementsTrueXPosition + "px";
	objHighlighter.style.top = nMyElementsTrueYPosition + "px";
}

function showPlayer(strPlayerNameIn)
{

/* commented out for now

	var strPlayerId, strPlayerName;

	// strPlayerNameIn can be decorated
	
	if (strPlayerNameIn == white_name || strPlayerNameIn.substring(1) == white_name)
		{
		strPlayerId = white_id;
		strPlayerName = white_name;
		}
	else
		{
		strPlayerId = black_id;
		strPlayerName = black_name;
		}

	if (event.ctrlKey)
		{
		window.location='showUser.asp?Userid=' + strPlayerId;
		}
	else
		{
		if (fPostedGame)
			{
			window.location='List.asp?ListId=3238&filter_strvalue3=%5B %5B %5D' + strPlayerName + '%5D';
			}
		else
			{
			window.location='List.asp?ListId=1728&filter_strvalue3=%5B %5B %5D' + strPlayerId + 
				'%5D&p1=all&p2=' + strPlayerId + '&p3=' + strPlayerName;
			}
		}

*/	
    return;               
}

function DL_GetElementLeft(eElement)
{
    var nLeftPos = eElement.offsetLeft;          // initialize var to store calculations
    var eParElement = eElement.offsetParent;     // identify first offset parent element  
    while (eParElement != null)
    {                                            // move up through element hierarchy
        nLeftPos += eParElement.offsetLeft;      // appending left offset of each parent
        eParElement = eParElement.offsetParent;  // until no more offset parents exist
    }
    return nLeftPos;                             // return the number calculated
}

function DL_GetElementTop(eElement)
{
    var nTopPos = eElement.offsetTop;            // initialize var to store calculations
    var eParElement = eElement.offsetParent;     // identify first offset parent element  
    while (eParElement != null)
    {                                            // move up through element hierarchy
        nTopPos += eParElement.offsetTop;        // appending top offset of each parent
        eParElement = eParElement.offsetParent;  // until no more offset parents exist
    }
    return nTopPos;                              // return the number calculated
}

function clickImage()
{
	touchPiece(this.name.substr(1,2));
}


///////////////////////////////////
/*	
	-------------------------
	INITIALIZATION ROUTINES:
		init()
		initBoard()
		parseGameData()
		preloadPieces()
		initGameStuff()
		initStateVariables()

	-------------------------
*/

function initGameStuff() {

	// Initialize Conversion Constants
	ctoi['a'] = 1;
	ctoi['b'] = 2;
	ctoi['c'] = 3;
	ctoi['d'] = 4;
	ctoi['e'] = 5;
	ctoi['f'] = 6;
	ctoi['g'] = 7;
	ctoi['h'] = 8;
	ctoi['o'] = 'o';
	ctoi['r'] = 'r';
	
	itoc[1] = 'a';
	itoc[2] = 'b';
	itoc[3] = 'c';
	itoc[4] = 'd';
	itoc[5] = 'e';
	itoc[6] = 'f';
	itoc[7] = 'g';
	itoc[8] = 'h';
	
	fullname['K'] = 'King';
	fullname['Q'] = 'Queen';
	fullname['R'] = 'Rook';
	fullname['B'] = 'Bishop';
	fullname['N'] = 'Knight';
	fullname['P'] = 'Pawn';
	
	fullcolor['W'] = 'White';
	fullcolor['B'] = 'Black';

	//buti_oxa REVIEW I have to init VirtualBoard array, right? Check if I can skip this.
	
	for (x = 1; x < 9; x++) {
		for (y = 1; y < 9; y++) {
			VirtualBoardColor['p' + y + x] = 'X';
			VirtualBoardRank['p' + y + x] = 'X';
		}
	}

	return;
}

function initTable()
{
	var nav = document.getElementById('theBoard');
	var imgs = nav.getElementsByTagName('img');
	var index;

	for (index=0; index<imgs.length; index++)
	{
	imgs[index].onclick = clickImage;
	}
}

function initCapturedPieces()
{
	document.getElementById('topcapturedpieces').innerHTML = htmlCaptured('top')
	document.getElementById('botcapturedpieces').innerHTML = htmlCaptured('bot')
}

function htmlCaptured(top_or_bot)
{
	var x;
	var strHTML = "";

	for (x=1; x<16; x++)
	{
	strHTML += '<img src="b.gif" height=15 width=15 alt="" id="' + top_or_bot + 'captured' + x + '"> ';
	}

	return strHTML;
}

function setGameResult()
{
var spanGameResult = document.getElementById("GameResult");

if (gamestate == 300)  { spanGameResult.innerHTML = "White WON"; }
if (gamestate == 301)  { spanGameResult.innerHTML = "Black WON"; }
if (gamestate == 302)  { spanGameResult.innerHTML = "Game was a DRAW"; }
}

function mfochess_init(rootURL) {

	if (javascriptMfoChessVersion != templateMfoChessVersion)
		{
		alert('You may need to refresh your javascript (Ctrl-F5)');
		}

	if (iRandomChess == 'F' && 
		(typeof (strStartingFen) != 'string' || strStartingFen == ''))
		{
		iRandomChess = '0';					// chess0
		}

	rootPath = rootURL;
	basePath = rootURL + 'chess/';
	capturepiecepath = rootURL + 'captured/chesspc_';

	playerColor = 'W';
	viewpoint = 'white';

	// flip viewpoint if I am playing black OR
	//					I am challenged to play black OR random
	//					I challenged someone to play white

	if ((gamestate != 299 && my_id == black_id) ||
		(gamestate == 299 && my_id == black_id && challengecolor != 3) ||
		(gamestate == 299 && white_id == my_id && challengecolor == 3))
		{ 
		playerColor = 'B'; 
		viewpoint = 'black';
		}

	// posted games comments should be black

	if (fPostedGame)
		{ 
		playerColor = 'B'; 
		}

	if (document.getElementById("divComments").getAttribute('scrollshow') == 'top')
		{
		fScrollIntoView = true;
		}

	iCommentHighlighted = 0;
	initTable();
	initCapturedPieces();
	initGameStuff();
	preloadPieces();
	setPlayerNames();
	setGameResult();
	parseGameData();
	alignIndices();
	loadComments();
	document.onkeydown = KeyDown;
	
	retraceMove((fIAmPlaying) ? 'all' : 0 );
		
	if (fMyMove) {
		if (kingInCheck(playerColor) == true)
			{
			if (IsCheckmated(playerColor))
				{
				alert('You are checkmated!');
				}
			else
				{
				alert('You are in check!');
				}
			}
		
		if (!document.getElementById("btnAcceptDraw").disabled)
			{
			alert('You are offered a draw.');
			}
	}
}

// Used by show_game_link.php

function linkGame(e, img, idGame, cHalfMoves)
{
var sParams = img.src.split("?")[1];			// f=FEN&m=SIDE2MOVE

if (e.ctrlKey)
	{
	popup_window("/cd/mcdwa.html?" + sParams + "&n=" + cHalfMoves,610,660);
	}
else
	{
	popup_window('/cd/show_chess_game.php?g=' + idGame,800,740);
	}
}

function setupGameLinkImages() {

	var el;
	var rgEl = document.getElementsByTagName("img");
	var x;

	for (x=0; x<rgEl.length; x++) {
		el = rgEl[x];
		
		if (el.className == 'linkChessGame') {

			el.style.cursor = "pointer";
			el.title = "Click to see game, Ctrl-Click to analyze position";
			}
	}

	rgEl = document.getElementsByTagName("span");

	for (x=0; x<rgEl.length; x++) {
		el = rgEl[x];
		
		if (el.className == 'linkPlayerInfo') {

			el.style.cursor = "pointer";
			el.title = "Click to see games, Ctrl-Click to see profile";
			}
	}
}

function KeyDown(e)
{
 if (!e) var e = window.event;

 var key = e.keyCode;
 var strKey = String.fromCharCode(key).toLowerCase();

 if(key==37||key==100)	// Left Arrow
   {prevMove();return false;}
 if(key==39||key==102)	// Right Arrow
   {nextMove();return false;}
 if(key==103)			// Num Pad 7
   retraceMove(0);
 if(key==97)			// Num Pad 1
   retraceMove('all');
 if(key==111)			// Num Pad Divide
   FlipBoard();

 if (e.ctrlKey && strKey == "c") 
	{
	setdiagramdata(curMove);
		
	if (window.clipboardData)
		{
		// Firefox cannot do that and hates when we try
		
		window.clipboardData.setData("Text", document.forms.diagram.diagramdata.value);
		}
	}
 
 if (e.ctrlKey && strKey == "a") 	// analyzeGame is defined in Show Item
	{
	analyzeGame(); 
	return false;						// cancel standard behaviour
	}

 if (e.ctrlKey && strKey == "g") 	// setpgndata is defined in Show Item
	{
	setpgndata();
	}

 if (e.ctrlKey && strKey == "m" && document.getElementById("btnMessage"))
	{
	messageOpponent();
	}
 
 // Escape closes window if we are in a pop-up
 if (window.opener && key==27) { window.close(); }

 return true;
}

function setdiagramdata() {
	document.forms.diagram.diagramdata.value = getdiagramdata(curMove);
}

function setpgndata() {
	document.forms.diagram.diagramdata.value = getpgndata();
}

function analyzeGame() {
	var imove = curMove + 1;
	var rgFEN = getdiagramdata(curMove).split(' ');
	var sParams = "f=" + rgFEN[0] + '&m=' + rgFEN[1].toUpperCase() + '&n=' + imove;
	var sUrl = rootPath + "mcdwa.html?" + sParams;

	popup_window(sUrl,610,660);
}

function messageOpponent() {
	var opp_id = (my_id == white_id) ? black_id : white_id;	

	window.open('/privmsg.php?mode=post&u=' + opp_id, 'PM');	
}

function showPlayerInfo(e, span, id) {
	
	if (e.ctrlKey)
		{
		window.open('/profile.php?mode=viewprofile&u=' + id, 'ViewGames');
		}
	else
		{
		window.open('/cd/list_chess_games.php?username=' + span.innerHTML, 'ViewGames');
		}
}

function popup_window(url,width,height) { 
   window.open(url, "_blank", "width=" + width + ",height=" + height + ",scrollbars=yes,resizable=yes");   
}
