var OBJECT = 0;
var ATTRIBUTE = 1;
var FROM = 2;
var TO = 3;
var DURATION = 4;
var EASING = 5;
var FRAME = 6;
var SCRIPT = 7;
var START = 8;
var DELAY = 9;
var REPEAT = 10;
var LOOPS = 11;

var EaseNone = 0;
var EaseIn = 1;
var EaseOut = 2;
var EaseInAndOut = 3;

var NoRepeat = 0;
var Repeat = 1;
var RepeatWithoutDelay = 2;
var RepeatPeriod = 3;
var RepeatPeriodWithoutDelay = 4;

var tweens = new Array();
var defaultDuration = 0.5;
var tweenFPS = 25;
var tweenTimer;
var tweenLoops = 0;


var styleAttributes = new Array(
	new Array('width', 'px'),
	new Array('height', 'px'),
	new Array('top', 'px'),
	new Array('left', 'px'),
	new Array('margin-top', 'px'),
	new Array('margin-right', 'px'),
	new Array('margin-bottom', 'px'),
	new Array('margin-left', 'px'),
	new Array('border-width', 'px'),
	
	new Array('color', 'color'),
	new Array('background-color', 'color'),
	new Array('border-color', 'color'),
	
	new Array('zIndex', 'int')
)




function getPercentage(number, total)
{
	return (100 / total) * number;
}

function getIntermediateInt(from, to, percent)
{
	from 		= parseInt(from);
	to 			= parseInt(to);
	percent 	= parseInt(percent);
	
	return from + getValueFromPercentage((to - from), percent);
}

function getValueAtFrame(from, to, duration, easing, frame)
{
	var delta
	var end;
	var start;
	
	if (easing == EaseNone)
	{
		var percent = getPercentage(frame, duration);
		return getIntermediateInt(from, to, percent);
	}
	
	if (easing == EaseIn)
	{
		delta 	= duration;
		start 	= from;
		end 	= to;
	}
	
	if (easing == EaseOut)
	{
		delta	= duration;
		start	= to;
		end		= from;
		frame	= delta - frame;
	}
	
	if (easing == EaseInAndOut)
	{
		delta 	= duration /2;
		
		if (frame < delta)
		{
			start 	= from;
			end 	= from + (to - from) / 2;
		}
		else
		{
			frame	= delta - (frame - delta);
			end 	= from + (to - from) / 2;
			start 	= to;
		}
	}
	
	//Acceleration
	var a = ((end - start)*2) / (delta * delta);
	
	var value = Math.round(start + (a * (frame*frame)) / 2);
	
	//alert('start = ' + start + ' end = ' + end + ' frame = '+ frame + ' duration = ' + duration + ' delta = '+ delta +' a = '+ a +' value = ' + value);
	
	return value;
}

function getValueFromPercentage(total, percent)
{
	return (total * percent) / 100;
}

function tweensLeft()
{
	var i;
	var count = 0;
	
	for (i = 0; i < tweens.length; i++)
	{
		if (tweens[i])
		{
			count++;
		}
	}
	return count;
}

function isTweenActive(slot)
{
	if (tweens[slot])
	{
		return true;
	}
	else
	{
		return false;
	}
}

function getTweenSlot(tween)
{
	var i;
	
	for (i = 0; i < tweens.length; i++)
	{
		if (tween[OBJECT] == tweens[i][OBJECT] && tween[ATTRIBUTE] == tweens[i][ATTRIBUTE])
		{
			return i;
		}
	}
	return -1;
}

function getAttributeType(attribute)
{
	if (attribute.substring(0, 5) == 'style')
	{
		var styleAttr = attribute.substring(6, attribute.length);
		
		var i;
		for (i = 0; i < styleAttributes.length; i++)
		{
			if (styleAttributes[i][0] == styleAttr)
			{
				return styleAttributes[i][1];
			}
		}
	}
	
	return 'number';
}

function getIntermediateValue(attribute, from, to, duration, easing, frame)
{
	var type = getAttributeType(attribute);
	var value = 0;
	
	if (type == 'px')
	{
		if (isNaN(to) && to.substring(to.length -1, to.length) == '%')
		{
			value = getValueAtFrame(parseInt(from), parseInt(to), duration, easing, frame, easing) + '%';
		}
		else
		{
			if (isNaN(from))
			{
				from = parseInt(from.substring(0, from.length - 2));
			}
			
			if (isNaN(to) && to)
			{
				to = parseInt(to.substring(0, to.length - 2));
			}
			

			value = getValueAtFrame(from, to, duration, easing, frame) + 'px';
		}
		
	}
	else if (type == 'color')
	{
		var red 	= new Array(parseInt(from.substring(1, 3)), parseInt(to.substring(1, 3)));
		var green 	= new Array(parseInt(from.substring(3, 5)), parseInt(to.substring(3, 5)));
		var blue 	= new Array(parseInt(from.substring(5, 7)), parseInt(to.substring(5, 7)));
		
		value = '#' 
			+ getValueAtFrame(red[0], red[1], duration, easing, frame) 
			+ getValueAtFrame(green[0], green[1], duration, easing, frame) 
			+ getValueAtFrame(blue[0], blue[1], duration, easing, frame);
	}
	else
	{
		if (type == 'int')
		{
			value = Math.round(value);
		}
		value = getValueAtFrame(from, to, duration, easing, frame, easing);
	}
	
	return value;
}

function getObjectOpacity(object)
{
	var value;
	
	if (object.style.opacity)
	{
		value = object.style.opacity * 100;
	}
	else if (object.style.MozOpacity)
	{
		value = object.style.MozOpacity * 100;
	}
	else if (object.style.filter) 
	{ 
		value = object.style.filter.substr(15, object.style.filter.length - 1);
	}
	
	return value;
}

function setObjectOpacity(object, amount)
{
	amount = (amount == 100)?99.999:amount;
  
	// IE
	object.style.filter = "alpha(opacity:"+amount+")";
	
	// Safari<1.2, Konqueror
	object.style.KHTMLOpacity = amount/100;
  
	// Mozilla and Firefox
	object.style.MozOpacity = amount/100;
  
	// Safari 1.2, newer Firefox and Mozilla, CSS3
	object.style.opacity = amount/100;
}

function getVal(object, attribute)
{
	var value;
	if (attribute == 'opacity')
	{	
		value = getObjectOpacity(object);
		if (isNaN(value))
		{
			return -1;
		}
	}
	else
	{
		eval('value = object.'+attribute+';');
	}
	
	if (value)
	{
		return value;
	}
	else
	{
		return 0;
	}
}

function setVal(object, attribute, value)
{
	if (attribute == 'opacity')
	{
		setObjectOpacity(object, value);
	}
	else
	{
		//document.getElementById('who').value = 'object.'+attribute+' = ' +value+';';
		eval('object.'+attribute+' = value;');
	}
}

function tweenNextFrame()
{
	var i;
	var parameters;
	var count = 0;
	
	for (i = 0; i < tweens.length; i++)
	{
		if (tweens[i])
		{
			count ++;
			var object 		= tweens[i][OBJECT];
			var attribute	= tweens[i][ATTRIBUTE];
			var from 		= tweens[i][FROM];
			var to 			= tweens[i][TO];
			var duration	= tweens[i][DURATION];
			var easing		= tweens[i][EASING];
			var frame 		= tweens[i][FRAME];
			var start		= tweens[i][START];
			var delay		= tweens[i][DELAY];
			var loops		= tweens[i][LOOPS];
			var repeat		= tweens[i][REPEAT];
			
			if (start <= tweenLoops)
			{
				var nbOfFrames	= getNumberOfFrames(duration);
				
				var value		= getIntermediateValue(attribute, from, to, nbOfFrames, easing, frame);
				
				if (tweens[i][SCRIPT])
				{
					eval(tweens[i][SCRIPT]);
				}
				
				setVal(object, attribute, value);
				
				if (object.style.display != 'none' && (object.style.width == '0px' || object.style.height == '0px' || getVal(object, 'opacity') == 0))
				{
					object.style.display = 'none';
				}
				else if (object.style.display != 'block')
				{
					object.style.display = 'block';
				}
				
				if (frame >= nbOfFrames)
				{
					if (repeat == NoRepeat || loops == 1)
					{
						clearTween(i);
					}
					else
					{
						if (loops > 1)
						{
							tweens[i][LOOPS] = loops - 1;
						}
						
						if (repeat == RepeatWithoutDelay || repeat == RepeatPeriodWithoutDelay)
						{
							tweens[i][START] = 0;
						}
						else
						{
							tweens[i][START] = tweenLoops + delay;
						}
						
						if (repeat == RepeatPeriod || repeat == RepeatPeriodWithoutDelay)
						{
							tweens[i][FROM] = to;
							tweens[i][TO] = from;
							
							if (easing == EaseIn)
							{
								tweens[i][EASING] = EaseOut;
							}
							else if (easing == EaseOut)
							{
								tweens[i][EASING] = EaseIn;
							}
						}
						
						tweens[i][FRAME] = 0;
					}
				}
				else
				{
					frame++;
					tweens[i][FRAME] = frame;
				}
			}
		}
	}
	
	tweenLoops ++;
	tweenProcess();
}

function tweenProcess()
{
	if (tweenTimer)
	{
		clearTimeout(tweenTimer);
	}
	
	tweenTimer = setTimeout('tweenNextFrame();', getTweenTimeframe());
}

function getNumberOfFrames(duration)
{
	return tweenFPS * duration;
}

function getTweenTimeframe()
{
	return 1000 / tweenFPS;
}

function getNewTweenSlot()
{
	var i;
	
	for (i = 0; i < tweens.length; i++)
	{
		if (!tweens[i])
		{
			return i;
		}
	}
	return i;
}

function clearTween(slot)
{
	//var  = tweens[slot][EVENT];
	tweens[slot] = 0;
	//eval(event);
}

function addTween(tween)
{
	var tweenExists = getTweenSlot(tween);
	
	if (tweenExists != -1)
	{
		/*if (tweens[tweenExists][TO] == tween[TO])
		{*/
			clearTween(tweenExists);
			//return tweenExists;
		/*}*/
	}
	
	var slot = getNewTweenSlot();
	tweens[slot] = tween;
	
	return slot;
}

function setTweenEvent(slot, event)
{
	tweens[slot][EVENT] = event;
}

function animate(id, attribute, from, to, duration, easing, repeat, delay, loops, script)
{
	var object = id;
	
	if (typeof(id) == 'string')
		var object = document.getElementById(id);
	
	if (from == 'null')
	{
		from = getVal(object, attribute);
	}
	
	if (!delay)
	{
		delay = 0;
	}
	else
	{
		delay = getNumberOfFrames(delay);
	}
	
	if (!repeat)
	{
		repeat = NoRepeat;
	}
	
	if (!loops)
	{
		loops = 0;
	}
	
	var tween 			= new Array();
	tween[OBJECT] 		= object;
	tween[ATTRIBUTE] 	= attribute;
	tween[FROM] 		= from;
	tween[TO] 			= to;
	tween[DURATION] 	= duration;
	tween[EASING]		= easing;
	tween[FRAME] 		= 0;
	tween[DELAY]		= delay;
	tween[START]		= tweenLoops + delay;
	tween[REPEAT]		= repeat;
	tween[LOOPS]		= loops;
	tween[SCRIPT]		= script;
	
	var slot = addTween(tween);
	tweenProcess();
	
	return slot;
}

function setAttribute(id, attribute, value, duration)
{
	if (!duration)
	{
		duration = defaultDuration;
	}
	return animate(id, attribute, 'null', value, duration, EaseInAndOut, '', 0);
}

