/**
 * Copyright 2006 Toomas Römer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
**/
	
	
/*
	Convert PGN format to an easier format. The problem
	with PGN is that it is really difficult and ugly to
	accomplish backward moves. 
	
	Let's say we have a move "e4" and we need to go one 
	move back. The only info is that we have placed a pawn
	to e4. We also have to remember from where did we place
	the pawn. To make it easier and to have less calculations
	the PGN is converted into a format where the from square
	with contents is explicit and to square also. There are
	other problems also regarding backward moving and remembering
	which piece was taken.
*/


function Converter(pgn) {
	this.pgn = pgn
	this.vBoard = new Array(8)
	this.initialBoard = new Array(8)
	this.moves = new Array()
	this.iteIndex = 0
	this.flippedI = false
	this.flippedV = false

	this.wKingX, this.wKingY, this.bKingX, this.bKingY
	
	/* Virtual board initialization */
	for(var i = 0; i < 8; i++) {
		this.vBoard[i] = new Array(8)
		for (var j = 0; j < 8; j++) {
			this.vBoard[i][j] = new vSquare()
		}
	}
	
	// pawns
	for (var i = 0;i < 8; i++) {
		this.vBoard[6][i].piece = 'pawn';
		this.vBoard[6][i].color = 'white';
            
		this.vBoard[1][i].piece = 'pawn';
		this.vBoard[1][i].color = 'black';
	}

	// rooks, bishops, knights
	for(var i = 0; i < 2; i++) {
		this.vBoard[7][i*7].piece = 'rook'
		this.vBoard[7][i*7].color = 'white'
          
		this.vBoard[0][i*7].piece = 'rook'
		this.vBoard[0][i*7].color = 'black'
  
		this.vBoard[7][i*5+1].piece = 'knight'
		this.vBoard[7][i*5+1].color = 'white'    
          
		this.vBoard[0][i*5+1].piece = 'knight'
		this.vBoard[0][i*5+1].color = 'black'
  
		this.vBoard[7][i*3+2].piece = 'bishop'
		this.vBoard[7][i*3+2].color = 'white'

		this.vBoard[0][i*3+2].piece = 'bishop'
		this.vBoard[0][i*3+2].color = 'black'
	}
         
	this.vBoard[7][3].piece = 'queen'
	this.vBoard[7][3].color = 'white'
	
	this.vBoard[7][4].piece = 'king'
	this.vBoard[7][4].color = 'white'
	this.wKingX = 7, this.wKingY = 4

	this.vBoard[0][3].piece = 'queen'
	this.vBoard[0][3].color = 'black'

	this.vBoard[0][4].piece = 'king'
	this.vBoard[0][4].color = 'black'
	this.bKingX = 0, this.bKingY = 4

	// let's clone the initial pos
	for (var i = 0;i < 8;i++){
		this.initialBoard[i] = new Array(8)
		for (var j = 0;j < 8;j++) {
			this.initialBoard[i][j] = this.vBoard[i][j].clone()
		}	 
	}
	/* EO Virtual board initialization */
	
	this.convert = function() {
		var move = null;
		do {
			 move = this.convertMove()
			 if (move)
			 	this.moves[this.moves.length] = move
		}
		while(move);
	}
	
	/*
		Result iterator
	*/

	this.getCurMove = function() {
		if (this.moves.length>this.iteIndex)
			return this.moves[this.iteIndex]
		return null
	}

	this.getCurMoveNo = function() {
		 return this.iteIndex
	}
	
	this.nextMove = function() {
		if (this.moves.length>this.iteIndex)
			return this.moves[this.iteIndex++]
		return null
	}

	this.prevMove = function() {
		if (this.iteIndex>0)
			return this.moves[--this.iteIndex]
		return null
	}
	
	this.resetToEnd = function() {
		 this.iteIndex = this.moves.length
	}

	this.resetToStart = function() {
		this.iteIndex = 0
	}

	/*
		EOF Result Iterator
	*/

	this.getStartPos = function(flipped) {
		if (flipped!=this.flippedI) {
			 this.flipBoard(this.initialBoard)
			 this.flippedI = !this.flippedI
		}
		return this.initialBoard;
	}

	this.getEndPos = function(flipped) {
		if (flipped!=this.flippedV) {
			this.flipBoard(this.vBoard)
			this.flippedV = !this.flippedV
		}
		return this.vBoard;	 
	}

	this.flipBoard = function(board) {
		this.flipped = !this.flipped
		for (var i = 0;i<8;i++) {
			for (var j = 0;j<4;j++) {
				tmp = board[i][j]
				board[i][j] = board[7-i][7-j]
				board[7-i][7-j] = tmp
			}
		}
	}
	
	/*
		Convert a move.
	*/
	this.convertMove = function(board) {
		var to = this.pgn.nextMove()
		var oldTo = to
		if (to == null)
			return;
		var color = to[1]
		to = to[0]
		
		/*
			Check which piece has to move.
			Find the location of the piece.
		*/
		var pawnre = /^[a-z]+[1-8]/
		var knightre = /^N[0-9]?[a-z]+[1-8]/
		var bishre = /^B[a-z]+[1-8]/
		var queenre = /^Q[0-9]?[a-z]+[1-8]/
		var rookre = /^R[0-9]?[a-z]+[1-8]/
		var lCastlere = /^(0|O)-(0|O)-(0|O)/i
		var sCastlere = /^(0|O)-(0|O)/i
		var kingre = /^K[a-z]+[1-8]/
		var prom = ""
		
		var toCoords = getSquare(to)
		var fromCoords, from, to, result, tmp, myMove = null, pawnM = false
		if (pawnre.test(to)) {
			// let see if it is a promotional move
			if (/^[a-z]+[1-8]=[A-Z]/.test(to))
				prom = to.charAt(to.indexOf('=')+1)
			fromCoords = findFromPawn(this.vBoard, to, toCoords, color)
			pawnM = true
		}
		else if (knightre.test(to)) {
			fromCoords = findFromKnight(this, to, toCoords, color)
		}
		else if (bishre.test(to)) {
			fromCoords = findFromBish(this.vBoard, to, toCoords, color)
		}
		else if (queenre.test(to)) {
			fromCoords = findFromQueen(this.vBoard, to, toCoords, color) 
		}
		else if (rookre.test(to)) {
			fromCoords = findFromRook(this, to, toCoords, color)
		}
		else if (kingre.test(to)) {
			fromCoords = findFromKing(this.vBoard, to, toCoords, color)   
		}
		else if (sCastlere.test(to)) {
			var bCoords = new Array('e8','g8','h8','f8')
			var wCoords = new Array('e1','g1','h1','f1')
			
			if (lCastlere.test(to)) {
					bCoords = new Array('e8', 'c8', 'a8', 'd8')
					wCoords = new Array('e1', 'c1', 'a1', 'd1')
			}
			var coords = color=='white'?wCoords:bCoords
			
			fromCoords = getSquare(coords[0])
			toCoords = getSquare(coords[1])
			
			from = this.vBoard[fromCoords[0]][fromCoords[1]]
			to = this.vBoard[toCoords[0]][toCoords[1]]
			// update king location
			if ('king' == from.piece && 'white' == from.color)
				 this.wKingX = toCoords[0], this.wKingY = toCoords[1]
			else if ('king' == from.piece && 'black' == from.color)
				 this.bKingX = toCoords[0], this.bKingY = toCoords[1]
			
			result = movePiece(from, to, prom)
				
			myMove = new MyMove()
			myMove.moveStr = oldTo[0]
			myMove.oPiece = result[2].piece
			myMove.oColor = result[2].color
			myMove.pPiece = result[3]

			myMove.add(new MySquare(fromCoords[0], fromCoords[1]
												,result[0].piece, result[0].color))
			
			myMove.add(new MySquare(toCoords[0], toCoords[1]
												,result[1].piece, result[1].color))

			fromCoords = getSquare(coords[2])
			toCoords = getSquare(coords[3])
		}
		else {
			throw("Can't figure out which piece to move '"+oldTo+"'")   
		}
		from = this.vBoard[fromCoords[0]][fromCoords[1]]
		to = this.vBoard[toCoords[0]][toCoords[1]]
			
		// update king location
		if ('king' == from.piece && 'white' == from.color)
			this.wKingX = toCoords[0], this.wKingY = toCoords[1]
		else if ('king' == from.piece && 'black' == from.color)
			this.bKingX = toCoords[0], this.bKingY = toCoords[1]
			
		// in case of castling we don't have a null value
		if (!myMove)
			 myMove = new MyMove()
	 	
	 	var enPassante = null
		if (pawnM)
			enPassante = getEnPassante(this, fromCoords[0], fromCoords[1],
														 toCoords[0], toCoords[1])
		
		if (enPassante) {
			var sq = this.vBoard[enPassante[0]][enPassante[1]]
			var enP = new MySquare(enPassante[0], enPassante[1]
													,sq.piece, sq.color)
			myMove.enP = enP
			this.vBoard[enPassante[0]][enPassante[1]].color = null
			this.vBoard[enPassante[0]][enPassante[1]].piece = null
		}
			
		result = movePiece(from, to ,prom)
		
		myMove.oPiece = result[2].piece
		myMove.oColor = result[2].color
		myMove.pPiece = result[3]
		myMove.moveStr = oldTo[0]

		myMove.add(new MySquare(fromCoords[0], fromCoords[1]
												,result[0].piece, result[0].color))
		
		myMove.add(new MySquare(toCoords[0], toCoords[1]
												,result[1].piece, result[1].color))

		return myMove
	}
		
	 
	/* FINDING FROM LOCATION FUNCTIONS
		When a SAN (Standard Algebraic Notation) move is given
		we need to figure out from where the move is made. Lets
		say the SAN is "e4" - pawn moves to e4. The from location
		can be e2, e3 or e5. This depends on the color of the player
		and on where the pawn was located. All pieces have different
		logic on finding which piece exactly has to move to the location.
	*/
        
	/*
		Find the pawn from location.
	*/
	findFromPawn = function(pos, to, tmp, color) {
		var x = tmp[1], y = tmp[0]
       
		// taking move or with xtra information
		if (tmp[2][0] != -1 || tmp[3] != -1) {
			var froms = new Array(
				new Array(tmp[0]+1,tmp[1]-1),
				new Array(tmp[0]+1,tmp[1]+1),
				new Array(tmp[0]-1,tmp[1]-1),
				new Array(tmp[0]-1,tmp[1]+1)
			)

			for(var i = 0;i<froms.length;i++) {
				try {
					if (pos[froms[i][0]][froms[i][1]].piece == 'pawn'
							&& pos[froms[i][0]][froms[i][1]].color == color) {
							// we have the file information too
							if (tmp[3] != -1 && tmp[3] == froms[i][1]) {
								// no back taking
								if (y < froms[i][0] && color == "black")
									 continue;
								if (y > froms[i][0] && color == "white")
									 continue;
								return new Array(froms[i][0], froms[i][1])
							}
							//else
							//	return new Array(froms[i][0], froms[i][1])
					}
				}
				catch (e) {}
			}
		}
		else {
			// non-taking move
			try {
				var j
				for(var i = 0; i < 8; i++) {
					j = (color == 'white')?7-i:i
					if (pos[j][x].piece == 'pawn' 
							&& pos[j][x].color == color) {
						if (Math.abs(j-y)>2) {
							 continue;
						}
						// we might be looking at the wrong pawn
						// there can be one between src and dst
						if (2 == Math.abs(j-y)) {
							var j2 = (color == 'white')?(j-1):j+1
							if (pos[j2][x].piece == 'pawn'
								 && pos[j2][x].color == color) {
								 return new Array(j2, x)
							}
						}
						return new Array(j, x);
					}
				}
			}
			catch (e) {}
		}
		throw("Could not find a move with a pawn '"+toSAN+"'")
	}

	/*
		Find the bishop from location.
	*/
	function findFromBish(pos, toSAN, toCoords, color) {
		var to = toCoords
		var rtrn
		var coord
		for(var i = 0;i < 8; i++) {
			// diagonal down right
			try {
				coord = pos[to[0]+i][to[1]+i]
				if (coord.piece == 'bishop' && coord.color == color) {
					return new Array(to[0]+i, to[1]+i)
				}
			}
			catch (e) {}

			try {
				coord = pos[to[0]-i][to[1]-i]
				if (coord.piece == 'bishop' && coord.color == color) {
					return new Array(to[0]-i, to[1]-i)
				}
			}
			catch (e) {}
               
			try {
				coord = pos[to[0]+i][to[1]-i]
				if (coord.piece == 'bishop' && coord.color == color) {
					return new Array(to[0]+i, to[1]-i)
				}
			}
			catch (e) {}

			try {
				coord = pos[to[0]-i][to[1]+i]
				if (coord.piece == 'bishop' && coord.color == color) {
					return new Array(to[0]-i, to[1]+i)
				} 
			}
			catch (e) {}
		}
		throw('No move found for the bishop '+toSAN)
}

	/* 
		Find the king from location.
	*/
	function findFromKing(pos, toSAN, toCoords, color) {
		var to = toCoords
		var froms = new Array(
									new Array(to[0], to[1]+1),
									new Array(to[0], to[1]-1),
									new Array(to[0]+1, to[1]),
									new Array(to[0]-1, to[1]),

									new Array(to[0]+1, to[1]+1),
									new Array(to[0]+1, to[1]-1),
									new Array(to[0]-1, to[1]+1),
									new Array(to[0]-1, to[1]-1) 
								)

		var tmp
		for(var i=0;i<froms.length;i++) {
			try {
				tmp = pos[froms[i][0]][froms[i][1]]
				if (tmp.piece == 'king' && tmp.color == color)
					return froms[i]
			}
			catch (e) {}
		}
		throw('No king move found')
}

	/* 
		Find the queen's from location.
	*/
	function findFromQueen(pos, toSAN, to, color) {
		var op = getOppColor(color)
		var extra = to[2]
		var rtrns = new Array()
					
		var tmp
		try {
			for (var i = 1;i<8;i++) {
				 tmp = pos[to[0]+i][to[1]]
				 if (tmp && "queen" == tmp.piece && tmp.color == color) {
						rtrns[rtrns.length] = new Array(to[0]+i, to[1])
						break
				 }
				 else if (tmp.piece)
						break
			}
		}
		catch (e) {}
		
		try {
			for (var i = 1;i<8;i++) {
				 tmp = pos[to[0]][to[1]+i]
				 if (tmp && "queen" == tmp.piece && tmp.color == color) {
						rtrns[rtrns.length] = new Array(to[0], to[1]+i)
						break
				 }
				 else if (tmp.piece)
						break
			}
		}
		catch (e) {}

		try {
			for (var i = 1;i<8;i++) {
				 tmp = pos[to[0]-i][to[1]]
				 if (tmp && "queen" == tmp.piece && tmp.color == color) {
						rtrns[rtrns.length] = new Array(to[0]-i, to[1])
						break
				 }
				 else if (tmp.piece)
						break
			}
		}
		catch (e) {}
					
		try {
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]][to[1]-i]
				if (tmp && "queen" == tmp.piece && tmp.color == color) {
						rtrns[rtrns.length] = new Array(to[0], to[1]-i)
						break
				}
				else if (tmp.piece)
					break
			}
		}
		catch (e) {}
					
		try {
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]-i][to[1]-i]
				if (tmp && "queen" == tmp.piece && tmp.color == color) {
					rtrns[rtrns.length] = new Array(to[0]-i, to[1]-i)
					break
				}
				else if (tmp.piece)
					break
			}
		}
		catch (e) {}
			 
		try {
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]+i][to[1]+i]
				if (tmp && "queen" == tmp.piece && tmp.color == color) {
					rtrns[rtrns.length] = new Array(to[0]+i, to[1]+i)
					break
				}
				else if (tmp.piece)
					break
			}
		}
		catch (e) {}
					
		try {
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]-i][to[1]+i]
				if (tmp && "queen" == tmp.piece && tmp.color == color) {
					rtrns[rtrns.length] = new Array(to[0]-i, to[1]+i)
					break
				}
				else if (tmp.piece)
					break
			}
		}
		catch (e) {}
					
		try {
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]+i][to[1]-i]
				if (tmp && "queen" == tmp.piece && tmp.color == color) {
					rtrns[rtrns.length] = new Array(to[0]+i, to[1]-i)
					break
				}
				else if (tmp.piece)
					break
			}
		}
		catch (e) {}
		// only one option
		if (rtrns.length == 1)
			return rtrns[0]
		if (extra[0] != -1 || extra[1] != -1) {
			// more than one queen can move there
			// use the extra informatin (eg b from Qbd7
			for (var i = 0;i < rtrns.length;i++) {
				if (extra[0] != -1 && extra[0] == rtrns[i][1])
					return rtrns[i]
				else if (extra[1] != -1 && extra[1] == rtrns[i][0])
					return rtrns[i]
			}
		}
		throw("No queen move found '"+toSAN+"'")
	}

	/* 
		Find the rook's from location.
	*/
	findFromRook = function(brd, toSAN, toCoords, color) {
		var op = getOppColor(color)
		var to = toCoords
		var pos = brd.vBoard
		var extra = to[2]

		// it ain't that simple, what if 2 rooks
		// can move to the same piece but one of
		// them is blocked by another piece
		// then we actually have to go from the dest
		// coord to 4 directions until we find the
		// bloody rook or die trying
		var rtrns = new Array()
		try {
			var tmp
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]+i][to[1]]
				if (tmp && tmp.piece == 'rook' && tmp.color == color) {
					rtrns[rtrns.length] = new Array(to[0]+i, to[1])
					break
				}
				else if (tmp.piece) {
					break;
				}
			}
		}
		catch(e){}
					
		try {
			var tmp
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]-i][to[1]]
				if (tmp && tmp.piece == 'rook' && tmp.color == color) {
					rtrns[rtrns.length] = new Array(to[0]-i, to[1])
					break
				}
				else if (tmp.piece) {
					break
				}
			}
		}
		catch(e){}

		try {
			var tmp
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]][to[1]+i]
				if (tmp && tmp.piece == 'rook' && tmp.color == color) {
					rtrns[rtrns.length] = new Array(to[0], to[1]+i)
					break
				}
				else if (tmp.piece) {
					break
				}
			}
		}
		catch(e){}
					
		try {
			var tmp
			for (var i = 1;i<8;i++) {
				tmp = pos[to[0]][to[1]-i]
				if (tmp && tmp.piece == 'rook' && tmp.color == color) {
					rtrns[rtrns.length] = new Array(to[0], to[1]-i)
					break
				}
				else if (tmp.piece) {
					break
				}
			}
		}
		catch(e){}
		
		// only one option
		if (rtrns.length == 1)
			return rtrns[0]

		if (extra[0] != -1 || extra[1] != -1) {
			// more than one rook can move there
			// use the extra informatin (eg b from Rbd7
			for (var i = 0;i < rtrns.length;i++) {
				if (extra[0] != -1 && extra[0] == rtrns[i][1])
					return rtrns[i]
				else if (extra[1] != -1 && extra[1] == rtrns[i][0])
					return rtrns[i]
			}
		}
		else if (2 == rtrns.length) {
			// let's try the check rule, if it fails
			for (var i = 0;i < rtrns.length; i++) {
				var from = pos[rtrns[i][0]][rtrns[i][1]]
				var oldTo = pos[to[0]][to[1]]
				
				pos[rtrns[i][0]][rtrns[i][1]] = new vSquare()
				pos[to[0]][to[1]] = from

				var checked = isKingChecked(brd,from.color, pos)
				pos[rtrns[i][0]][rtrns[i][1]] = from
				pos[to[0]][to[1]] = oldTo
				if (checked)
					continue
				else
					return rtrns[i]
			}
		}
		throw("No rook move found '"+toSAN+"'")
	}

	/* 
		Find the knight's from location.
	*/
	findFromKnight = function(brd, toSAN, toCoords, color) {
		var to = toCoords
		var extra = to[2]
		var pos = brd.vBoard
		var rtrns = new Array()
		var froms = new Array(
						new Array(to[0]+2, to[1]+1),
						new Array(to[0]+2, to[1]-1),

						new Array(to[0]-2, to[1]+1),
						new Array(to[0]-2, to[1]-1),

						new Array(to[0]+1, to[1]+2),
						new Array(to[0]-1, to[1]+2),

						new Array(to[0]+1, to[1]-2),
						new Array(to[0]-1, to[1]-2)
		)

		for (var i = 0;i<froms.length;i++) {
			try{
				var tmp = pos[froms[i][0]][froms[i][1]]
				if (tmp.piece == 'knight' && tmp.color == color) {
					if (extra[0] != -1 && froms[i][1] != extra[0]) {
						continue;
					}
					else if(extra[1] != -1 && froms[i][0] != extra[1]) {
						continue;
					}
					rtrns[rtrns.length] = new Array(froms[i][0], froms[i][1])
				}
			}
			catch (e) {}
		}
		
		if (rtrns.length>1) {
			for (var i = 0; i< rtrns.length;i++){
				var from = pos[rtrns[i][0]][rtrns[i][1]]
				pos[rtrns[i][0]][rtrns[i][1]] = new vSquare()

				var checked = isKingChecked(brd, from.color, pos)
				pos[rtrns[i][0]][rtrns[i][1]] = from
				if (checked)
					continue
				else
					return rtrns[i]
			}
			return rtrns[0]
		}
		else if (rtrns.length == 1)
			return rtrns[0]
		throw("No knight move found. '"+toSAN+"'")
	}

	/*
	 * Converts a SAN (Standard Algebraic Notation) into 
	 * board coordinates. The SAN is in the format of
	 * eg e4, dxe4, R2b7. When SAN contains extra information
	 * "taking move", "en passante", "check", "piece from a
	 * specific file or rank" it is also extracted.
	*/
	function getSquare(coord) {
		if (arguments.length != 1) {
			throw "Wrong number of arguments"
		}
		
		var map = new Object();
		// if only from certain file we can make the move
		var extra = new Array(-1,-1)
		var taking = -1
		map['a'] = 7, map['b'] = 6, map['c'] = 5;
		map['d'] = 4, map['e'] = 3, map['f'] = 2;
		map['g'] = 1, map['h'] = 0;

		// trim the everything from +
		if (coord.indexOf("+") != -1)
			coord = coord.substring(0, coord.indexOf("+"))
		// let's trim the piece prefix
		if (/^[A-Z]/.test(coord)) {
			coord = coord.substr(1)
		}

		// the move is a taking move, we have to look for different
		// files then with pawns
		if (/x/.test(coord)) {
			var tmp = coord.split("x")   
			if (tmp[0].length) {
				if (/[a-z]/.test(tmp[0]))
					extra[0] = 7-map[tmp[0]]
				else if (/[0-9]/.test(tmp[0]))
					extra[1] = 8-tmp[0]
			}
			coord = tmp[1]
			taking = 7-map[tmp[0]]
		}
		
		// we have extra information on the from file
		// eg Rbd7
		if (/^[a-z]{2,2}/.test(coord)) {
			extra[0] = 7-map[coord.substring(0,1)]
			coord = coord.substring(1)
		}

		// we have the row no also
		if (/^[0-9][a-z][0-9]/.test(coord)) {
			extra[1] = 8-coord.substring(0,1)
			coord = coord.substring(1)
		}

		var rtrn = new Array(8-coord.charAt(1),
												7-map[coord.charAt(0)],
												extra, taking)
		return rtrn;
	}

	getEnPassante = function(brd, x1, y1, x2, y2) {
		var from = brd.vBoard[x1][y1]
		var to = brd.vBoard[x2][y2]

		// pawn move
		if ("pawn" != from.piece)
			return null

		// taking move
		if ((y1-y2) == 0)
			return null

		// destination should be null
		if ( null != to.piece )
			return null

		// the piece we are looking for
		return new Array(x1, y2)
	}

	getOppColor = function(color) {
		return "white"==color?"black":"white"
	}
        
	movePiece = function(from, to, prom) {
		var hist = to.clone()
		var tmpPiece = from.piece
		var pPiece = null

		to.piece = from.piece
		to.color = from.color

		from.piece = null
		from.color = null

		// promoting the piece
		if (prom.length>0) {
			var image = new Image()
			pPiece = tmpPiece

			switch(prom) {
				case 'R':
					to.piece = 'rook'
					break
				case 'B':
					to.piece = 'bishop'
					break
				case 'N':
					to.piece = 'knight'
					break
				case 'Q':
					to.piece = 'queen'
					break
				default:
					throw('Unknown promotion')
			}
		}
		return new Array(from, to, hist, pPiece)
	}
		
	isKingChecked = function(brd, col) {
		var op = getOppColor(col)
		
		var x = brd.wKingX, y = brd.wKingY
		if ("black" == col) {
			x = brd.bKingX, y = brd.bKingY
		}
		// diagonals, looking for bishops, queens
		var tmp
		try {
			for (var i = 1;i < 7; i++) {
				tmp = brd.vBoard[x-i][y-i]
				if (tmp.color == col)
					break
				if (tmp.color == op &&
							("bishop" == tmp.piece || "queen" == tmp.piece))
					return true
			}
		}
		catch (e) {}
			
		try {
			for (var i = 1;i < 7; i++) {
				tmp = brd.vBoard[x+i][y+i]
				if (tmp.color == col)
					break;
					if (tmp.color == op &&
								("bishop" == tmp.piece || "queen" == tmp.piece))
					return true
			}
		}
		catch (e) {}
			
		try {
			for (var i = 1;i < 7; i++) {
				tmp = brd.vBoard[x+i][y-i]
					if (tmp.color == col)
						break;
					if (tmp.color == op &&
								("bishop" == tmp.piece || "queen" == tmp.piece))
					return true
			}
		}
		catch (e) {}
		
		try {
			for (var i = 1;i < 7; i++) {
				tmp = brd.vBoard[x-i][y+i]
				if (tmp.color == col)
					break;
				if (tmp.color == op &&
							("bishop" == tmp.piece || "queen" == tmp.piece))
					return true
			}
		}
		catch (e) {}

		// horizontals, verticals - looking for rooks and queens
		try {
			for (var i = 1;i < 7; i++) {
				tmp = brd.vBoard[x][y+i]
				if (tmp.color == col)
					break;
				if (tmp.color == op &&
							("rook" == tmp.piece || "queen" == tmp.piece))
					return true
			}
		}
		catch (e) {}
		try {
			for (var i = 1;i < 7; i++) {
				tmp = brd.vBoard[x][y-i]
				if (tmp.color == col)
					break;
				if (tmp.color == op &&
							("rook" == tmp.piece || "queen" == tmp.piece))
					return true
			}
		}
		catch (e) {}
		try {
			for (var i = 1;i < 7; i++) {
				tmp = brd.vBoard[x+1][y]
				if (tmp.color == col)
					break;
				if (tmp.color == op &&
							("rook" == tmp.piece || "queen" == tmp.piece))
					return true
			}
		}
		catch (e) {}
		try {
			for (var i = 1;i < 7; i++) {
				tmp = brd.vBoard[x-i][y]
				if (tmp.color == col)
					break;
				if (tmp.color == op &&
							("rook" == tmp.piece || "queen" == tmp.piece))
					return true
			}
		}
		catch (e) {}

		return false
	}
}
      
function MyMove() {
	this.actions = new Array()
	this.oPiece = null
	this.oColor = null
	// in case of promotion have to remember the prev
	// piece
	this.pPiece = null
	//
	this.enP = null
	//
	this.moveStr = null

	this.add = function(action) {
	this.actions[this.actions.length] = action
}

	this.toString = function() {
		return "MyMove -- no. actions "+this.actions.length	 
	}
}
      
function MySquare(x, y, piece, color) {
	var colors = new Array('white','black')
	var pieces = new Array('rook')

	this.x = x
	this.y = y
	this.color = color
	this.piece = piece

	this.toString = function() {
		return "MySquare -- x = "+this.x+" y="+this.y
							+" color="+this.color
							+ " piece="+this.piece
	}

	this.clone = function() {
		var sq = new MySquare(this.x, this.y,
		this.piece, this.color)	 
		return sq
	}
}

function vSquare() {
	this.piece = null
	this.color = null
	
	this.toString = function() {
		return "vSquare -- piece = "+this.piece+" color="+this.color
	}

	this.clone = function() {
		var sq = new vSquare()
		sq.piece = this.piece
		sq.color = this.color
		return sq
	}
}
/**
 * Copyright 2006 Toomas Römer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
**/

/*
	Representation of the PGN format. Different meta information
	about the actual game(s) plus the moves and result of the game.
*/

function Pgn(pgn) {
	// properties of the game eg players, ELOs etc
	this.props = new Object()
	// the moves, one move contains the black and white move
	this.moves = new Array()
	// the current move in the game
	this.currentMove = 0;
	// for outputting white and black moves separately
	this.skip = 0

	this.pgn = pgn

	/* constructor */

	// strip comments
	this.pgn = this.pgn.replace(/\{[^}]*\}/g,'')

	// the properties
	var reprop = /\[([^\]]*)\]/gi
	var matches = this.pgn.match(reprop)
	if (matches) {
		 for(var i = 0;i < matches.length; i++) {
			 // lose the brackets
			 tmpMatches = matches[i].substring(1, matches[i].length-1)
			 // split by the first space
			 var key = tmpMatches.substring(0, tmpMatches.indexOf(" "))
			 var value = tmpMatches.substring(tmpMatches.indexOf(" ")+1)
			 if (value.charAt(0) == '"')
				 value = value.substr(1)
			 if (value.charAt(value.length-1) == '"')
				 value = value.substr(0, value.length-1)
			 
			 this.props[key] = value;
			 this.pgn = this.pgn.replace(matches[i], "")
		 }
	}

	var gameOverre = new Array(
		/1\/2-1\/2/,
		/0-1/,
		/1-0/
	)

	// the moves
	var re;
	for(var i = 1;;i++) {
		re = i+"\\.(\\n| )?([^.]*)"
		
		var result = this.pgn.match(re)
		if (result == null)
			break
		// newlines to spaces
		result[2] = result[2].replace(/\n/g, " ")
		// leave only one space in the middle
		while(result[2].indexOf("  ")!=-1)
			 result[2] = result[2].replace("  ", " ")
		// possible first space gets removed
		if (" "==result[2].charAt(0))
			result[2] = result[2].substring(1)
		var tmp = result[2].split(" ")
		for (var j = 0;j<gameOverre.length;j++) {
			if (gameOverre[j].test(tmp[1]))
			tmp[1] = null
		}
		if (tmp[1] && 0 == tmp[1].length)	
			 tmp[1] = null
		var move = new Move(tmp[0], tmp[1])
		this.moves[this.moves.length] = move
	}

	// no moves
	if (this.moves.length>0) {
		 for(var i = 0; i < gameOverre.length; i++) {
			 if (gameOverre[i].test(this.moves[this.moves.length-1][1])) {
				 this.moves[this.moves.length-1][1] = null
			 }
		 }
	}

	if (/1\/2-1\/2/.test(this.pgn)) {
		this.props['result'] = '1/2-1/2'
	}
	else if (/1-0/.test(this.pgn)) {
		this.props['result'] = '1-0'   
	}
	else if (/0-1/.test(this.pgn)) {
		this.props['result'] = '0-1'
	}
	else {
		this.props['result'] = ''   
	}

	this.nextMove = function() {
		var rtrn = null
		try{
			if (this.skip) {
				this.skip = 0
				rtrn = new Array(this.moves[this.currentMove].black,
													'black');
				this.currentMove++
			}
			else {
				this.skip = 1
				rtrn = new Array(this.moves[this.currentMove].white,
											'white')
			}
	
			if (rtrn[0] == null || rtrn[0].length == 0)
				rtrn = null
			return rtrn
			}
		catch (e) {
			return null
		}
	}
}

function Move(white, black) {
	this.white = white
	this.black = black

	this.toString = function() {
		return this.white+" "+this.black
	}
}

/**
 * Copyright 2006 Toomas Römer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
**/

	function Board(divId, options) {
		var pgn = new Pgn(document.getElementById(divId).firstChild.nodeValue);
		this.conv = new Converter(pgn)
		this.conv.convert()
		this.movesOnPane = new Array()

		this.flipped = false
		this.id = (new Date()).getTime()
		window[this.id] = this
		if (options)
			this.options = options
		else
			this.options = {}
		this.moveInput = null
		this.lastBold = null
		this.lastBoldIdx = null
		this.lastSquare = null
		this.visuals = {"pgn":{}}

		// static
		this.imagePrefix = "img/"
		if (this.options && this.options['imagePrefix']) {
			 this.imagePrefix = this.options['imagePrefix']
		}
		var imageNames = {
			"white" : {"rook":"wRook.gif"
								 ,"bishop":"wBishop.gif"
								 ,"knight":"wKnight.gif"
								 ,"queen":"wQueen.gif"
								 ,"king":"wKing.gif"
								 ,"pawn":"wPawn.gif"}
            
			,"black" : {"rook":"bRook.gif"
								 ,"bishop":"bBishop.gif"
								 ,"knight":"bKnight.gif"
								 ,"queen":"bQueen.gif"
								 ,"king":"bKing.gif"
								 ,"pawn":"bPawn.gif"}
			,"btns" : {"ffward":"buttons/ffward.gif"
									,"rwind":"buttons/rwind.gif"
									,"forward":"buttons/forward.gif"
									,"back":"buttons/back.gif"
									,"toggle":"buttons/toggle.gif"
									,"flip":"buttons/flip.gif"}
		};
		// end of static
		this.pos = new Array()

		for(var i = 0;i<8;i++)
			this.pos[i] = new Array()
      
	 this.init = function() {
		// prefix the images correctly
		for ( i in imageNames)
			 for (j in imageNames[i])
					imageNames[i][j] = this.imagePrefix+imageNames[i][j]
		// the main frame
		var boardFrame = document.getElementById(divId+"_board");
		
		// toplevel table
		var topTable = document.createElement("table")
		var topTableTb = document.createElement("tbody")
		topTable.appendChild(topTableTb)
		
		topTable.style.border = "1px solid #000000"

		var boardTd = document.createElement("td")
		boardTd.style.width = "257px"
		var btnTd = document.createElement("td")
		btnTd.vAlign = 'top'
		var propsTd = document.createElement("td")
		
		// movesTable
		var movesTd = document.createElement("td")
		this.movesTd = movesTd
		if (this.options['movesPaneWidth'])
			movesTd.style.width = this.options['movesPaneWidth']
		else
			movesTd.style.overflow = "auto"
		movesTd.rowSpan = 3
		movesTd.valign = "top"
		
		var tmp = document.createElement("tr")
		tmp.appendChild(boardTd)
		tmp.appendChild(movesTd)
		topTableTb.appendChild(tmp)

		topTableTb.appendChild(document.createElement("tr")).appendChild(btnTd)
		topTableTb.appendChild(document.createElement("tr")).appendChild(propsTd)


		var board = document.createElement("table")
		var boardTb = document.createElement("tbody")
		board.appendChild(boardTb)
		
		board.style.top = boardFrame.style.top;
		board.style.left = boardFrame.style.left;
		board.style.borderCollapse = "collapse"
		
		boardFrame.appendChild(topTable);
		boardTd.appendChild(board)
		
		var width = 31;
		var height = 31;
		this.options['blackSqColor'] = "#4b4b4b"
		this.options['whiteSqColor'] = "#ffffff"
		var whiteC = this.options['whiteSqColor']
		var blackC = this.options['blackSqColor']

		// white pieces
		for(var i = 0; i < 8; i++) {
			var tr = document.createElement("tr")
			var flip = (i % 2)?1:0;
			for(var j = 0; j < 8; j++) {
				var td = document.createElement("td")   

				td.style.height = height+"px"
				td.style.width = width+"px"
				td.style.border = "1px solid #000000"
				td.style.padding = "0px"
				var color = !flip?(j%2)?blackC:whiteC:!(j%2)?blackC:whiteC
				
				td.style.background = color

				this.pos[i][j] = td;
				tr.appendChild(td)
			}
			boardTb.appendChild(tr)
		}
		this.populatePieces()
		this.populateProps(propsTd)
		this.populateMoves(movesTd)
	 
		// in java i could do Board.this in anon function
		var tmp = this
		// button td
		btnTd.align = 'center'
		btnTd.valign = 'middle'

		// rwnd
		var hrefS = document.createElement("a")
		hrefS.href = "javascript:void(0)"
		var href = hrefS.cloneNode(false)
		var input = this.getImg("rwind","btns")
		input.alt = 'Rewind to the beginning'
		input.title = 'Rewind to the beginning'
		href.appendChild(input)
		
		input.onclick = function() {
			startPosition(tmp)
		}
		btnTd.appendChild(href)

		// back
		input = this.getImg("back","btns")
		input.alt = 'One move back'
		input.title = 'One move back'
		href = hrefS.cloneNode(false)
		href.appendChild(input)
		
		input.onclick = function() {
			makeBwMove(tmp)
		}
			
		btnTd.appendChild(href)
		
		// flip the board
		input = this.getImg("flip","btns")
		input.alt = 'Flip the board'
		input.title = 'Flip the board'
		href = hrefS.cloneNode(false)
		href.appendChild(input)
		
		input.onclick = function() {
			flipBoard(tmp)
		}

		btnTd.appendChild(href)
		
		// current move
		var input = document.createElement("input")
		input.style.fontSize = "7pt"
		input.size = "9"
		input.style.border = "1px solid #000000"
		this.moveInput = input
		btnTd.appendChild(input)
		// end of current move

		// hide
		input = this.getImg("toggle","btns")
		input.alt = 'Show moves pane'
		input.title = 'Show moves pane'
		href = hrefS.cloneNode(false)
		href.appendChild(input)
		
		if (!this.options['showMovesPane'])
			 this.options['showMovesPane'] = false
		
		input.onclick = function() {
			toggleMoves(tmp, "flip")
		}

		btnTd.appendChild(href)
		
		// next btn
		input = this.getImg("forward","btns")
		input.alt = 'Play one move'
		input.title = 'Play one move'
		href = hrefS.cloneNode(false)
		href.appendChild(input)

		input.onclick = function() {
			makeMove(tmp)
		}

		btnTd.appendChild(href)
		
		// ffwd
		input = this.getImg("ffward","btns")
		input.alt = 'Fast-forward to the end'
		input.title = 'Fast-forward to the end'
		href = hrefS.cloneNode(false)
		href.appendChild(input)

		input.onclick = function() {
				endPosition(tmp)
		}
		btnTd.appendChild(href)
		updateMoveInfo(this)
	 }

		flipBoard = function(board) {
			board.deMarkLastMove(true)
			var frst, snd, tmp
			board.flipped = !board.flipped
			for (var i = 0;i<8;i++) {
				for (var j = 0;j<4;j++){
					frst = board.pos[i][j]
					snd = board.pos[7-i][7-j]

					try {
						 tmp = frst.removeChild(frst.firstChild)
					}
					catch (e) {tmp=null}

					try{
						 frst.appendChild(snd.removeChild(snd.firstChild))
					}
					catch (e) {}
					
					if (tmp)
						snd.appendChild(tmp)
				} 
			}
		}

					this.skipToMove = function(no, color) {
						var rNo = no*2+color+1
						if (this.conv.getCurMoveNo()<rNo) {
							var i = 0
							while(this.conv.getCurMoveNo()<rNo && i < 200) {
								makeMove(this, true)
								i++
							}
							updateMoveInfo(this)
							updateMovePane(this)
							this.deMarkLastMove()
							this.markLastMove()
						}
						else if (this.conv.getCurMoveNo()>rNo) {
							var i = 0
							while(this.conv.getCurMoveNo()>rNo && i < 200) {
								makeBwMove(this, true)
								i++
							}
							updateMoveInfo(this)
							updateMovePane(this)
							this.deMarkLastMove()
							this.markLastMove()
						}
					}

					endPosition = function(board) {
						board.deMarkLastMove()
						var vBoard = board.conv.getEndPos(board.flipped)
						board.syncBoard(vBoard);
						board.conv.resetToEnd()
						updateMoveInfo(board)
						updateMovePane(board, true)
						board.markLastMove()
					}

					this.startPosition = function(){
						startPosition(this)
					}

					startPosition = function(board) {
						board.deMarkLastMove(true)
						var vBoard = board.conv.getStartPos(board.flipped)
						board.syncBoard(vBoard)
						board.conv.resetToStart()
						updateMoveInfo(board)
						updateMovePane(board)
					}

					makeBwMove = function(board, noUpdate) {
						var move = board.conv.prevMove()
						if (move == null)
							 return;
						
						if (!noUpdate) {
							board.deMarkLastMove(true)
							board.markLastMove()
							updateMoveInfo(board)
							updateMovePane(board, true)
						}

						for(var i=move.actions.length;i > 1;i-=2) {
							var frst = move.actions[i-1].clone()
							var snd = move.actions[i-2].clone()
							var tmpM = new MySquare()
							tmpM.piece = frst.piece
							tmpM.color = frst.color
							frst.piece = snd.piece
							frst.color = snd.color
							snd.piece = tmpM.piece
							snd.color = tmpM.color

							frst.piece = move.oPiece
							frst.color = move.oColor
							
							if (move.pPiece)
								 snd.piece = move.pPiece

							board.drawSquare(frst)
							board.drawSquare(snd)
						}
						if (move.enP) {
							 var x = move.enP.x, y = move.enP.y
							 if (board.flipped) {
								 x=7-x
								 y=7-y
							}
							var sq = board.pos[x][y]
							sq.appendChild(board.getImg(move.enP.piece, move.enP.color))
						}
					}

					this.markLastMove = function() {
						try {
							var move = this.conv.moves[this.conv.iteIndex-1].actions[1];
							var piece = this.pos[move.x][move.y]
							if (this.flipped) {
								piece = this.pos[7-move.x][7-move.y]
							}
							// on konq the bg contains "initial initial initial "
							// i guess xtra information. Anyways setting the
							// background to a color containing the "initial"
							// parts fails. Go figure
							piece.lastBg = piece.style.background.replace(/initial/g, "")
							piece.style.background = "#e89292"
							this.lastSquare = piece
						}
						catch (e) {}
					}

					this.deMarkLastMove = function() {
						var move = this.conv.moves[this.conv.iteIndex-2]
						if (arguments.length && arguments[0]) {
							move = this.conv.moves[this.conv.iteIndex-1]
						}
						
						if (this.conv.iteIndex+1 == this.conv.moves.length)
							 move = this.conv.getCurMove()

						if (move) {
							move = move.actions[1]
							
							var piece = this.pos[move.x][move.y]
							if (this.flipped) 
								piece = this.pos[7-move.x][7-move.y]
							if (piece.lastBg)
								piece.style.background = piece.lastBg
						}
						if (this.lastSquare && this.lastSquare.lastBg) {
							this.lastSquare.style.background = this.lastSquare.lastBg
							this.lastSquare = null
						}
					}

					/*
						Toggle moves pane, actually not toggle but
						showing it depending the 'flag'.
					*/
					this.toggleMoves = function(flag) {
						if (flag == "flip")
							flag = this.movesTd.style.visibility=="hidden"
						if (flag) {
							this.movesTd.style.display = "block"
							this.movesTd.style.visibility = "visible"
						}
						else {
							this.movesTd.style.display = "none"
							this.movesTd.style.visibility = "hidden"
						}
					}

					/*
						Non-member toggle function. The onClick that I'm
						setting must not be a member function. I'm just
						using it to proxy.
					*/
					toggleMoves = function(board, flag) {
						board.toggleMoves(flag)
					}

					updateMoveInfo = function(board) {
						var idx = board.conv.getCurMoveNo()-1
						if (board.conv.getCurMoveNo() == board.conv.moves.length-1)
							idx = board.conv.getCurMoveNo()
						var move = board.conv.moves[idx]
						if (move && move.moveStr) {
							 var str = Math.floor((idx==0?1:idx)/2+1)+". "+move.moveStr
							 board.moveInput.value = str
						}
						else
							 board.moveInput.value = ""
					}

					makeMove = function(board, noUpdate) {
						var move = board.conv.nextMove()
						if (move == null)
							 return;
						
						if (!noUpdate) {
							 board.deMarkLastMove()
							 board.markLastMove()

							 updateMoveInfo(board)
							 updateMovePane(board)
						}
						
						for(var i=0;i < move.actions.length;i++) {
							board.drawSquare(move.actions[i]);	 
						}
						
						board.drawEnPassante(move)
					}

					updateMovePane = function(board, bw) {
						// highlight the move in the move's pane
						var idx = board.conv.getCurMoveNo()
						board.movesOnPane[this.lastBoldIdx] = deMakeBold(this.lastBold)
						if (bw)
							 idx+=1
						this.lastBold = null
						this.lastBoldIdx = null
						if (board.movesOnPane[idx-1]) {
							board.movesOnPane[idx-1] = makeBold(board.movesOnPane[idx-1])
							this.lastBold = board.movesOnPane[idx-1]
							this.lastBoldIdx = idx-1
						}
					}

					makeBold = function(el) {
						var b = document.createElement("b")
						b.appendChild(el.cloneNode(true))
						el.parentNode.replaceChild(b, el)
						return b
					}

					deMakeBold = function(el) {
						if (!el)
							 return;
						var rtrn = el.firstChild.cloneNode(true)
						el.parentNode.replaceChild(rtrn, el)
						return rtrn
					}

					this.drawEnPassante = function(move) {
						if (!move.enP)
							 return;
						var x = move.enP.x, y = move.enP.y
						if (this.flipped) {
							x = 7-x
							y = 7-y
						}
						var sq = this.pos[x][y]
						
						sq.color = null
						sq.piece = null

						sq.removeChild(sq.firstChild)
					}

					this.drawSquare = function(square) {
						var x = square.x, y = square.y
						if (this.flipped) {
							x=7-x
							y=7-y
						}
						var sq = this.pos[x][y]

						sq.color = square.color
						sq.piece = square.piece

						if (sq.firstChild)
							sq.removeChild(sq.firstChild)

						if (sq.piece) {
							sq.appendChild(this.getImg(sq.piece,sq.color))
						}
					}

					this.updatePGNInfo = function() {
						if (this.conv.pgn.props['White'])
							this.visuals['pgn']['players'].nodeValue = 
									this.conv.pgn.props['White']+" - "+
									this.conv.pgn.props['Black']
						if (this.visuals['pgn']['WhiteElo'])
							this.visuals['pgn']['elos'].nodeValue = 
									this.conv.pgn.props['WhiteElo']+" - "+
									this.conv.pgn.props['BlackElo']
						if (this.visuals['pgn']['Event'])	
							this.visuals['pgn']['event'].nodeValue =
									this.conv.pgn.props['Event']+", "
									+this.conv.pgn.props['Date']
					}

					this.updateSettings = function() {
						var blacks = this.options['blackSqColor']
						var whites = this.options['whiteSqColor']
						
						for(var i=0;i<8;i++){
							var flip = (i%2)?true:false
							for(var j=0;j<8;j++){
								var color = flip?(j%2)?whites:blacks:!(j%2)?whites:blacks
								this.pos[i][j].style.background = color
							}
						}
					}

					/*
					 * Draw the board with all the pieces in the initial
					 * position
					*/
					this.populatePieces = function() {
					// pawns
					for (var i = 0;i < 8; i++) {
						img = this.getImg('pawn','white')
						this.pos[6][i].appendChild(img);
						this.pos[6][i].piece = 'pawn';
						this.pos[6][i].color = 'white';
            
						img = this.getImg('pawn','black')
						this.pos[1][i].appendChild(img);
						this.pos[1][i].piece = 'pawn';
						this.pos[1][i].color = 'black';
					}

					// rooks, bishops, knights
					for(var i = 0; i < 2; i++) {
						img = this.getImg('rook','white')
						this.pos[7][i*7].appendChild(img)
						this.pos[7][i*7].piece = 'rook'
						this.pos[7][i*7].color = 'white'

						img = this.getImg('rook','black')
						this.pos[0][i*7].appendChild(img)
						this.pos[0][i*7].piece = 'rook'
						this.pos[0][i*7].color = 'black'

						img = this.getImg('knight','white')
						this.pos[7][i*5+1].appendChild(img)
						this.pos[7][i*5+1].piece = 'knight'
						this.pos[7][i*5+1].color = 'white'

						img = this.getImg('knight','black')
						this.pos[0][i*5+1].appendChild(img)
						this.pos[0][i*5+1].piece = 'knight'
						this.pos[0][i*5+1].color = 'black'
         
						img = this.getImg('bishop','white')
						this.pos[7][i*3+2].appendChild(img)
						this.pos[7][i*3+2].piece = 'bishop'
						this.pos[7][i*3+2].color = 'white'

						img = this.getImg('bishop','black')
						this.pos[0][i*3+2].appendChild(img)
						this.pos[0][i*3+2].piece = 'bishop'
						this.pos[0][i*3+2].color = 'black'
					}
         
					img = this.getImg('queen','white')
					this.pos[7][3].appendChild(img)
					this.pos[7][3].piece = 'queen'
					this.pos[7][3].color = 'white'

					img = this.getImg('king','white')
					this.pos[7][4].appendChild(img)
					this.pos[7][4].piece = 'king'
					this.pos[7][4].color = 'white'

					img = this.getImg('queen','black')
					this.pos[0][3].appendChild(img)
					this.pos[0][3].piece = 'queen'
					this.pos[0][3].color = 'black'

					img = this.getImg('king','black')
					this.pos[0][4].appendChild(img)
					this.pos[0][4].piece = 'king'
					this.pos[0][4].color = 'black'
				}

				this.populateMoves = function(cont) {
					if (!this.options['showMovesPane']) {
						 cont.style.visibility="hidden"
						 cont.style.display="none"
					}
					cont.vAlign = "top"
					var tmp2=this.conv.pgn.moves
					var p = document.createElement("p")
					p.style.fontSize = "9pt"
					p.style.fontFace = "Tahoma, Arial, sans-serif"
					p.style.fontWeight = "bold"
					var txt = document.createTextNode("")
					if (this.conv.pgn.props['White'])
						var txt = document.createTextNode(this.conv.pgn.props['White']
										+" - "+this.conv.pgn.props['Black'])
					p.appendChild(txt)
					cont.appendChild(p)
					
					var link, tmp, tmp3
					for (var i = 0;i < tmp2.length;i++) {
						link = document.createElement("a")
						tmp = document.createTextNode(tmp2[i].white)
						tmp3 = document.createElement("b")

						tmp3.style.fontFamily = "Tahoma, Arial, sans-serif"
						tmp3.style.fontSize = "8pt"
						tmp3.appendChild(document.createTextNode(" "+(i+1)+". "))
						cont.appendChild(tmp3)
						
						link.href = 'javascript:void(window['+this.id+']'
												+'.skipToMove('+i+','+0+'))'
						link.appendChild(tmp)
						link.style.fontSize = "8pt"
						cont.appendChild(link)
						this.movesOnPane[this.movesOnPane.length] = link

						if (tmp2[i].black != null) {
							cont.appendChild(document.createTextNode(" "))
							tmp = document.createTextNode(tmp2[i].black)
							link = document.createElement("a")
							link.style.fontSize = "8pt"
							link.appendChild(tmp)
							link.href = 'javascript:void(window['+this.id+']'
												+'.skipToMove('+i+','+1+'))'
							cont.appendChild(link)
							this.movesOnPane[this.movesOnPane.length] = link
						}
					}
					txt = document.createTextNode("  "+this.conv.pgn.props['result'])
					tmp2 = document.createElement("b")
					tmp2.appendChild(txt)
					cont.appendChild(tmp2)
					this.movesOnPane[this.movesOnPane.length] = tmp2
				}

				this.populateProps = function(container) {
					// init the style
					var tdS = document.createElement('td')
					tdS.style.fontFamily = "Tahoma, Arial, sans-serif"
					tdS.style.fontSize = "8pt"
					tdS.align = 'center'
					// end of init the style
					
					var tbl = document.createElement('table')
					tbl.cellPadding = "0"
					tbl.cellSpacing = "0"
					var tblTb = document.createElement("tbody")
					tbl.appendChild(tblTb)

					tbl.width = "100%"
					container.appendChild(tbl)
					
					// white - black
					var tr = document.createElement('tr')
					tblTb.appendChild(tr)
					
					var td = tdS.cloneNode(true)
					td.style.fontWeight = "bold"
					tr.appendChild(td)

					var txt = document.createTextNode('')
					this.visuals['pgn']['players'] = txt
					td.appendChild(txt)
					//
					
					// ELO
					tr = document.createElement('tr')
					tblTb.appendChild(tr)
					
					td = tdS.cloneNode(false)
					tr.appendChild(td)

					txt = document.createTextNode('')
					this.visuals['pgn']['elos'] = txt
					td.appendChild(txt)
					//
					
					// Date 
					tr = document.createElement('tr')
					tblTb.appendChild(tr)
					
					td = tdS.cloneNode(false)
					tr.appendChild(td)

					txt = document.createTextNode('')
					this.visuals['pgn']['event'] = txt
					td.appendChild(txt)
					//
					this.updatePGNInfo()
				}

				this.getImg = function(piece, color) {
					var img = new Image()
					img.src = imageNames[color][piece]
					img.border = 0
					
					return img
				}

				this.syncBoard = function(result) {
					for(var i=0;i<8;i++) {
						for(var j=0;j<8;j++) {
							this.syncSquare(result[i][j]
													,this.pos[i][j])
						}
					}
				}

				this.syncSquare = function(from, to) {
					to.piece = from.piece
					to.color = from.color

					if (to.firstChild)
						 to.removeChild(to.firstChild)
					if (to.piece) {
						to.appendChild(this.getImg(to.piece, to.color))
					}
				}

				function setUp(board, divId) {
					var pgn = new Pgn(document.getElementById(divId).firstChild.nodeValue);
					var conv = new Converter(pgn)
					conv.convert()      
					 
					var brd = new Board(conv)
					brd.init()
				}
			}
