// ============================================================
function pushIn(any){this[this.length] = any;return this.length;/*Javascript 1.3 compatible*/}
if(!Array.prototype.push){Array.prototype.push = pushIn;}
// ============================================================
function copyFrame(frame){
	this.Left = frame.Left;this.Top = frame.Top;
	this.Width = frame.Width;this.Height = frame.Height;
	this.Time = frame.Time;
}
// ============================================================
function applyFx(element){
	element.style.left = Math.round(this.Left) + 'px';
	element.style.top = Math.round(this.Top) + 'px';
	element.style.width = Math.round(this.Width) + 'px';
	element.style.height = Math.round(this.Height) + 'px';
}
// ============================================================
function AnimationFrame(left, top, width, height, time){
	this.Left = left;this.Top = top;
	this.Width = width;this.Height = height;
	this.Time = time;
	this.Copy = copyFrame;this.Apply = applyFx;
}
// ============================================================
function AnimationObject(element){
	if(typeof(element)=="string"){element = document.getElementById(element);}

	var me = this;
	var frames = null, timeoutID = -1, running = 0, currentFI = 0, currentData = null, lastTick = -1, callback = null;
	var prevDir = 0;

	this.AddFrame = function(frame){frames.push(frame);};
	this.SetCallback = function(cb){callback = cb;};
	this.getFrames = function (){return frames;}
	//
	this.ClearFrames = function(){
		if(running!==0){this.Stop();}
		frames = [];
		frames.push(new AnimationFrame(0,0,0,0,0));
		frames[0].Time = 0;
		frames[0].Left = parseInt(element.style.left, 10);
		frames[0].Top = parseInt(element.style.top, 10);
		frames[0].Width = parseInt(element.style.width, 10);
		frames[0].Height = parseInt(element.style.height, 10);
		currentFI = 0;
		prevDir = 0;
		currentData = new AnimationFrame(0,0,0,0,0);
	};
	//
	this.ResetToStart = function(){
		if(running!==0){me.Stop();}
		currentFI = 0;
		prevDir = 0;
		currentData = new AnimationFrame(0,0,0,0,0);
		frames[0].Apply(element);
	};
	//
	this.ResetToEnd = function(){
		if(running!==0){me.Stop();}
		currentFI = 0;
		prevDir = 0;
		currentData = new AnimationFrame(0,0,0,0,0);
		frames[frames.length - 1].Apply(element);
	};
	//
	this.Stop = function(){
		if(running===0){return;}
		if(timeoutID!=-1){clearTimeout(timeoutID);}
		prevDir = running;
		running = 0;
	};
	//
	this.RunForward = function(){
		if(running==1){return;}
		if(running==-1){me.Stop();}
		if(frames.length==1 || element===null){return;}
		lastTick = new Date().getTime();

		//Start from the begining
		if(prevDir===0){
			currentFI = 1;
			currentData.Time = 0;
			currentData.Left = parseInt(element.style.left, 10);
			currentData.Top = parseInt(element.style.top, 10);
			currentData.Width = parseInt(element.style.width, 10);
			currentData.Height = parseInt(element.style.height, 10);
			frames[0].Copy(currentData);
		}
		else if(prevDir!=1){
			currentFI++;
			currentData.Time =
			frames[currentFI].Time - currentData.Time;
		}
		running = 1;
		animate();
	};
	//
	this.RunBackward = function(){
		if(running==-1){return;}
		if(running==1){me.Stop();}
		if(frames.length==1 || element===null){return;}

		lastTick = new Date().getTime();

		//Start from the end
		if(prevDir===0){
			currentFI = frames.length-2;
			currentData.Left = parseInt(element.style.left, 10);
			currentData.Top = parseInt(element.style.top, 10);
			currentData.Width = parseInt(element.style.width, 10);
			currentData.Height = parseInt(element.style.height, 10);
			currentData.Time = frames[frames.length-1].Time;
			frames[frames.length-1].Copy(currentData);
			currentData.Time = 0;
		}
		else if(prevDir!=-1){
			currentData.Time =
			frames[currentFI].Time - currentData.Time;
			currentFI--;
		}
		running = -1;
		animate();
	};
	//
	function animate(){
		if(running===0){return;}
		var curTick = new Date().getTime();
		var tickCount = curTick - lastTick;
		lastTick = curTick;

		var timeLeft = frames[((running==-1) ? currentFI+1 : currentFI)].Time - currentData.Time;

		while(timeLeft<=tickCount){
			currentData.Copy(frames[currentFI]);
			currentData.Time = 0;
			currentFI += running;
			if(currentFI>=frames.length || currentFI<0){
				currentData.Apply(element);
				lastTick = -1;
				running = 0;
				prevDir = 0;
				if(callback!==null){callback();}
				return;
			}
			tickCount = tickCount - timeLeft;
			timeLeft = frames[((running==-1) ? currentFI+1 : currentFI)].Time - currentData.Time;
		}

		if(tickCount!==0){
			currentData.Time += tickCount;
			var ratio = currentData.Time/
			frames[((running==-1) ? currentFI+1 : currentFI)].Time;

			currentData.Left = frames[currentFI-running].Left + (frames[currentFI].Left - frames[currentFI-running].Left) * ratio;
			currentData.Top = frames[currentFI-running].Top + (frames[currentFI].Top - frames[currentFI-running].Top) * ratio;
			currentData.Width = frames[currentFI-running].Width + (frames[currentFI].Width - frames[currentFI-running].Width) * ratio;
			currentData.Height = frames[currentFI-running].Height + (frames[currentFI].Height - frames[currentFI-running].Height) * ratio;
		}
		currentData.Apply(element);
		timeoutID = setTimeout(animate, 33);
	}
	//
	this.ClearFrames();
}

