//------------------------------------------------------------------------------------------
// (c) iBoard/netAdapt Ltd.
//------------------------------------------------------------------------------------------
function CPgnControl(tileSize, setStyle, boardStyle)
{
    this.m_instanceId = Math.floor(Math.random() * 999999);
    this.m_isInAnimationPause = false;    
    this.m_moveIndex = 0;
    this.m_renderBoardCallBack = 0;
    this.m_movesArray = new Array;
    this.m_tileSize = tileSize;
    this.m_setStyle = setStyle;
    this.m_boardStyle = boardStyle;
    this.m_isInverted = false;
    this.m_isPgnVisibleAtRender = false;
    this.m_isHeaderVisibleAtRender = false;
    this.m_isCommentsVisibleAtRender = true;
    this.m_isStartGameLink = false;
    this.m_pgnArray = new Array;
    this.m_isMaterialCapturedShown = true;
    this.m_isIntegratedNavControlsShown = true;
    this.m_isCommentsEnabled = true;
    this.m_isQuickNavLinks = true;
    this.m_lastMarkedMoveIndex = false;
    this.RenderControl = RenderControl;
    this.RenderBoardContent = RenderBoardContent;
    this.SetHeadersArray = SetHeadersArray;    
    this.SetMoveIndex = SetMoveIndex;
    this.GetLastMoveIndex = GetLastMoveIndex;
    this.GetInstanceId = GetInstanceId;
    this.GoToFirstMove = GoToFirstMove;
    this.GoToLastMove = GoToLastMove;
    this.GoToPreviousMove = GoToPreviousMove;
    this.GoToNextMove = GoToNextMove;
    this.GoToMove = GoToMove;
    this.InvertBoard = InvertBoard;
    this.StartGame = StartGame;   
    this.SetPgnMove = function ( moveIndex, pgnMove )
    {
    	this.m_movesArray[ moveIndex ] =  pgnMove;
	} 
	this.GetPgnMove = function ( moveIndex )
    {
    	return this.m_movesArray[ moveIndex ];
	} 
	this.CountPgnMoves = function ( )
	{
		return this.m_movesArray.length;
	}
    this.SetIsPgnVisibleAtRender = function ( isPgnVisibleAtRender )
	{
	    this.m_isPgnVisibleAtRender = isPgnVisibleAtRender;
	}
    this.SetIsHeadersVisibleAtRender = function( isHeaderVisibleAtRender )
    {
    	this.m_isHeaderVisibleAtRender = isHeaderVisibleAtRender;        
	}
    this.SetIsCommentsVisibleAtRender = function ( isCommentsVisibleAtRender ) 
    {
    	this.m_isCommentsVisibleAtRender = isCommentsVisibleAtRender;
	}
	this.SetIsQuickNavLinks  = function ( isQuickNavLinks )
	{
		this.m_isQuickNavLinks = isQuickNavLinks;
	}
    this.SetPgnArray = SetPgnArray;
    this.TogglePgn = TogglePgn;
    this.ToggleHeaders = ToggleHeaders;
    this.ToggleComment = ToggleComment;
    this.RenderNavControl = RenderNavControl;
    this.RenderSpecialControl = RenderSpecialControl;
    this.SetIsStartGameLink = SetIsStartGameLink;
    this.SetIsMaterialCapturedShown = function (isMaterialCapturedShown)
    {
        this.m_isMaterialCapturedShown = isMaterialCapturedShown;
    }    
    this.GetCapturedContentDiv = GetCapturedContentDiv;
    this.m_capturedBarPcSizePx = 22;
    this.m_capturedBarXOffset = 0;
    this.m_capturedBarYOffset = 0;
    this.m_isPlayOnRender = false;
    this.AddCapturedPieces = AddCapturedPieces;
    this.NextAnimation = NextAnimation;
    this.AnimatePieceMove = AnimatePieceMove;
    this.IsAnimationFinished = IsAnimationFinished;
    this.StartPlayAnimation = StartPlayAnimation;
    this.StopPlayAnimation = StopPlayAnimation;
    this.m_currentAnimatedPcEl = null;
    this.StopAnimation = StopAnimation;
    this.ProgressMoveIndex = ProgressMoveIndex;
    this.MarkMoveCell = MarkMoveCell; 
    this.GetMoveCellEl = GetMoveCellEl;
    this.GetMoveCellColor  = function ( moveIndex ) 
    {
    	return (this.IsComment( moveIndex )?'#FDF1AC':'#FFF');
	}
    this.GetBoardContainerHeight= function( )
    {
    	return (this.m_tileSize * 8 + 14);
	}
    this.IsMicroBoard = function ()
    {
        return this.m_tileSize < 44;
    }
    this.SetBoardRenderCallBack = function (boardRenderCallBack)
    {    	
    	this.m_renderBoardCallBack = boardRenderCallBack;
	}
	this.GetMoveIndex = function ( ) 
	{
		return this.m_moveIndex;
	}
	this.GetAlgebraicMoveStr = function ( moveIndex )
	{		
		return this.m_movesArray[moveIndex].GetAlgebraicMoveStr( );
	}
	this.SetIsIntegratedNavControlsShown = function ( isIntegratedNavControlsShown )
	{
	 	this.m_isIntegratedNavControlsShown = isIntegratedNavControlsShown;	 	
	}
	this.IsInAnimationPause = function ( )
	{
		return this.m_isInAnimationPause;
	}
	this.SetIsInAnimationPause = function ( isInAnimationPause )
	{
		this.m_isInAnimationPause = isInAnimationPause;
	}
	this.IsComment = function( moveIndex ) 
	{
		return (this.m_movesArray[moveIndex].GetAnnotationComment( ) != '');
	}
	this.GetComment = function ( moveIndex )
	{
		return this.m_movesArray[moveIndex].GetAnnotationSymbol( ) + ' ' + this.m_movesArray[moveIndex].GetAnnotationComment( );	
	}
	this.IsCommentsEnabled = function ( )
	{
		return this.m_isCommentsEnabled;
	}
	this.SetIsCommentsEnabled = function ( isCommentsEnabled )
	{
	 	this.m_isCommentsEnabled = isCommentsEnabled;
	}
}

function GetMoveCellEl( moveIndex )
{
	var moveCellId =  'moveCellId' + this.GetInstanceId() + '_' + moveIndex;
	return 	document.getElementById(  moveCellId );
}

function MarkMoveCell( moveIndex )
{
	if ( this.m_lastMarkedMoveIndex )
	{
		this.GetMoveCellEl( this.m_lastMarkedMoveIndex ).style.background = this.GetMoveCellColor( this.m_lastMarkedMoveIndex );		
	}
	
	var moveCell =  this.GetMoveCellEl( moveIndex );
	if ( moveCell )
	{		
		moveCell.style.background = '#D1F78C';		
		var topPos = moveCell.offsetTop; 			
		var quickNavEl = 	document.getElementById('quickNavDivId' + this.GetInstanceId( )); 				
		if ( this.m_lastMarkedMoveIndex+1 == moveIndex && topPos > this.GetBoardContainerHeight( )-28)
		{			
			quickNavEl.scrollTop = topPos - (this.GetBoardContainerHeight( )-28);		
		}			
		this.m_lastMarkedMoveIndex = moveIndex;	
	}
	if ( moveIndex == 0 && 	document.getElementById('quickNavDivId' + this.GetInstanceId( )))
	{
		document.getElementById('quickNavDivId' + this.GetInstanceId( )).scrollTop = topPos; 
	}
}

function GetInstanceId()
{
    return this.m_instanceId;
}

function SetHeadersArray(headersArray)
{
    this.m_headersArray = headersArray;
}

function SetMoveIndex(moveIndex)
{
    this.m_moveIndex = moveIndex;
}

function SetPgnArray(pgnArray)
{
    this.m_pgnArray = pgnArray;
}

function RenderControl(instanceName)
{
    var isPgn = this.m_pgnArray.length > 0;
    if (this.IsMicroBoard())
    {
        this.m_isMaterialCapturedShown = false;
    }
    InitMiniBoard(this.m_tileSize, this.m_setStyle, this.m_boardStyle);
    document.write("<div id=\"pgnBrowserDivId" + this.GetInstanceId() + "\" style=\"text-align:left;width:" + (this.GetBoardContainerHeight( ) + (this.m_isQuickNavLinks?160:0)) + "px;background:#FFF;padding:4px;margin:4px;border:solid 1px #CCC\" align=\"center;\">");
    
    document.write("<div id=\"headersDivId" + this.GetInstanceId() + "\" style=\"display:" + (this.m_isHeaderVisibleAtRender ? "block" : "none") + ";\">");
    document.write("<table width=\"100%\">");
    var n = 0;
    for (key in this.m_headersArray)
    {
        document.write("<tr><td style=\"border-bottom:dashed 1px #CCC;border-right:solid 1px #CCC;font-family:helvetica;font-size:11px;\" valign=\"top\">" + key + "</td><td style=\"font-size:11px;border-bottom:dashed 1px #CCC\">" + this.m_headersArray[key] + "&nbsp;</td></tr>");
    }
    document.write("</table>");
    document.write("</div>");
    
    
    if ( this.m_isQuickNavLinks )
    {
    	document.write('<div id="quickNavDivId' + this.GetInstanceId() + '" style="float:right;width:160px;background:#FDFDFD;height:' + this.GetBoardContainerHeight( ) + 'px;overflow:auto;">');
    	document.write('<table style="color:#666;border:solid 1px #CCC;margin-left:3px;width:136px;">');
    	var n = 0;
    	for (n=1;n<this.CountPgnMoves( );n++)
    	{
    		if ( n%2!=0)
    		{
    			document.write('<tr><td style="width:22px;text-align:right;border:solid 1px #EEE;font-weight:bold;">' + Math.ceil(n/2)  + '.</td>'); //open row
			}			
			document.write('<td id="moveCellId' + this.GetInstanceId() + '_' + n + '"  style="width:38px;padding:2px;text-align:center;cursor:pointer;border:solid 1px #888;background:' + (this.GetMoveCellColor( n ) )  +  '" onclick="' +  instanceName + '.GoToMove(' + n + ')">' + this.GetPgnMove( n ).GetAlgebraicMoveStr( ) + '</td>');
			if ( n%2==0)
    		{
    			document.write('</tr>'); //close row
			}
		}
		if ( this.CountPgnMoves( ) > 0 && n%2==0) 
		{
			document.write('<td></td></tr>'); //close off final row
		}
		document.write('</table>');
    	document.write('</div>');
	}
    

    document.write("<div id=\"boardDivId" + this.GetInstanceId() + "\"></div>");
    document.getElementById("boardDivId" + this.GetInstanceId()).innerHTML = GetVacantMiniBoardCode(this.GetInstanceId());
    if ( ! this.m_isQuickNavLinks )
    {
    	document.write("<div id=\"moveDivId" + this.GetInstanceId() + "\"  align=\"center\" style=\"margin-top:2px;border:solid 1px #888;padding:4px;font-size:13px;font-weight:bold\"></div>");
	}    
    
    if ( this.IsCommentsEnabled( ) )
    {
    	document.write("<div id=\"commentsDivId" + this.GetInstanceId() + "\" style=\"overflow : auto;display:" + (this.m_isCommentsVisibleAtRender ? "block" : "none") + ";margin-top:2px;margin-bottom:4px;padding:4px;position:relative;height:64px;background:#FAFAFA;border:solid 1px #888;\"></div>");
	}    
        
   
    if ( this.m_isIntegratedNavControlsShown )
    {
	    document.write("<div id=\"navControlsDivId" + this.GetInstanceId() + "\" style=\"margin-top:2px;padding-top:8px;padding-bottom:8px;background:#DEDEDE;border:solid 1px #888;\" align=\"center\">");
	    this.RenderNavControl(instanceName, this.IsMicroBoard() ? "&laquo;" : "&laquo; First",
	    "GoToFirstMove( )");
	    this.RenderNavControl(instanceName, "&lt; Prev", "GoToPreviousMove( )");
	    this.RenderNavControl(instanceName, "Play", "StartPlayAnimation( )");
	    this.RenderNavControl(instanceName, "Next &gt;", "GoToNextMove( )");
	    this.RenderNavControl(instanceName, this.IsMicroBoard() ? "&raquo;" : "Last &raquo;", "GoToLastMove( )");
	    document.write("</div>");
	}
	
	if (this.m_isMaterialCapturedShown)
    {
        var captureElementsStr = "";
        captureElementsStr += "<div style=\"margin-top:2px;padding:4px;position:relative;height:56px;background:#DEDEDE;border:solid 1px #888;\">";
        captureElementsStr += "<div id=\"materialDiffScoreId" + this.GetInstanceId() + "\" style=\"float:right;height:" + ValInPx(this.m_capturedBarPcSizePx * 2) + ";padding-top:" + ValInPx(this.m_capturedBarPcSizePx - 3) + ";\"></div>";
        captureElementsStr += "<div id=\"capturedMaterial" + this.GetInstanceId() + "\" style=\"position:absolute;margin-top:2px;padding:2px;height:50px;\">&nbsp;</div>";
        captureElementsStr += "</div>";
        document.write(captureElementsStr);
    } 
    
    document.write("<div id=\"specialControlsDivId" + this.GetInstanceId() + "\" style=\"padding:8px;\" align=\"center\">");
    this.RenderSpecialControl(instanceName, "Invert Board", "InvertBoard( )");
    if (isPgn)
    {
        this.RenderSpecialControl(instanceName, "PGN", "TogglePgn( )");
    }
    this.RenderSpecialControl(instanceName, "Headers", "ToggleHeaders( )");
    if (this.m_isStartGameLink)
    {
        this.RenderSpecialControl(instanceName, "Start Game", "StartGame( )");
    }
    if (this.IsCommentsEnabled( ))
    {
        this.RenderSpecialControl(instanceName, "Comments", "ToggleComment( )");
    }
    document.write("</div>");
    
    if (isPgn)
    {
        document.write("<div id=\"pgnDivId" + this.GetInstanceId() + "\" style=\"display:" + (this.m_isPgnVisibleAtRender ? "block" : "none") + ";padding:4px;border:solid 1px #FFD735;background:#FFF1BB;font-family:Courier New,Courier;font-size:11px;height:80px;overflow-x: hidden; overflow-y: scroll;\">");
        var n = 0;
        for (var n = 0; n < this.m_pgnArray.length; n++)
        {
            document.write(this.m_pgnArray[n] + "<br>");
        }
        document.write("</div>");
    }
    
    document.write("</div>");
    this.RenderBoardContent();
}

function RenderNavControl(instanceName, label, action)
{
    document.write("<input type=\"button\" value=\"" + label + "\"   onclick=\"" + instanceName + "." + action + ";return false;\" style=\"cursor:pointer;background:#FDFDFD;border:solid 1px #AAA;margin:1px;padding:" +  (this.m_tileSize/8) + "px\">");
}

function RenderSpecialControl(instanceName, label, action)
{
    document.write("<span style=\"margin-top:2px;padding:2px;\"><a style=\"color:#000\" href=\"#\" onclick=\"" + instanceName + "." + action + ";return false;\">" + label + "</a></span>");
}

function SetIsHeadersVisibleAtRender(isHeaderVisibleAtRender)
{
    this.m_isHeaderVisibleAtRender = isHeaderVisibleAtRender;
}

function SetIsStartGameLink(isStartGameLink)
{
    this.m_isStartGameLink = isStartGameLink;
}

function IsAnimationFinished()
{
    return this.m_moveIndex >= this.GetLastMoveIndex();
}

function StartPlayAnimation()
{
    this.StopAnimation( );
    if (this.m_moveIndex == this.GetLastMoveIndex())
    {
        this.GoToFirstMove();
    }
    this.NextAnimation(true);
}

function StopPlayAnimation( )
{	
	this.StopAnimation( ); 	
}         

function ProgressMoveIndex( )
{
 	this.m_moveIndex++;	
}

function NextAnimation(isFirstAnimationP)
{
    var isFirstAnimation = isFirstAnimationP || false;
    if (!this.IsAnimationFinished())
    {
        this.RenderBoardContent();                
        var rawMove =  this.m_movesArray[this.m_moveIndex+1].GetRawMove( );
         
        var srcX = rawMove.charAt(0);
        var srcY = rawMove.charAt(1);
        var tgtX = rawMove.charAt(2);
        var tgtY = rawMove.charAt(3);
        var pcEl = GetPcEl(this.GetInstanceId(), srcX, srcY);
        pcEl.m_owner = this;
        if (pcEl)
        {
            pcEl.m_numPauseIterations = isFirstAnimation ? 0 : 90;
            pcEl.m_pauseIterationsIndex = 0;
            this.AnimatePieceMove(pcEl, srcX, srcY, tgtX, tgtY);
        }
    }
}

function AnimatePieceMove(pcEl, srcX, srcY, tgtX, tgtY)
{
    srcX = CorrectBoardPos(srcX, this.m_isInverted);
    srcY = CorrectBoardPos(srcY, this.m_isInverted);
    tgtX = CorrectBoardPos(tgtX, this.m_isInverted);
    tgtY = CorrectBoardPos(tgtY, this.m_isInverted);
    pcEl.m_animStepsMax = 50;
    pcEl.m_animStepIndex = 0;
    var xDiff = tgtX - srcX;
    var yDiff = tgtY - srcY;
    var xDiffPx = this.m_tileSize * xDiff;
    var yDiffPx = this.m_tileSize * yDiff;
    pcEl.m_xSrcPx = this.m_tileSize * srcX;
    pcEl.m_ySrcPx = this.m_tileSize * srcY;
    pcEl.m_xStepPx = xDiffPx / (pcEl.m_animStepsMax + 1);
    pcEl.m_yStepPx = yDiffPx / (pcEl.m_animStepsMax + 1);
    pcEl.style.zIndex = 250;
    pcEl.m_previousZindex = pcEl.style.zIndex;
    this.m_currentAnimatedPcEl = pcEl;
    g_animationManager.AddAnimatedEl(pcEl.id, pcEl);
}

function StopAnimation()
{
    if (this.m_currentAnimatedPcEl)
    {
        g_animationManager.RemoveAnimatedEl(this.m_currentAnimatedPcEl.id);
        this.m_currentAnimatedPcEl = null;
        this.RenderBoardContent();
    }
}

function GetLastMoveIndex()
{
    return this.m_movesArray.length - 1;
}

function GoToFirstMove()
{
    this.StopAnimation();
    this.m_moveIndex = 0;
    this.RenderBoardContent();
}

function GoToLastMove()
{
    this.StopAnimation();
    this.m_moveIndex = this.GetLastMoveIndex();
    this.RenderBoardContent();
}

function GoToPreviousMove()
{
    this.StopAnimation();
    if (this.m_moveIndex > 0)
    {
        this.m_moveIndex--;
    }
    this.RenderBoardContent();
}

function GoToNextMove()
{
    this.StopAnimation();
    if (this.m_moveIndex < this.m_movesArray.length - 1)
    {
        this.m_moveIndex++;
    }
    this.RenderBoardContent();
}

function GoToMove( newMoveId )
{
	this.StopAnimation();	
	if (newMoveId > 0 && newMoveId < this.m_movesArray.length )
    {
        this.m_moveIndex = newMoveId;
    }
	this.RenderBoardContent();	
}

function InvertBoard()
{
    this.m_isInverted = !this.m_isInverted;
    this.RenderBoardContent();
}

function TogglePgn()
{
    ToggleBlock("pgnDivId" + this.GetInstanceId());
}

function ToggleHeaders()
{
    ToggleBlock("headersDivId" + this.GetInstanceId());
}

function ToggleComment( )
{
	ToggleBlock("commentsDivId" + this.GetInstanceId());
}

function RenderBoardContent()
{     
    var rawMove = null;
    var pgnMove = this.m_movesArray[this.m_moveIndex];
    if (this.m_movesArray.length > 0)
    {
        rawMove = pgnMove.GetRawMove( );
    }    
    g_pcSize = this.m_tileSize;
    g_pcSet = this.m_setStyle;
    g_board = this.m_boardStyle;
    PopulateMiniBoard(this.GetInstanceId(), pgnMove.GetFen( ), this.m_isInverted, rawMove);
    if ( moveDivEl = document.getElementById("moveDivId" + this.GetInstanceId()))
    {
    	moveDivEl.innerHTML = pgnMove.GetAlgebraicMoveStr( );
	}
    if (this.m_isMaterialCapturedShown)
    {
        var fenReport = new CFenReport( pgnMove.GetFen( ));
        var capturedMaterialDiv = document.getElementById("capturedMaterial" + this.GetInstanceId());
        capturedMaterialDiv.innerHTML = "";
        capturedMaterialDiv.appendChild(this.GetCapturedContentDiv(fenReport));
        var diffScore = fenReport.GetMaterialDifferenceScore();
        document.getElementById("materialDiffScoreId" + this.GetInstanceId()).innerHTML = diffScore > 0 ? "+" + diffScore : diffScore;
    }
    if ( document.getElementById("commentsDivId" + this.GetInstanceId( )))
    {
    	document.getElementById("commentsDivId" + this.GetInstanceId( )).innerHTML = this.GetComment( this.m_moveIndex );
	}
    
    this.MarkMoveCell( this.m_moveIndex );
    
    if ( this.m_renderBoardCallBack )
    {
    	this.m_renderBoardCallBack( this );
	}
}

function GetCapturedContentDiv(fenReport)
{
    var capturedContentDiv = CreateElement("div");
    this.m_capturedBarXOffset = 0;
    this.m_capturedBarYOffset = 0;
    this.AddCapturedPieces(capturedContentDiv, "Q", 1 - fenReport.GetTotalWhiteQueens());
    this.AddCapturedPieces(capturedContentDiv, "R", 2 - fenReport.GetTotalWhiteRooks());
    this.AddCapturedPieces(capturedContentDiv, "B", 2 - fenReport.GetTotalWhiteBishops());
    this.AddCapturedPieces(capturedContentDiv, "N", 2 - fenReport.GetTotalWhiteKnights());
    this.AddCapturedPieces(capturedContentDiv, "P", 8 - fenReport.GetTotalWhitePawns());
    this.m_capturedBarXOffset = 0;
    this.m_capturedBarYOffset = 1;
    this.AddCapturedPieces(capturedContentDiv, "q", 1 - fenReport.GetTotalBlackQueens());
    this.AddCapturedPieces(capturedContentDiv, "r", 2 - fenReport.GetTotalBlackRooks());
    this.AddCapturedPieces(capturedContentDiv, "b", 2 - fenReport.GetTotalBlackBishops());
    this.AddCapturedPieces(capturedContentDiv, "n", 2 - fenReport.GetTotalBlackKnights());
    this.AddCapturedPieces(capturedContentDiv, "p", 8 - fenReport.GetTotalBlackPawns());
    return capturedContentDiv;
}

function AddCapturedPieces(parentEl, pcChar, num)
{
    var i;
    for (i = 0; i < num; i++)
    {
        parentEl.appendChild(CreatePcEl(this.GetInstanceId(), g_pcSet, this.m_capturedBarPcSizePx, pcChar, this.m_capturedBarXOffset++, this.m_capturedBarYOffset), false);
    }
}

function StartGame()
{
    window.location = "/core/newgame.php?setpiecefen=" + escape( this.m_movesArray[this.m_moveIndex].GetFen( ));
}

//------------------------------------------------------------------------------------------
// pgnMove
//------------------------------------------------------------------------------------------
function CPgnMove( fen, algebraicMove, rawMove, annotationSysmbol, annotationComment ) 
{	
    this.m_fen = fen;
    this.m_algebraicMove = algebraicMove;
    this.m_rawMove = rawMove;
    this.m_annotationSysmbol = annotationSysmbol;
    this.m_annotationComment = annotationComment;	
    
    this.GetFen = function( )
    {
    	return this.m_fen;
	}	
	
	this.GetAlgebraicMoveStr = function( )
	{
		return this.m_algebraicMove;
	}
	
	this.GetRawMove = function( )
	{
		return this.m_rawMove;
	}
	
	this.GetAnnotationSymbol = function( )
	{
		return this.m_annotationSysmbol;
	}
	
	this.GetAnnotationComment = function( )
	{
		return this.m_annotationComment;
	}
}

//------------------------------------------------------------------------------------------
// fenReport
//------------------------------------------------------------------------------------------

function CFenReport(fen)
{
    this.m_fen = fen;
    this.m_fenCursor = 0;
    this.m_totalWhite = 0;
    this.m_totalBlack = 0;
    this.m_totalWhitePawns = 0;
    this.m_totalBlackPawns = 0;
    this.m_totalWhiteKnights = 0;
    this.m_totalBlackKnights = 0;
    this.m_totalWhiteBishops = 0;
    this.m_totalBlackBishops = 0;
    this.m_totalWhiteRooks = 0;
    this.m_totalBlackRooks = 0;
    this.m_totalWhiteQueens = 0;
    this.m_totalBlackQueens = 0;
    this.m_totalWhiteKings = 0;
    this.m_totalBlackKings = 0;
    this.m_totalUnknown = 0;
    this.AnalyseFen = AnalyseFen;
    this.GetFenBoardToken = GetFenBoardToken;
    this.GetTotalWhitePawns = function ()
    {
        return this.m_totalWhitePawns;
    };
    this.GetTotalWhiteKnights = function ()
    {
        return this.m_totalWhiteKnights;
    };
    this.GetTotalWhiteBishops = function ()
    {
        return this.m_totalWhiteBishops;
    };
    this.GetTotalWhiteRooks = function ()
    {
        return this.m_totalWhiteRooks;
    };
    this.GetTotalWhiteQueens = function ()
    {
        return this.m_totalWhiteQueens;
    };
    this.GetTotalWhiteKings = function ()
    {
        return this.m_totalWhiteKings;
    };
    this.GetTotalWhite = function ()
    {
        return this.m_totalWhite;
    };
    this.GetTotalBlackPawns = function ()
    {
        return this.m_totalBlackPawns;
    };
    this.GetTotalBlackKnights = function ()
    {
        return this.m_totalBlackKnights;
    };
    this.GetTotalBlackBishops = function ()
    {
        return this.m_totalBlackBishops;
    };
    this.GetTotalBlackRooks = function ()
    {
        return this.m_totalBlackRooks;
    };
    this.GetTotalBlackQueens = function ()
    {
        return this.m_totalBlackQueens;
    };
    this.GetTotalBlackKings = function ()
    {
        return this.m_totalBlackKings;
    };
    this.GetTotalBlack = function ()
    {
        return this.m_totalBlack;
    };
    this.GetTotalPieces = function ()
    {
        return this.GetTotalWhite() + this.GetTotalBlack();
    };
    this.GetTotalKings = function ()
    {
        return this.GetTotalBlackKings() + this.GetTotalWhiteKings();
    };
    this.GetScoreWhiteCapturedMaterial = GetScoreWhiteCapturedMaterial;
    this.GetScoreBlackCapturedMaterial = GetScoreBlackCapturedMaterial;
    this.GetScoreFromPiecesOnBoard = GetScoreFromPiecesOnBoard;
    this.GetMaterialDifferenceScore = GetMaterialDifferenceScore;
    this.AnalyseFen();
}

function SetFen(fen)
{
    this.m_fen = fen;
}

function AnalyseFen()
{
    while ((fenChar = this.GetFenBoardToken()))
    {
        switch (fenChar)
        {
        case "P":
            this.m_totalWhitePawns++;
            break;
        case "p":
            this.m_totalBlackPawns++;
            break;
        case "N":
            this.m_totalWhiteKnights++;
            break;
        case "n":
            this.m_totalBlackKnights++;
            break;
        case "B":
            this.m_totalWhiteBishops++;
            break;
        case "b":
            this.m_totalBlackBishops++;
            break;
        case "R":
            this.m_totalWhiteRooks++;
            break;
        case "r":
            this.m_totalBlackRooks++;
            break;
        case "Q":
            this.m_totalWhiteQueens++;
            break;
        case "q":
            this.m_totalBlackQueens++;
            break;
        case "K":
            this.m_totalWhiteKings++;
            break;
        case "k":
            this.m_totalBlackKings++;
            break;
        default:
            this.m_totalUnknown++;
        }
    }
    this.m_totalWhite = this.m_totalWhitePawns + this.m_totalWhiteKnights + this.m_totalWhiteBishops + this.m_totalWhiteRooks + this.m_totalWhiteQueens + this.m_totalWhiteKings;
    this.m_totalBlack = this.m_totalBlackPawns + this.m_totalBlackKnights + this.m_totalBlackBishops + this.m_totalBlackRooks + this.m_totalBlackQueens + this.m_totalBlackKings;
}

function GetScoreWhiteCapturedMaterial()
{
    return this.GetScoreFromPiecesOnBoard(this.m_totalWhitePawns, this.m_totalWhiteKnights, this.m_totalWhiteBishops, this.m_totalWhiteRooks, this.m_totalWhiteQueens);
}

function GetScoreBlackCapturedMaterial()
{
    return this.GetScoreFromPiecesOnBoard(this.m_totalBlackPawns, this.m_totalBlackKnights, this.m_totalBlackBishops, this.m_totalBlackRooks, this.m_totalBlackQueens);
}

function GetScoreFromPiecesOnBoard(pawns, knights, bishops, rooks, queens)
{
    return (8 - pawns) * 1 + (2 - knights) * 3 + (2 - bishops) * 3 + (2 - rooks) * 5 + (1 - queens) * 9;
}

function GetMaterialDifferenceScore()
{
    return this.GetScoreBlackCapturedMaterial() - this.GetScoreWhiteCapturedMaterial();
}

function IsErrorInFen()
{
    return this.m_totalUnknown > 0;
}

function GetFenBoardToken()
{
    if (this.m_fenCursor > this.m_fen.length || this.m_fen.charAt(this.m_fenCursor) == " ")
    {
        return false;
    }
    return this.m_fen.charAt(this.m_fenCursor++);
}

function ProcessAnimationQueue()
{
    g_animationManager.AnimateAll();
}

function CAnimationManager(intervalTime)
{
    this.m_intervalTime = intervalTime || 12;
    this.m_animatedElArray = new Array;
    this.IsAnimatedEl = IsAnimatedEl;
    this.AddAnimatedEl = AddAnimatedEl;
    this.GetAnimatedEl = GetAnimatedEl;
    this.m_timerId = 0;
    this.SetTimerId = function (timerId)
    {
        this.m_timerId = timerId;
    };
    this.GetTimerId = function ()
    {
        return this.m_timerId;
    };
    this.RemoveAnimatedEl = RemoveAnimatedEl;
    this.AnimateAll = AnimateAll;
    this.SetTimerId(setInterval("ProcessAnimationQueue()", this.m_intervalTime));
}

function AddAnimatedEl(elId, el)
{
    this.m_animatedElArray[elId] = el;
}

function IsAnimatedEl(elId)
{
    if (this.m_animatedElArray[elId])
    {
        return true;
    }
    return false;
}

function RemoveAnimatedEl(elId)
{
    if (this.IsAnimatedEl(elId))
    {
        delete this.m_animatedElArray[elId];
    }
}

function GetAnimatedEl(elId)
{
    return this.m_animatedElArray[elId];
}

function AnimateAll()
{
    for (key in this.m_animatedElArray)
    {
        if (this.IsAnimatedEl(key))
        {
            var el = this.GetAnimatedEl(key);
            if (el.m_pauseIterationsIndex > el.m_numPauseIterations)
            {
                var xTransPx = el.m_xSrcPx + el.m_animStepIndex * el.m_xStepPx;
                var yTransPx = el.m_ySrcPx + el.m_animStepIndex * el.m_yStepPx;
                SetElPos(el, parseInt(xTransPx), parseInt(yTransPx));
                if (el.m_animStepIndex > el.m_animStepsMax)
                {
                    el.style.zIndex = el.m_previousZindex;
                    this.RemoveAnimatedEl(key);
                    el.m_owner.ProgressMoveIndex( );                
                    if (!el.m_owner.IsAnimationFinished())
                    {
                        el.m_owner.NextAnimation();
                    }
                    else
                    {
                        el.m_owner.StopAnimation();
                    }                     
                }
                el.m_animStepIndex++; 
                el.m_owner.SetIsInAnimationPause( false );
            }
            else
            {
                el.m_pauseIterationsIndex++;
                el.m_owner.SetIsInAnimationPause( true );
            }
        }
    }
}
var g_animationManager = new CAnimationManager;
