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 = 40;
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('marginTop', 'px'),
	new Array('marginRight', 'px'),
	new Array('marginBottom', 'px'),
	new Array('marginLeft', 'px'),
	new Array('borderWidth', 'px'),
	new Array('backgroundPosition', 'px'),
	
	new Array('color', 'color'),
	new Array('backgroundColor', 'color'),
	new Array('borderColor', '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')
	{
		from 	= new RGBColor(from);
		to 		= new RGBColor(to);
		value	= new RGBColor('black');
		
		value.r = getValueAtFrame(from.r, to.r, duration, easing, frame);
		value.g = getValueAtFrame(from.g, to.g, duration, easing, frame);
		value.b = getValueAtFrame(from.b, to.b, duration, easing, frame);
		
		value = value.toHex();
	}
	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 (typeof(object) != 'object')
	{
		object = document.getElementById(object);
	}
	
	if (attribute == 'opacity')
	{	
		value = getObjectOpacity(object);
		if (isNaN(value))
		{
			return -1;
		}
	}
	else
	{
		eval('value = object.'+attribute+';');
	}
	
	if (getAttributeType(attribute) == 'color')
	{
		value = new RGBColor(value);
		return value.toHex();
	}
	
	if (value)
	{
		return value;
	}
	else
	{
		return '';
	}
}

function setVal(object, attribute, value)
{
	if (typeof(object) != 'object')
	{
		object = document.getElementById(object);
	}
	
	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 value		= '';
				var nbOfFrames	= getNumberOfFrames(duration);
				
				if (typeof(to) == 'string')
				{
					var fromList 	= from.split(' ');
					var toList		= to.split(' ');
					
					for (var k = 0; k < toList.length; k++)
					{
						if (k > 0)
						{
							value += ' ';
						}
						
						value += getIntermediateValue(attribute, fromList[k], toList[k], nbOfFrames, easing, frame);
					}
				}
				else
				{
					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 (tweens[i][OBJECT].area)
				{
					tweens[i][OBJECT].area.adapt();
				}
				
				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;
				}
			}
		}
	}
	
	
	/*if (tweensLeft())
	{
		tweenProcess();
	}*/
	
	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)
{
	if (tweens[slot][SCRIPT])
	{
		var object = tweens[slot][OBJECT];
		eval(tweens[slot][SCRIPT]);
	}
	tweens[slot] = 0;
}

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(object, attribute, from, to, duration, easing, repeat, delay, loops, script)
{
	if (typeof(object) != 'object')
	{
		object = document.getElementById(object);
	}
	
	if (from == 'null' || from == '')
	{
		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);
}


