function isString(variable) {
	if (typeof variable === "string" || variable instanceof String)
	{
		return true;
	}
	
	return false;
}

function setTimeVariables(variable, animStart, animEnd, animDuration) {
	if (isString(variable.start))
	{
		variable.start = convertTimeToSeconds(variable.start);
	}
	if (isString(variable.duration))
	{
		variable.duration = convertTimeToSeconds(variable.duration);
	}
	if (isString(variable.end))
	{
		variable.end = convertTimeToSeconds(variable.end);
	}

	if (variable.start === undefined)
	{
		variable.start = animStart;
	}
	if (variable.duration === undefined)
	{
		if (variable.end !== undefined)
		{
			variable.duration = variable.end - variable.start;
		}
		else
		{
			variable.duration = animDuration;
			variable.end = variable.start + variable.duration;
		}
	}
	if (variable.end === undefined)
	{
		variable.end = variable.start + variable.duration;
	}
}

function addAnimation(animationLayers, animationDefinitions) {
	var layer = 1;
	var startTime = getSceneStartTime();
	var endTime = getSceneEndTime();
	var durationTime = 0;
	for (var animationI = 0; animationI < animationDefinitions.length; animationI++)
	{
		var animationDefinition = animationDefinitions[animationI];
		if (animationDefinition.layer !== undefined)
		{
			layer = animationDefinition.layer;
		}
		animationDefinition.layer = layer;
				
		if (animationLayers[layer] === undefined)
		{
			animationLayers[layer] = new Array();
		}
	
		setTimeVariables(animationDefinition, startTime, endTime, durationTime);
		
		startTime = animationDefinition.start;
		endTime = animationDefinition.end;
		durationTime = endTime - startTime;
		
		if (animationDefinition.object !== undefined)
		{
			animationDefinition.type = "object";
			animationDefinition.ref = loadObject(animationDefinition.object);
			
			if (animationDefinition.fps === undefined)
			{
				animationDefinition.fps = 0;
			}
			if (animationDefinition.camera === undefined)
			{
				animationDefinition.camera = "Camera01";
			}
			if (animationDefinition.clearDepthBuffer === undefined)
			{
				animationDefinition.clearDepthBuffer = 0;
			}
			else
			{
				animationDefinition.clearDepthBuffer = animationDefinition.clearDepthBuffer === true ? 1 : 0;
			}
		}
		else if (animationDefinition.image !== undefined)
		{
			animationDefinition.type = "image";
			animationDefinition.ref = imageLoadImage(animationDefinition.image);
			
			var animStart = startTime;
			var animEnd = endTime;
			var animDuration = durationTime;
			
			//color initialization
			animStart = startTime;
			animEnd = startTime;
			animDuration = animEnd-animStart;
			var r = 255;
			var g = 255;
			var b = 255;
			var a = 255;
			if (animationDefinition.color === undefined)
			{
				animationDefinition.color = [{}];
			}
			
			for (var i = 0; i < animationDefinition.color.length; i++)
			{
				var color = animationDefinition.color[i];
				setTimeVariables(color, animStart, animEnd, animDuration);

				if (color.r === undefined)
				{
					color.r = r;
				}
				if (color.g === undefined)
				{
					color.g = g;
				}
				if (color.b === undefined)
				{
					color.b = b;
				}
				if (color.a === undefined)
				{
					color.a = a;
				}
				
				animStart = color.end;
				animDuration = color.duration;
				animEnd = animStart + animDuration;
				r = color.r;
				g = color.g;
				b = color.b;
				a = color.a;
			}
			
			//angle initialization
			if (animationDefinition.angle !== undefined)
			{
				animStart = startTime;
				animEnd = startTime;
				animDuration = startTime;
				var degrees = 0;
				var pivotX = 0;
				var pivotY = 0;
				for (var i = 0; i < animationDefinition.angle.length; i++)
				{
					var angle = animationDefinition.angle[i];
					setTimeVariables(angle, animStart, animEnd, animDuration);

					if (angle.degrees === undefined)
					{
						angle.degrees = degrees;
					}

					if (angle.pivot !== undefined)
					{
						if (angle.pivot.x === undefined)
						{
							angle.pivot.x = pivotX;
						}
						if (angle.pivot.y === undefined)
						{
							angle.pivot.y = pivotY;
						}
					}
					else
					{
						angle.pivot = {};
						angle.pivot.x = pivotX;
						angle.pivot.y = pivotY;
					}

					animStart = angle.end;
					animDuration = angle.duration;
					animEnd = animStart + animDuration;
					degrees = angle.degrees;
					pivotX = angle.pivot.x;
					pivotY = angle.pivot.y;
				}
			}

			//scale initialization
			animStart = startTime;
			animEnd = startTime;
			animDuration = animEnd-animStart;
			var scaleX = 1.0;
			var scaleY = 1.0;
			if (animationDefinition.scale === undefined)
			{
				animationDefinition.scale = [{}];
			}
			for (var i = 0; i < animationDefinition.scale.length; i++)
			{
				var scale = animationDefinition.scale[i];
				setTimeVariables(scale, animStart, animEnd, animDuration);

				if (scale.x === undefined)
				{
					scale.x = scaleX;
				}
				if (scale.y === undefined)
				{
					scale.y = scaleY;
				}

				animStart = scale.end;
				animDuration = scale.duration;
				animEnd = animStart + animDuration;
				scaleX = scale.x;
				scaleY = scale.y;
			}

			//position initialization
			if (animationDefinition.position !== undefined)
			{
				animStart = startTime;
				animEnd = startTime;
				animDuration = animEnd-animStart;
				var posX = 0;
				var posY = 0;
				for (var i = 0; i < animationDefinition.position.length; i++)
				{
					var position = animationDefinition.position[i];
					setTimeVariables(position, animStart, animEnd, animDuration);

					if (position.x === undefined)
					{
						position.x = posX;
					}
					if (position.y === undefined)
					{
						position.y = posY;
					}

					animStart = position.end;
					animDuration = position.duration;
					animEnd = animStart + animDuration;
					posX = position.x;
					posY = position.y;
				}
			}

			//debugPrint("=> " + JSON.stringify(animationDefinition,null,2));
		}
		else if (animationDefinition.fbo !== undefined)
		{
			animationDefinition.type = "fbo";

			if (animationDefinition.fbo.name === undefined)
			{
				animationDefinition.fbo.name = "fbo";
			}

			animationDefinition.ref = fboInit(animationDefinition.fbo.name);
		}

		if (animationDefinition.initFunction !== undefined)
		{
			evaluateVariable(animationDefinition, animationDefinition.initFunction);
		}

		animationLayers[layer].push(animationDefinition);
		
		startTime = endTime;
		endTime = startTime + durationTime;
	}

	//Sort layers
	return Object.keys(animationLayers).sort().reduce(function (result, key) {
        result[key] = animationLayers[key];
        return result;
    }, {});
}

function evaluateVariable(animation, variable)
{
	if (isString(variable) && variable.charAt(0) === '{')
	{
		var func = new Function('animation', variable);
		return func(animation);
	}

	return variable;
}

function enableShader(animation)
{
	if (animation.shader !== undefined)
	{
		activateShaderProgram(animation.shader.name);

		if (animation.shader.variables !== undefined)
		{
			for (var i = 0; i < animation.shader.variables.length; i++)
			{
				var variable = animation.shader.variables[i];
				var name = getUniformLocation(variable.name);
				var value = evaluateVariable(animation, variable.value);
				if (variable.type === 'int')
				{
					setUniformInt(name, value);
				}
				else //float
				{
					setUniformFloat(name, value);
				}
			}
		}
	}
}

function disableShader(animation)
{
	if (animation.shader !== undefined)
	{
		disableShaderProgram();
	}
}

function drawAnimation(animationLayers)
{
	var canvasWidth = getScreenWidth();
	var canvasHeight = getScreenHeight();
	var time = getSceneTimeFromStart();

	for (var key in animationLayers)
	{
		if (animationLayers.hasOwnProperty(key))
		{
			for (var animationI = 0; animationI < animationLayers[key].length; animationI++)
			{
				var animation = animationLayers[key][animationI];
				
				var start = evaluateVariable(animation, animation.start);
				var end = evaluateVariable(animation, animation.end);

				if (time >= start && time < end)
				{
					enableShader(animation);

					if (animation.type === "image")
					{
						if (animation.additive === true)
						{
							setTextureBlendFunc(animation.ref.ptr, GL_SRC_ALPHA, GL_ONE);
						}

						if (animation.angle !== undefined)
						{
							var degrees = evaluateVariable(animation, animation.angle[0].degrees);
							var pivotX = animation.angle[0].pivot.x;
							var pivotY = animation.angle[0].pivot.y;
							for (var i = 0; i < animation.angle.length; i++)
							{	
								var angle = animation.angle[i];
								if (time >= angle.start)
								{
									var p = (time-angle.start)/angle.duration;
									degrees = interpolateLinear(p,degrees,evaluateVariable(animation, angle.degrees));
									pivotX = interpolateLinear(p,pivotX,angle.pivot.x);
									pivotY = interpolateLinear(p,pivotY,angle.pivot.y);
								}
							}
							setTexturePivotPixel(animation.ref.ptr, pivotX, pivotY);
							setTextureAngle(animation.ref.ptr, degrees);
						}

						var scaleX = animation.scale[0].x;
						var scaleY = animation.scale[0].y;
						for (var i = 0; i < animation.scale.length; i++)
						{	
							var scale = animation.scale[i];
							if (time >= scale.start)
							{
								var p = (time-scale.start)/scale.duration;
								scaleX = interpolateLinear(p,scaleX,scale.x);
								scaleY = interpolateLinear(p,scaleY,scale.y);
							}
						}
						scaleTexture(animation.ref.ptr, scaleX, scaleY);

						if (animation.position !== undefined)
						{
							var xFixed = -(animation.ref.w*scaleX)/2.;
							var yFixed = -(animation.ref.h*scaleY)/2.;
							
							var posX = animation.position[0].x;
							var posY = animation.position[0].y;
							for (var i = 0; i < animation.position.length; i++)
							{	
								var position = animation.position[i];
								if (time >= position.start)
								{
									var p = (time-position.start)/position.duration;
									posX = interpolateLinear(p,posX,position.x);
									posY = interpolateLinear(p,posY,position.y);
								}
							}
							setTexturePositionPixel(animation.ref.ptr, xFixed+posX, canvasHeight-(posY-yFixed));
						}
						else
						{
							alignTextureCenter(animation.ref.ptr, 1);
						}

						var r = animation.color[0].r;
						var g = animation.color[0].g;
						var b = animation.color[0].b;
						var a = animation.color[0].a;
						for (var i = 0; i < animation.color.length; i++)
						{	
							var color = animation.color[i];
							if (time >= color.start)
							{
								var p = (time-color.start)/color.duration;
								r = interpolateLinear(p,r,color.r);
								g = interpolateLinear(p,g,color.g);
								b = interpolateLinear(p,b,color.b);
								a = interpolateLinear(p,a,color.a);
							}
						}
						glColor4ub(r,g,b,a);

						showImage(animation.ref.ptr);
						setTextureDefaults(animation.ref.ptr);
					}
					else if (animation.type === "object")
					{
						var camera = animation.camera;
						var fps = (time-start)*animation.fps;
						if (animation.frame !== undefined)
						{
							fps = animation.frame;
						}
						var clearDepthBuffer = animation.clearDepthBuffer;
						displayObject(animation.ref.ptr, camera, fps, clearDepthBuffer);
					}
					else if (animation.type === "fbo")
					{
						if (animation.fbo.action === "begin")
						{
							fboBind(animation.ref.ptr);
							fboUpdateViewport(animation.ref.ptr);
						}
						else if (animation.fbo.action === "end")
						{
							fboBind();
							fboUpdateViewport();
							
							fboBindTextures(animation.ref.ptr);

							fboDrawFullScreen(animation.ref.ptr);
							
							fboBindTextures();
						}
					}
					
					if (animation.runFunction !== undefined)
					{
						evaluateVariable(animation, animation.runFunction);
					}
					
					disableShader(animation);
				}
			}
		}
	}
}
