// Utils global functions

function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	}
	else {
		window.onload = function() {
			oldonload();
			func();
		}
	}
}

function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}

function savePreferences() {
	var name='pref';var days=730;var value='';
	
	value+='{"chessSet":"'+chessHereObj.chessSet+'","boardLabels":true,"squareSize":'+
	chessHereObj.squareSize+',"myCursor":"'+chessHereObj.myCursor+'","winBg":"'+chessHereObj.winBg+
	'","sounds":'+chessHereObj.sound+',"playDelay":'+chessHereObj.playDelay+',"indicators":'+chessHereObj.indicateLastMove+',"divIndicatorsColor":"#F9F340"'+
	',"bgImageLightSquares":"'+chessHereObj.bgImageLightSquares+'","bgImageDarkSquares":"'+
	chessHereObj.bgImageDarkSquares+'","colorLightSquares":"'+chessHereObj.colorLightSquares+'","colorDarkSquares":"'+chessHereObj.colorDarkSquares +'"}';
	
	createCookie(name,value,days);
	
}

if (!Array.prototype.push) {
    Array.prototype.push = function(el){
        this[this.length] = el;
    }
}

function keepSessionAlive(){
    var img = new Image();
    img.src = "http://www.chesshere.com/play-chess/sesska.php?rnd=" + new Date().getTime();
}

window.setInterval(keepSessionAlive, 1000 * 60 * 10);

function parseJSON(text) {
if (!text) return false;
try {
var re=eval('('+text+')');
return re;
} catch(e) {
return false;
}
}

function checkSaving(evt)
{
		if (gameControl.isChangesDone == true) {
			var message = 'The changes you have made have not been saved yet! (Variants and Comment)';
			evt = evt || window.event;
			if (evt) {
				evt.returnValue = message;
			}
			return message;
	
		}
}			


if( window.addEventListener ) {
			window.addEventListener('beforeunload',checkSaving,false);
		} else if ( window.attachEvent ) {
			window.attachEvent('onbeforeunload',checkSaving);
		} else {
			window.onbeforeunload = checkSaving;
}

function debug(msg){
    $('debug').innerHTML += msg + '<br><br>';
}

//EO Utils


// Game Controller

var gameControl;

function CHController(fen, pgn, color, mod, turn) {

    var defaultFen;
    var defaultPgn;
    var mySideColor = color;
    
    var gameStatus;

	var firstPgnMove;

	var controlMode;

	var currentMoveIndex;
	
	var parentSanIndex;
	var variantLineIndex;
	
	var enableVariant;
	
	var isChangesDone;
	var isItMyTurn;
  var repeatedMoves;	
	var userMadeHisMove;
	var lastMoveIndex;
	this.currentMoveIndex = 0;
	this.lastMoveIndex =0;
  this.repeatedMoves = 0;	

	this.parentSanIndex = 0;
	this.variantLineIndex = 0;
	
	this.variantLines = 0;
	
	this.enableVariant = true;
	
	this.boardMode = '';
	
	this.isChangesDone = false;
	
	this.isItMyTurn = turn || false;
	
	this.controlMode = mod || 'viewer';
	

	this.userMadeHisMove=false;

			    
    if (!fen) {
        this.defaultFen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
    } else {
    	this.defaultFen = fen;	
	}   

    this.defaultPgn = pgn;
	
    this.mySideColor = mySideColor;
    
    this.gameStatus = [];
	
	this.firstPgnMove = 1;
	
	gameControl = this;
    
    this.startChess();
}

CHController.prototype = {

    startChess: function(){
		
		this.currentMoveIndex = 0;

		this.parentSanIndex = 0;
		this.variantLineIndex = 0;
	
		this.variantLines = 0;
	
		this.enableVariant = true;
		
		var cc = new ChessHereBoard(this.mySideColor);
	
		chessHereObj.createNewBoard(this.defaultFen);
	
		addLoadEvent(this.setWinBg);		
		
		if (this.controlMode=='viewer') {
			this.doFree();
		} else if (this.controlMode=='player') {
			this.doPlay();
		} else if (this.controlMode=='analyzer') {
			this.doVariant();			
		}

				
		//TODO: validate fen!
			
		this.gameStatus.push( new ChessHereMove(this.currentMoveIndex, this.parentSanIndex,
		 this.variantLines, this.variantLineIndex,
			this.defaultFen,'','','','',chessHereObj.moveNumber,'')
		);
		
	
		this.firstPgnMove = chessHereObj.moveNumber;
		if (chessHereObj.currentMoveTurn == 'b') {
                this.firstPgnMove += 0.5;
        }

		if (this.defaultPgn) {
        chessHereObj.ShowMode = 'hidden';
        if (!this.processRavPgn(this.defaultPgn)) { 
			this.defaultPgn = ''; // pgn not valid!	
      //$('fix_form').action = window.location.href;	
			//$('fix_form').submit(); //debug!!
		}
		chessHereObj.ShowMode = 'visible';
   }
        
        chessHereObj.__createBoardDiv();
        chessHereObj.addRealPiecesToBoard();
        $('loadingDiv').style.display = 'none';
		
        if (this.defaultPgn) {
            chessHereObj.indicateMove(this.gameStatus[this.lastMoveIndex].move);		      
            this.SANArrayToPGN();
			
			$('pgnTableMoves').innerHTML = this.SANArrayToScoreSheet(0);
			
			this.currentSanFocus();
			
			if (this.controlMode != 'viewer') {
				var comment = this.gameStatus[this.currentMoveIndex].comment;
				this.showComment(this.currentMoveIndex);
			}
			
		if (chessHereObj.sound) {
			this.playSound(this.gameStatus[this.currentMoveIndex].sound);
		}
	
		this.showMsg(this.gameStatus[this.currentMoveIndex].message);			
			
        }
		
		chessHereObj.isMyTurn = this.isItMyTurn;

			
		$('fenBox').innerHTML = this.gameStatus[this.gameStatus.length-1].fen;
			
        chessHereObj.fillTakenPieces('w');
        chessHereObj.fillTakenPieces('b');
		
		this.playDelay = chessHereObj.playDelay || 1000;
        
    }
	,
	isAllowToAddMoveHere : function()
	{
		var idx = this.currentMoveIndex;
		var parent = this.gameStatus[idx].parentSan;
		var line = this.gameStatus[idx].variantLine;
		
		for (var i = idx+1; i < this.gameStatus.length; i++) {
			if (!gameControl.gameStatus[i]) { continue; }
			if (gameControl.gameStatus[i].parentSan == parent && 
			    gameControl.gameStatus[i].variantLine == line
				) {
				return false;
			}
		
		}
		
		return true;
		
	}
	,
	moveDone : function(status)
	{
		
	if (chessHereObj.ShowMode != 'hidden') {
		
		if (chessHereObj.sound) {
			this.playSound(status.sound);
		}
		
		if (!status.message || status.message == 'undefined') {
			status.message = '';
		}		
		this.showMsg(status.message);
		
		$('fenBox').innerHTML = status.fen;
		
		if (this.boardMode == 'play') {
			if (this.currentMoveIndex != this.lastMoveIndex) {
				alert('You are in playing mode now, so you can only view or make move from the real game position!');
			    this.goToMove(this.lastMoveIndex);
				chessHereObj.isMyTurn = this.isItMyTurn;
				return;
			}
			this.updatePlayerMove(status.move, status.san);
			
		} else if (this.boardMode == 'free' || this.currentMoveIndex==0) {
			return;
		} else if (this.boardMode == 'variant') {
				this.isChangesDone = true;
		}
	}

	var isAllowedToAddMoveHere = this.isAllowToAddMoveHere();
	if ( this.enableVariant && chessHereObj.ShowMode != 'hidden' && 
	( (!isAllowedToAddMoveHere || this.parentSanIndex==0) && this.boardMode=='variant') ) {
		this.openVariant();
	}
	
	if (chessHereObj.currentMoveTurn == 'w') {
		status.m_no+=0.5;
	}
	
	if (!this.enableVariant) {
		this.variantLineIndex = this.gameStatus[this.parentSanIndex].variantLines;
	}
	
	this.currentMoveIndex = this.gameStatus.length;	
		
		this.gameStatus.push( new ChessHereMove(this.currentMoveIndex, this.parentSanIndex,
		 this.variantLines, this.variantLineIndex, 
			status.fen,status.move,status.san,'',status.sound,status.m_no,status.message)
		);
		
	this.enableVariant = true;
	
	if (chessHereObj.ShowMode != 'hidden') {
	
		this.SANArrayToPGN();
		
		$('pgnTableMoves').innerHTML = this.SANArrayToScoreSheet(0);

		$('ravCommentInput').value = '';
		$('comment_view').innerHTML = '';
		
		this.currentSanFocus();
		
			if (this.gameStatus[this.currentMoveIndex].parentSan> 0) {
				$('ravTableMoves').innerHTML = this.SANArrayToScoreSheet(this.gameStatus[this.currentMoveIndex].parentSan);
				
				var nextLevel = this.SANArrayToScoreSheet(this.currentMoveIndex);
				if (nextLevel) {
					$('ravTableMoves').innerHTML += '<div style="text-align: center"> - Variant Level 2 - </div>' + nextLevel;
				}
				
			} else {
				$('ravTableMoves').innerHTML = this.SANArrayToScoreSheet(this.currentMoveIndex);
			}	
					
  	if (chessHereObj.gameWinner == '*' && this.isThreeFoldDraw())
  	{
	   chessHereObj.gameWinner='Draw';
	   chessHereObj.gameResault = '1\\2-1\\2'; 
	  }
    if (this.boardMode == 'play') {
	  $('fenBox').innerHTML += '<br><br> [ Position Repeated: ' + this.repeatedMoves + ' ]';
    }
    
	 if (chessHereObj.gameWinner && chessHereObj.gameWinner != '*') {
	     
	   if (chessHereObj.gameWinner=='Draw') {
	   
	   if (chessHereObj.gameReason == 'Half moves draw' && chessHereObj.halfMoves < 100) {
     chessHereObj.gameReason='';
     chessHereObj.gameWinner='';
     
     } else {
	    var v='';
	    if ($('claim_a_draw_div') && this.boardMode == 'play') {
	        $('claim_a_draw_div').style.display='block';
	        $('claim_a_draw').value='ab';
       //v='<br><br> [ You can enforce it by click on `Claim a draw`! ]';
          this.showMsg('Current position is a draw - ' + chessHereObj.gameReason + v); 
       } else if ($('claim_a_draw') && this.boardMode == 'play') {
       	  $('claim_a_draw_div').style.display='none';
	        $('claim_a_draw').value='claim';
       }
     }
      
     } else {
       this.showMsg(chessHereObj.gameWinner +' won! &nbsp;&nbsp;'+ chessHereObj.gameReason);
     }
  }
  
		
	}	
	}
	,
	currentSanFocus : function()
	{
		if ($('currentSanTd')) {
			$('pgnTableMoves').scrollTop = $("currentSanTd").offsetTop;
		}
		
	}
	,
	openVariant : function()
	{
		if (!gameControl.enableVariant) {return;}
		
		gameControl.enableVariant = false;
		
		gameControl.parentSanIndex = gameControl.currentMoveIndex;
		
		gameControl.gameStatus[gameControl.currentMoveIndex].variantLines++;
		
	}
	,
	closeVariant : function()
	{
		if (gameControl.gameStatus[gameControl.currentMoveIndex].parentSan == 0) { 
			return;
		}
		if (!gameControl.enableVariant) {			
			gameControl.gameStatus[gameControl.parentSanIndex].variantLines--;
		}
		
		gameControl.enableVariant = true;
		
		gameControl.goToMove(gameControl.parentSanIndex);
		
		gameControl.parentSanIndex = gameControl.gameStatus[gameControl.currentMoveIndex].parentSan;
	}
	,
	goToMove : function(idx)
	{
		if (gameControl.userMadeHisMove) {
			alert('You done your move, please click Move or Reset first');
			return false;
		}
				
		if (!gameControl.gameStatus[idx]) {return;}
			
		gameControl.currentMoveIndex=idx;
		
		
		if (gameControl.enableVariant) {
			gameControl.parentSanIndex = gameControl.gameStatus[idx].parentSan;
			gameControl.variantLineIndex = gameControl.gameStatus[idx].variantLine;
		}

		
		if (chessHereObj.ShowMode != 'hidden') {
			
            chessHereObj.removePiecesFromBoard();			
            chessHereObj.createNewBoard(gameControl.gameStatus[idx].fen);
            chessHereObj.addRealPiecesToBoard();			
			
			chessHereObj.indicateMove(gameControl.gameStatus[idx].move);
			
			chessHereObj.fillTakenPieces('w');
			chessHereObj.fillTakenPieces('b');
			
			gameControl.SANArrayToPGN();
			
		if (chessHereObj.sound) {
			gameControl.playSound(gameControl.gameStatus[idx].sound);
		}
		
		gameControl.showMsg(gameControl.gameStatus[idx].message);
		
		$('fenBox').innerHTML = gameControl.gameStatus[idx].fen;	
		
		$('pgnTableMoves').innerHTML = gameControl.SANArrayToScoreSheet(0);		
			
			if (gameControl.controlMode != 'viewer') {
				
				gameControl.showComment(idx);
				
				if (gameControl.gameStatus[idx].parentSan > 0) {
					$('ravTableMoves').innerHTML = gameControl.SANArrayToScoreSheet(gameControl.gameStatus[idx].parentSan);
					
					var nextLevel = gameControl.SANArrayToScoreSheet(idx);
					if (nextLevel) {
						$('ravTableMoves').innerHTML += '<div style="text-align: center"> - Variant Level 2 - </div>' + nextLevel;
					}
					
				}
				else {
					$('ravTableMoves').innerHTML = gameControl.SANArrayToScoreSheet(idx);
				}

			}
			
		this.currentSanFocus();
		
		//debug(gameControl.gameStatus[idx].toSource());
		
		} else {
			chessHereObj.createNewBoard(gameControl.gameStatus[idx].fen);
		}
		
		// chessHereObj.moveNumber = parseInt(chessHereObj.moveNumber+0.5);
		chessHereObj.moveNumber = parseInt(gameControl.gameStatus[idx].m_no+0.5);		
		chessHereObj.pieceSelected = null;		
	}
	,
	showComment : function(idx)
	{
		var comment = gameControl.gameStatus[idx].comment.replace(/\&lt;/g, "<").replace(/\&gt;/g, ">");
		$('ravCommentInput').value = comment;
		if (comment) {
			$('comment_view').innerHTML = '<span>Move comment:</span>&nbsp;' + gameControl.gameStatus[idx].comment;
		}
	}
	,
	addComment : function()
	{
		var comment = $('ravCommentInput').value.replace(/</g, "&lt;").replace(/>/g, "&gt;");
		gameControl.gameStatus[gameControl.currentMoveIndex].comment = comment;
		gameControl.SANArrayToPGN();
		gameControl.isChangesDone = true;
		$('cmd_comment').style.color = '#999999';
		if (comment) {
			$('comment_view').innerHTML = '<span>Move comment:</span>&nbsp;' + comment;
		}
		
	}
	,
	showMsg : function(msg,t)
	{
	 if (!$('sys_msg')) {return;}
     clearTimeout(this.msgTimeOut);
     $('sys_msg').innerHTML=msg;
	 if (t && t > 990) {
	 	this.msgTimeOut = setTimeout(gameControl.hideMsg, t);
	 }
	}
	,
	hideMsg : function()
	{
		$('sys_msg').innerHTML='';
	}
  ,
	isThreeFoldDraw : function()
	{ 
		var fen,all;
	  this.repeatedMoves = 0;
	  
    var curfen = this.gameStatus[this.currentMoveIndex].fen;
    all = curfen.split(' ');
    all.length = 4;
    curfen = all.join(' ');

		for (var i = 1; i < this.gameStatus.length; i++) {
			
			if (!this.gameStatus[i]) { continue; }
			if (this.gameStatus[i].parentSan == 0) {
        fen = this.gameStatus[i].fen;             
        if (fen.indexOf(curfen) > -1) {
                this.repeatedMoves++;
        }        
			}
		}	
        
     
    if (this.repeatedMoves >= 3) {
            this.gameReason = 'Threefold repetition draw';
            return true;
    } else {
			return false;
		}		
	}	
    ,
    processPGN: function(pgn) {
        if (!pgn) {
			return false;
		}
            
		
        var pgnMovesTxt = pgn.substr(pgn.indexOf('1.'));
        
        var lastIdx;
        if ((lastIdx = pgnMovesTxt.indexOf('1-0') > 0) || (lastIdx = pgnMovesTxt.indexOf('0-1') > 0) || (lastIdx = pgnMovesTxt.indexOf('1\\2') > 0)) {
            pgnMovesTxt = pgnMovesTxt.substr(0, lastIdx - 1);
            //option: get the result also!
        }
        pgnMovesTxt = pgnMovesTxt.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // Trim()
        pgn = pgnMovesTxt;
        
        if (!pgn) {
            return false;
        }
        
        pgnMovesTxt = pgnMovesTxt.replace(/\d+\.+\s+/g, '');
        pgnMovesTxt = pgnMovesTxt.replace(/\d+\.+/g, '');
        
        var pgnMoves = pgnMovesTxt.split(/\s+/);
        
        var TxtSan;
        var SAN;
        var PCMoveNotation;
        var idx;
        var color;
        var promote;
        var capture;
        var pawnMove;
        var pieceMove;
        
        for (var x = 0; x < pgnMoves.length; x++) {
            SAN = pgnMoves[x];

            color = (x + 1) % 2 == 0 ? 'b' : 'w';

            if (!chessHereObj.makeCurrentMove(this.SanToPcMove(SAN,color))) {
                return false; //invalid PGN !!!
            }
        }
        
        return true;
    }
    ,
    processRavPgn: function(pgn) {
    if (!pgn) {return false;}
            
    pgn = pgn.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // Trim()

    var pgnMoves = pgn.split(/\s+/);
		var move;
		var c='w';
		var mode='san';
		var prevMode=mode;
		var comment= '';
		
		var moveIdx;
		var moveNo;
		var parentSanIndex=0;
		var SAN='';
    var lastSAN;
        
      for (var x = 0; x < pgnMoves.length; x++) {
      
      c = chessHereObj.currentMoveTurn;
			
			if (SAN.length>2) lastSAN=SAN;
      SAN = pgnMoves[x];
			
			// comment
			if (SAN == '}') {
				mode=prevMode;
				gameControl.gameStatus[gameControl.currentMoveIndex].comment=comment;
				comment= '';
				continue;
			}			
			
			if (mode == 'comment') {
				comment+= SAN+' ';
				continue;
			}
			
			if (SAN == '{') {				
				prevMode=mode;
				mode='comment';
				continue;
			}
			
			//variant
			if (SAN == '(') {
			gameControl.openVariant();
			continue;
			}			
			if (SAN == ')') {
			gameControl.closeVariant();
			continue;
			}
			if (SAN == ')(') {
			gameControl.closeVariant();
			gameControl.openVariant();
			continue;
			}
			
			//move parsing:
			if (SAN=='..' || SAN=='...') {
				continue;
			}
			
			if (SAN.match(/\d+\./))
			{
				if (!gameControl.enableVariant) {
				
				parentSanIndex = gameControl.gameStatus[gameControl.currentMoveIndex].parentSan;
				
				moveNo = parseInt(SAN);
				
				if (pgnMoves[x + 1] && pgnMoves[x + 1] != '..') {
					moveNo-=0.5;
        }
				
				moveIdx = gameControl.findMoveIndex(moveNo, parentSanIndex);
				
				if (moveIdx) {
      	
				gameControl.goToMove(moveIdx);	
				} else {
        alert(parentSanIndex+' '+lastSAN);
        return true;
        }
				}
				continue;
			}
      			
     	  move =  this.SanToPcMove(SAN,c);
		   //alert('inMove: '+ SAN + ' = '+move);
        if (!chessHereObj.makeCurrentMove(move)) {
        alert('Error parsing move: '+ SAN + ' = '+move);
            return false; //invalid PGN !!!
        }
        if (gameControl.gameStatus[gameControl.currentMoveIndex].parentSan == 0) {
          gameControl.lastMoveIndex = gameControl.currentMoveIndex;
        }
        
      }
        
        return true;
    }
	,
	findMoveIndex : function(m_no,parentSan)
	{
		for (var i = 1; i < gameControl.gameStatus.length; i++) {
			if (!gameControl.gameStatus[i]) { continue; }
			if (gameControl.gameStatus[i].m_no==m_no && gameControl.gameStatus[i].parentSan == parentSan) {
				return i;
			}		
		}		
		return 0;	
	}
	,
	SanToPcMove : function(SAN, color)
	{
        var PCMoveNotation;
        var idx;
        var color;
        var promote;
        var capture;
        var pawnMove;
        var pieceMove;
		
            promote = '';
            capture = false;
            
            //Casteling:	    
            if (SAN.indexOf('O-O-O') > -1 || SAN.indexOf('0-0-0') > -1) {
                if (color == 'w') {
                    PCMoveNotation = '4020';
                }
                else {
                    PCMoveNotation = '4727';
                }
            }
            else 
                if (SAN.indexOf('O-O') > -1 || SAN.indexOf('0-0') > -1) {
                
                    if (color == 'w') {
                        PCMoveNotation = '4060';
                    }
                    else {
                        PCMoveNotation = '4767';
                    }
                }
                else {
                    if (SAN.indexOf('x') > 0) { //Capture:
                        capture = true;
                    }
                    
                    SAN = SAN.replace(/[\#\+x]/gi, '');
                    
                    if ((idx = SAN.indexOf('=')) > 0) { //Promote:
                        if (color == 'w') {
                            promote = SAN.substr(idx + 1, 1).toUpperCase();
                        }
                        else {
                            promote = SAN.substr(idx + 1, 1).toLowerCase();
                        }
                        
                        SAN = SAN.substr(0, idx);
                    }
                    
                    toSquare = SAN.substr(SAN.length - 2, 2); // to square:
                    toNumbers = chessHereObj.notationToCoords(toSquare).toString();
                    
                    pawnMove = SAN.match(/^[abcdefgh]/);
                    pieceMove = SAN.match(/^[BKQNR]/);
                    
                    
                    if (pieceMove) {
                        pieceMoved = pieceMove[0];
                        
                        if (SAN.length == 4) {
                            coordsFrom = SAN.charAt(1);
                            PCMoveNotation = chessHereObj.getPieceFrom(color, pieceMoved, toNumbers, coordsFrom);
                            
                        }
                        else 
                            if (SAN.length == 5) {
                                numFileFrom = SAN.charCodeAt(1) - 97;
                                numRankFrom = SAN.charCodeAt(2) - 97;
                                PCMoveNotation = '' + numFileFrom + numRankFrom + toNumbers;
                            }
                            else {
                                PCMoveNotation = chessHereObj.getPieceFrom(color, pieceMoved, toNumbers);
                            }
                    }
                    else 
                        if (pawnMove) {
                            numFileFrom = SAN.charCodeAt(0) - 97;
                            PCMoveNotation = chessHereObj.getPawnFrom(color, numFileFrom, toNumbers, capture);
                        }
                }
				
				return 	PCMoveNotation + promote;	
	}
	,
	SANArrayToPGN: function(root){
        if (this.ShowMode == 'hidden') { return; }
		
		if (!root) {root=0;}
		
		$('pgnMoves').innerHTML = '';
		
		for (var i = 1; i < this.gameStatus.length; i++) {
			if (!this.gameStatus[i]) { continue; }
			if (this.gameStatus[i].parentSan == root) {
				$('pgnMoves').innerHTML += this.gameStatus[i].render();
				
			}
		}   

    },
	SANArrayToScoreSheet: function(root){
        if (this.ShowMode == 'hidden') { return; }
		
		if (!root) {root=0;}
		
		var tbl = '';
		var no;
		
		var line=0;
		var lines = [];	
		
		for (var i = 1; i < this.gameStatus.length; i++) {
			
			if (!this.gameStatus[i]) { continue; }
			if (this.gameStatus[i].parentSan == root) {
				
				line = this.gameStatus[i].variantLine;					
				if (!lines[line]) { lines[line] = [];}
				lines[line].push(i);
			}
		}		
		
		for (i = 0; i < lines.length; i++) {
			
			if (!lines[i] ) { continue; }
			
			for (j = 0; j < lines[i].length; j++) {
				
				no = this.gameStatus[lines[i][j]].m_no;
				
				if (!no) { continue; }
				
				if (j==0 && root > 0) {
					tbl += '<tr class="startVar"><td colspan="3">Start variant '+ i +'</td></tr>';
				}	
							
				if (j == 0 && no != parseInt(no)) {
					tbl += '<tr class="sanTr"><td class="_no">' + parseInt(no) + '.</td><td>..</td>';
				}
				
				tbl += this.gameStatus[lines[i][j]].renderHtml();
				
			}

			if (no == parseInt(no)) {
					tbl += '<td>&nbsp;</td></tr>';
			}
			if (root > 0) {
				tbl += '<tr class="endVar"><td colspan="3">End variant ' + i + '</td></tr>';
				tbl += '<tr class="sanTr"><td colspan="3">---</td></tr>';
			}
		}
		
		if (tbl != '') { 
		tbl = '<table class="pgnTbl">' + tbl + '</table>'; 
		}
		
		return tbl; 

    }
	,
	playSound : function(s)
	{
		if (!s) {return;}
		try {
		 soundManager.play('s_'+ s);		 
		} catch(e) { }
	}
	,
    moveStepBack: function(){
		if (gameControl.userMadeHisMove) {
			alert('You done your move, please click Move or Reset first');
			return false;
		}
		var _line = gameControl.gameStatus[gameControl.currentMoveIndex].variantLine;
		var _parent	= gameControl.gameStatus[gameControl.currentMoveIndex].parentSan;
		
		for (i=gameControl.currentMoveIndex-1; i > 0 ; i--) {
			if (!gameControl.gameStatus[i]) { continue; }
			if (gameControl.gameStatus[i].variantLine ==_line && gameControl.gameStatus[i].parentSan == _parent) {
				gameControl.goToMove(i);
				return;
			}
			
		}
		
		gameControl.playStop();
    },
    moveStepForward: function(){

		if (gameControl.userMadeHisMove) {
			alert('You done your move, please click Move or Reset first');
			return false;
		}
			
		var _line = gameControl.gameStatus[gameControl.currentMoveIndex].variantLine;
		var _parent	= gameControl.gameStatus[gameControl.currentMoveIndex].parentSan;
		
		for (i=gameControl.currentMoveIndex+1; i < gameControl.gameStatus.length; i++) {
			if (!gameControl.gameStatus[i]) { continue; }
			if (gameControl.gameStatus[i].variantLine ==_line && gameControl.gameStatus[i].parentSan == _parent) {
				gameControl.goToMove(i);
				return;
			}
			
		}
		
		gameControl.playStop();

    }
	,
	playForward : function()
	{
		if (gameControl.userMadeHisMove) {
			alert('You done your move, please click Move or Reset first');
			return false;
		}
		this.playStop();
		
		this.playTimeout = window.setInterval(gameControl.moveStepForward,this.playDelay);
	}
	,
	toStart : function()
	{
		if (gameControl.userMadeHisMove) {
			alert('You done your move, please click Move or Reset first');
			return;
		}
		this.playStop();
		
		gameControl.goToMove(1);
		//this.playTimeout = window.setInterval(gameControl.moveStepBack,this.playDelay);
	}
	,
	playStop: function()
	{
		if (this.playTimeout) { clearTimeout(this.playTimeout); }
	}
	,
    deleteMove : function(){
		if (gameControl.userMadeHisMove) {
			alert('You done your move, please click Move or Reset first');
			return false;
		}	    
		var idx = gameControl.currentMoveIndex;
		if (!gameControl.gameStatus[idx]) { return; }
		
		var _line = gameControl.gameStatus[idx].variantLine;
		var _parent	= gameControl.gameStatus[idx].parentSan;
		
		if (_parent == 0) {return;}		
		
		if (!confirm('Move no '+gameControl.gameStatus[idx].m_no+' and all follow moves will be removed!')) { return; }		
		
		for (i=idx; i < gameControl.gameStatus.length; i++) {
			if (!gameControl.gameStatus[i]) { continue; }
			if (gameControl.gameStatus[i].variantLine ==_line && gameControl.gameStatus[i].parentSan == _parent) {
				gameControl.gameStatus[i]=null;
			}
			
		}
		
		gameControl.goToMove(gameControl.currentMoveIndex-1);

    }
	,
	doVariant : function()
	{
		if (gameControl.userMadeHisMove) {
			alert('You done your move, please click Move or Reset first');
			return false;
		}
		
		if (gameControl.gameStatus.length > 0) {
			gameControl.goToMove(gameControl.lastMoveIndex);
		}
		
		gameControl.boardMode='variant';
		
		chessHereObj.isMoveEnabled = true;
       	chessHereObj.isMasterBoard = true;
       	chessHereObj.isMyTurn = true;
					
		$('playControls').style.display='none';
		$('varsControls').style.display='block';
		
		gameControl.hilightMode();
		
		return true;	

	}
	,
	doPlay : function()
	{
		if (gameControl.isChangesDone && gameControl.boardMode=='variant') {
			if (!confirm('The changes you have made have not been saved yet! (Variants and Comment)')) {
				return false;
			}
		}
				
		if (gameControl.gameStatus.length > 0) {
			gameControl.goToMove(gameControl.lastMoveIndex);
		}
		
		gameControl.boardMode='play';
		
		chessHereObj.isMoveEnabled = true;
       	chessHereObj.isMasterBoard = false;
       	chessHereObj.isMyTurn = gameControl.isItMyTurn;
				
		$('playControls').style.display='block';
		$('varsControls').style.display='none';	
		
		gameControl.hilightMode();
		
		//if (mod) {
		//	$('pgnMoves').innerHTML = gameControl.getPgn();
		//	gameControl.goToMove();
		//}

	}
	,			
	doFree : function()
	{
		if (gameControl.userMadeHisMove) {
			alert('You done your move, please click Move or Reset first');
			return false;
		}
		
		if (gameControl.isChangesDone && gameControl.boardMode=='variant') {
			if (!confirm('The changes you have made have not been saved yet! (Variants and Comment)')) {
				return false;
			}
		}		
		
		gameControl.boardMode='free';
		
		if (gameControl.gameStatus.length > 0) {
			gameControl.goToMove(gameControl.lastMoveIndex);
		}
		
		
		chessHereObj.isMoveEnabled = true;
       	chessHereObj.isMasterBoard = true;
       	chessHereObj.isMyTurn = true;
					
		if ($('playControls')) {
			$('playControls').style.display = 'none';
		}
		if ($('varsControls')) {
			$('varsControls').style.display = 'none';
		}
		gameControl.hilightMode();
		return true;
	}
	,
	hilightMode : function()
	{
		if (!$('top_modes')) {return;}
		c = $('top_modes').getElementsByTagName('INPUT');
		for (i = 0; i < c.length; i++) {
			
			if (c[i].checked) {
				c[i].parentNode.style.background = '#FFAA55';
			} else {
				c[i].parentNode.style.background = '';
			}
		
		}		 
	}
	,
	updatePlayerMove : function(move,san)
	{
		if (!move || move.length < 4) {return;}

		formatted = '';
		
		formatted += (7-move.charAt(1)) +',' + move.charAt(0)+',';
		formatted += (7-move.charAt(3)) +',' + move.charAt(2);
		if (move.length == 5) {
			formatted += ',' + move.charAt(4).toLowerCase();
		}
		
		$('move').value = formatted;
		$('move_txt_id').innerHTML = '&nbsp;&nbsp;' + san + '&nbsp;&nbsp;';
		
		this.userMadeHisMove = true;
		$('submit').disabled = false;
		$('reset').disabled = false;
	}
	,
	resetPlayerMove : function()
	{
		$('move_txt_id').innerHTML = '&nbsp;&nbsp;?&nbsp;&nbsp;';
		$('move').value='';
		$('submit').disabled = true;
		$('reset').disabled = true;
		this.userMadeHisMove = false;
		gameControl.gameStatus[gameControl.currentMoveIndex] = null;
		gameControl.goToMove(gameControl.lastMoveIndex);
		chessHereObj.isMyTurn = gameControl.isItMyTurn;		
	}
	,
	saveChanges : function()
	{
		if (!confirm('All changes will be saved! are you sure?')) { return false; }
		
		$('rav_m').value = gameControl.getPgn();
		$('rav_form').action = window.location.href;
    gameControl.isChangesDone = false;		
		$('rav_form').submit();
	}
	,
	submitMove : function()
	{
		if (!confirm_draw_offer()) {return false;}
		//$('rav_mm').value = gameControl.getPgn();
		return true;
	}
	,
	discardChanges : function()
	{
		if (!gameControl.isChangesDone) {
			return;
		}
		if (!confirm('All changes will be discard! are you sure?')) { return; }
		gameControl.refresh();
	}
	,

	getPgn : function()
	{
		var pgn='';
		for (var i = 1; i < this.gameStatus.length; i++) {
			if (!this.gameStatus[i]) { continue; }
			if (this.gameStatus[i].parentSan == 0) {
				pgn += this.gameStatus[i].render(1);
				
			}
		}
		
		return pgn;		
	}
	,
	refresh : function()
	{
		window.location.href = window.location.href;
	}
	,
	openHelp : function(strUrl,strWindowName)
	{
		window.open(strUrl, strWindowName,"height=580,width=880,left=100;top=100;status=no,toolbar=no,scrollbars=yes,menubar=no,location=no,resizable=yes");
	}
	,
	setWinBg : function() 
	{
		try {
			var d='document.getElementsByTagName("BODY")[0].style.background=';
			var v = chessHereObj.winBg;
			eval(d + v);
		} catch(e) {

		}
		
	}
  
}

function ChessHereMove(currentMoveIndex, parentSanIndex,
		 variantLines, variantLineIndex, 
			fen,move,san,comment,sound,m_no,message)
{
	this.moveIndex=currentMoveIndex;
	this.parentSan=parentSanIndex;
	this.variantLines=variantLines;
	this.variantLine=variantLineIndex;
	
	this.fen=fen;
	this.move=move;
	this.san=san;
	this.comment=comment;
	this.sound=sound;
	this.message=message;
	this.m_no=m_no;
	
}
ChessHereMove.prototype = {
	
render : function(f)
{
	if (!f) {f=0;}
	// render current move - san
	var output = '';
	
	var no = this.m_no;
	
	if (no == parseInt(no)) 
	{
		output += parseInt(no) + '. ';
	}
	
	if (f == 1) {
		output += this.san + ' ';
	}
	else {
	
		if (gameControl.currentMoveIndex == this.moveIndex) {
			output += '<b class="currentSan">' + this.san + '</b> ';
		}
		else {
			output += '<b onclick="gameControl.goToMove(' + this.moveIndex + ')">' + this.san + '</b> ';
		}
	}
	
	if (this.comment != '')
	{
		output += '{ ' + this.comment + ' } ';
	}
	
	
	// render childs:
	var childs = '';
	var line=0;
	var prevLine;
	var lines=0;
	var firstChild = true;
	
	
	for (var i = 1; i < gameControl.gameStatus.length; i++) {
		if (!gameControl.gameStatus[i]) { continue; }
		
		if (gameControl.gameStatus[i].parentSan == this.moveIndex && i != this.moveIndex) {

		  prevLine = line;
		  line = gameControl.gameStatus[i].variantLine;
    		
			no = gameControl.gameStatus[i].m_no;
			
			if (firstChild) {
			if (no != parseInt(no)) {
				childs += parseInt(no) + '. .. ';
			} else {
				childs += ' .. ';
			}				
			} else if (line != prevLine && line > 1) {
				
				childs += ') ( ';

			if (no != parseInt(no)) {
				childs += parseInt(no) + '. .. ';
			} else {
				childs += ' .. ';
			}
							
			}
			
			childs += gameControl.gameStatus[i].render(f);
			
			firstChild = false;
		}
	
	}
	
		if (childs != '') {
			output += '( ' + childs + ') ';
		}	

			
	return output;
	
}
,
renderHtml : function()
{
	// render current move - san
	var output = '';
	
	var no = this.m_no;
	
	var haveChilds='';
	
	for (var i = 1; i < gameControl.gameStatus.length; i++) {
		if (!gameControl.gameStatus[i]) { continue; }
		if (gameControl.gameStatus[i].parentSan == this.moveIndex && i != this.moveIndex) {
		    haveChilds=' withChilds';
			break;
		}
		
	}	
		
	if (no == parseInt(no)) 
	{
		output += '<tr class="sanTr"><td class="_no">' + parseInt(no) + '.</td>';
	}
	
	if (gameControl.currentMoveIndex == this.moveIndex) {
		output += '<td id="currentSanTd" class="' + haveChilds +'"><b class="currentSan">' + this.san + '</b></td>';
	} else {
		output += '<td class="' + haveChilds +'"><b onclick="gameControl.goToMove(' + this.moveIndex + ')">' + this.san + '</b></td>';
	} 
	
	if (no != parseInt(no)) 
	{
		output += '</tr>';
	}		
	return output;
	}
}
// EO game controler


