function getElement( id )
{
	if( document.getElementById ) return document.getElementById( id );
	else return document.all[ id ];
}

function animate( it, eased )
{
	var dgrm = getElement( 'diagram' );
	var probs = new Array( NUM_STATES );
		
	//if( animationInterval ) window.clearInterval( animationInterval );
	
	for( var i = 0; i < NUM_SEGMENTS; i++ )
	{
		var sgmnt = getElement( 'segment' + i );
		
		if( it < 0 ) 
		{
			CURRENT_IT = 0;
			it = 0;
		}
		if( it >= NUM_ITERATIONS ) 
		{
			CURRENT_IT = NUM_ITERATIONS - 1;
			it = NUM_ITERATIONS - 1;
		}
		
		for( var j = 0; j < NUM_STATES; j++ )
		{
			probs[j] = emissions[ it ][ ( NUM_SEGMENTS * j ) + i ];
		}
		
		// Calculate the coordinates from the probabilities
		var coords = getCoords( probs );
		
		// Move the segment
		startPos = [ parseInt( sgmnt.style.left ), parseInt( sgmnt.style.top ) ];
		endPos = [ ( parseInt( dgrm.style.width )/2 + coords[0] ), ( parseInt( dgrm.style.height )/2 - coords[1] ) ];
			
		if( eased ) doPosChangeMem( sgmnt, startPos, endPos, 100, 10, 0.5 );
		else
		{
			sgmnt.style.left = ( parseInt( dgrm.style.width )/2 + coords[0] ) + 'px';
			sgmnt.style.top = ( parseInt( dgrm.style.height )/2 - coords[1] ) + 'px';
		}
	}	
	
	document.show.iteration.value = CURRENT_IT + 1 + "/" + NUM_ITERATIONS;
}

function animateFromForm()
{
	animate( parseInt( document.show.iteration.value - 1 ), eased );
	return false;
}

function animateSeries( begin, end, step )
{	
	CURRENT_IT = begin;
	animate( CURRENT_IT, false );
	playAnimatedSeries( end, step );			
}

function revAnimateSeries( begin, end, step )
{
	CURRENT_IT = begin;
	animate( CURRENT_IT, false );
	playRevAnimatedSeries( end, step );
}

function playAnimatedSeries( end, step )
{
	if( animationInterval ) window.clearInterval( animationInterval );
	
	animationInterval = window.setInterval( 
		function()
		{			
			if( CURRENT_IT >= end ) window.clearInterval( animationInterval );
			else
			{
				CURRENT_IT += step;
				if( CURRENT_IT > end ) CURRENT_IT = end;
				animate( CURRENT_IT, false );
			}
		}
		, 40 );			
}

function playRevAnimatedSeries( end, step )
{
	if( animationInterval ) window.clearInterval( animationInterval );

	animationInterval = window.setInterval( 
		function()
		{			
			if( CURRENT_IT <= end ) window.clearInterval( animationInterval );
			else
			{
				CURRENT_IT -= step;
				if( CURRENT_IT < end ) CURRENT_IT = end;
				animate( CURRENT_IT, false );
			}
		}
		, 40 );			
}

function stopAnimatedSeries()
{
	if( animationInterval ) window.clearInterval( animationInterval );
}

function doPosChangeMem(elem,startPos,endPos,steps,intervals,powr)
{
	//Position changer with Memory by www.hesido.com
	if( elem.posChangeMemInt ) window.clearInterval( elem.posChangeMemInt );
	
	var actStep = 0;
	
	elem.posChangeMemInt = window.setInterval(
		function() 
		{
			elem.currentPos =
			[
				easeInOut(startPos[0],endPos[0],steps,actStep,powr),
				easeInOut(startPos[1],endPos[1],steps,actStep,powr)
			];
			elem.style.left = elem.currentPos[0]+"px";
			elem.style.top = elem.currentPos[1]+"px";
			actStep++;
			if( actStep > steps ) window.clearInterval( elem.posChangeMemInt );
		}
		,intervals );
}

function easeInOut( minValue, maxValue, totalSteps, actualStep, powr )
{ 
	//Generic Animation Step Value Generator By www.hesido.com 
    var delta = maxValue - minValue; 
    var stepp = minValue+(Math.pow(((1 / totalSteps) * actualStep), powr) * delta); 
    return Math.ceil(stepp)
} 

function getCoords( highDimensionData )
{
	var weights = new Array( NUM_STATES );
	var sumHighDimensionData = 0.0;
	var coords = Array(2); 
	
	for( i = 0; i < NUM_STATES; i++ )
	{
		sumHighDimensionData += highDimensionData[i];		
	}

	for( i = 0; i < NUM_STATES; i++ )
	{
		weights[i] = highDimensionData[i] / sumHighDimensionData; 
	}

	coords[0] = 0.0;
	coords[1] = 0.0;
	
	// Compute xCoordinate and  yCoordinate
	for( i = 0; i < NUM_STATES; i++ )
	{
		coords[0] += weights[i] * STATE_COORDS[i][0]; // stateCoordinates[i][0] keeps the xCoordinate of state i
		coords[1] += weights[i] * STATE_COORDS[i][1]; // stateCoordinates[i][1] keeps the yCoordinate of state i
	}

	return coords;
}
