//=====================================================================
// AccelimationAug - Accel[erated] [an]imation object
// By youngpup.net
// Augmented by structuredview.com
// change a property of an object over time in an accelerated fashion
// Cross-browser augmentation
//=====================================================================
// obj 		: reference to the object you would like to change
// prop 	: AccelimationAug-specific value describing property to modify
//				Presently supports:
//				- AccelimationAug.OPACITY
//				- AccelimationAug.LEFT
// from   	: starting value of prop
// to   	: final value of prop
// time 	: time the animation should take to run
// zip		: optional. specify the zippiness of the acceleration. pick a
//		 		number between -1 and 1 where -1 is full decelerated, 1 is
//		  		full accelerated, and 0 is linear (no acceleration). default
//		  		is 0.
// unit		: optional. specify the units for use with prop. default is
//		  			"px".
//=====================================================================
// bezier functions lifted from the lib_animation.js file in the
// 13th Parallel API. www.13thparallel.org
//=====================================================================


function AccelimationAug(obj, prop, from, to, time, zip)
{
	if (typeof zip  == "undefined") zip  = 0;
	if (typeof unit == "undefined") unit = "";

	this.obj	= obj
	this.prop	= prop;
	this.x0		= from;
	this._x1	= to;
	this.dt		= time;
	this.zip	= -zip;
	this.timer	= null;
	this.onend	= new Function();

	AccelimationAug.MAXOP=getOpacityMax(obj);//nothing is final in js
}

//=====================================================================
// public methods
//=====================================================================

// after you create an AccelimationAug, you call this to start it-a runnin'
AccelimationAug.prototype.start = function()
{
	this.t0 = new Date().getTime();
	this.t1 = this.t0 + this.dt;
	var dx	= this._x1 - this.x0;
	this.c1 = this.x0 + ((1 + this.zip) * dx / 3);
	this.c2 = this.x0 + ((2 + this.zip) * dx / 3);
	AccelimationAug._add(this);
}

// and if you need to stop it early for some reason...
AccelimationAug.prototype.stop = function()
{
	AccelimationAug._remove(this);
}

//=====================================================================
// public static methods
//=====================================================================

AccelimationAug.stopAll = function()
{
	for (var i = 0; i < this.instances.length; i++)
	{
		this.instances[i].stop;
	}
}
//=====================================================================
// private methods
//=====================================================================

// paints one frame. gets called by AccelimationAug._paintAll.
AccelimationAug.prototype._paint = function(time)
{
	var elapsed = time - this.t0;
	x=AccelimationAug._getBezier(elapsed/this.dt,this.x0,this._x1,this.c1,this.c2);

	//=============================================================
	// This is where the augmentation is, providing
	// cross-browser(non-DOM) support for various properties
	//=============================================================
	if (time <= this.t1)
	{
		if(this.prop==AccelimationAug.OPACITY)
		{
			setOpacity(this.obj,x/.99);
		}

		if(this.prop==AccelimationAug.LEFT)
		{
			setX(this.obj,x);
		}
	}
	else
	{
		this._end_();
	}
}

// ends the animation
AccelimationAug.prototype._end_ = function()
{
	if(this.prop==AccelimationAug.OPACITY)
	{
		setOpacity(this.obj,this._x1);
	}
	if(this.prop==AccelimationAug.LEFT)
	{
		setX(this.obj,this._x1);
	}
	this.onend(this);
	AccelimationAug._remove(this);
}

//=====================================================================
// static methods (all private)
//=====================================================================

// add a function to the list of ones to call periodically
AccelimationAug._add = function(o)
{
	var index = this.instances.length;
	this.instances[index] = o;
	//window.status='adding total='+index;
	// if this is the first one, start the engine
	if (this.instances.length == 1)
	{
		this.timerID = window.setInterval("AccelimationAug._paintAll()", this.targetRes);
	}
}

// remove a function from the list
AccelimationAug._remove = function(o)
{
	for (var i = 0; i < this.instances.length; i++)
	{
		if (o == this.instances[i])
		{
			this.instances = this.instances.slice(0,i).concat( this.instances.slice(i+1) );
			break;
		}
	}
	// if that was the last one, stop the engine
	if (this.instances.length == 0)
	{
		window.clearInterval(this.timerID);
		this.timerID = null;
	}
}

// "engine" - call each function in the list every so often
AccelimationAug._paintAll = function()
{
	var now = (new Date()).getTime();
	for (var i = 0; i < this.instances.length; i++)
	{
		this.instances[i]._paint(now);
	}
}


// Bezier functions:
AccelimationAug._B1 = function(t) { return t*t*t }
AccelimationAug._B2 = function(t) { return 3*t*t*(1-t) }
AccelimationAug._B3 = function(t) { return 3*t*(1-t)*(1-t) }
AccelimationAug._B4 = function(t) { return (1-t)*(1-t)*(1-t) }


//Finds the coordinates of a point at a certain stage through a bezier curve
AccelimationAug._getBezier = function(percent,startPos,endPos,control1,control2)
{
	return endPos * this._B1(percent) + control2 * this._B2(percent) + control1 * this._B3(percent) + startPos * this._B4(percent);
}


//=====================================================================
// static properties
//=====================================================================

AccelimationAug.instances = [];
AccelimationAug.targetRes = 20;
AccelimationAug.timerID = null;
AccelimationAug.OPACITY=0;
AccelimationAug.MAXOP=1;
AccelimationAug.LEFT=1;

//=====================================================================
// Miscellaneous extra functions
// Simplifying Cross-browser Coding
// by  structuredview.com
//=====================================================================
function getObjectRef(elName)
{
	if(document.all)
	{
		return document.all[elName];
	}
	else if(document.getElementById(elName))
	{
		return document.getElementById(elName);
	}
	//Still need NN4 compatibility
	return false;
}

function getOpacityMax()
{
	if(document.all&&document.images[0].filters)
	{
		return 100;
	}
	else
	{
		return .99; // bug workaround for Safari 1.2
	}
}

function setOpacity(obj,x)
{
	if(document.all&&obj.filters)
	{
		if(browser.isMac)//MacIE says it has filters, but doesn't deliver.
		{
			return false;
		}
		obj.filters.alpha.opacity=x;
		return true;
	}
	else if(document.getElementById)
	{
		if(obj.style&&obj.style.MozOpacity!=null)
		{
			obj.style.MozOpacity=x;
			return true;
		}
		else if(obj.style&&obj.style.opacity!=null)
		{
			obj.style.opacity=x;//Safari 1.2... lets hope every one else gets the idea
			return true;
		}
		else if(obj.style&&obj.style.getPropertyValue&&obj.style.getPropertyValue('-khtml-opacity')!=null)
		{
			obj.style.setProperty('-khtml-opacity',x);//Safari 1.1, this was hard to find out.
			return true;
			//obj.style.KhtmlOpacity=x;
		}
	}
	return false;
}

function setX(obj,x)
{
	if(document.all){obj.style.pixelLeft=x;return;}
	if(document.getElementById){obj.style.left=x+"px";return;}
	if(document.layers){obj.left=x;}
}
