/*!\brief	Class that provides a common animation interface by providing
 *		the ability to change single value numeric css syles over an
 * 		arbitrary amount of time specified in miliseconds.  Also
 *		provided are convienience functions like fadein() and fadeout()
 *		that can be used for common, oft used effects.
 * \param	obj		The dom object to be animated.
 */
BS.com.Animate = function (obj)
{
	this.obj = obj;
	this.mm = new BS.com.Delete();
		
	this.animateCE = this.mm.ceNew('animate', this);
	this.animateCE.addCB(this._animate);
};

BS.com.Animate.prototype = {
	STEP_T:		10,
	lastProp:	null,
	timer:		0,
	label: 		null,
	duration: 	500,
	unit:		null,
	to: 		null,
	mult: 		1,
	ce:		null,

	_delete: function ()
	{
		this.mm._delete();
		this.ce = null;
		this.obj = null;
	},

	_animate: function (type, data, args)
	{
		var d = new Date().valueOf();
		var time = (d - this.timer)
		
		if (time >= this.duration) {
			_bsDom.setStyle(this.obj, this.lastProp,
					this.to + this.unit);
			this.animateCE.clearInterval();
			this._end();
			return;
		}
				
		var val = (this.mult > 0) ?
			time/this.duration : 1 - (time/this.duration);
		
		_bsDom.setStyle(this.obj, this.lastProp, val + this.unit);
	},

	_end: function ()
	{
		this.lastProp = null;
		if (this.ce) this.ce.exec('end', this.label);
	},

	/*!\brief	Sets the custom event to be called when animation
	 *		begins or ends.  The ce is called with two arguments,
	 *		the first being the state (either 'start' or 'end), and
	 *		the second being the label, defined in opts when
	 *		start() is called.  If label is not defined in opts,
	 *		the property is used.
	 * \param	ce		custom event
	 */
	setCE: function (ce) { this.ce = ce; },

	unSetCE: function () { this.ce = null; },

	/*!\brief	Animates a transition from one style to another. From
	 *		and to values are expected to be within the proper
	 *		range and are expected to be numbers and not strings.
	 *		The correct units are added automatically.
	 * \param	prop		css property
	 * \param	from		initial value
	 * \param	to		final value
	 * \param	opts		associative array containing options
	 *				Valid options:
	 *				lbl		first arg passed to CE
	 *				dur		time for animation (ms)
	 */		
	start: function (prop, from, to, opts)
	{
		if (this.lastProp) return;
		this.lastProp = prop;
		
		if (!isset(opts)) opts = {};
		this.timer = new Date().valueOf();
		this.label = isset(opts['lbl']) ? opts['lbl'] : prop;
		this.duration = isset(opts['dur']) ? 
						opts['dur'] : 500;
		this.to = to;
		this.mult = (from > to) ? -1 : 1;
		
		
		if (this.ce) this.ce.exec('start', this.label);
		
		var v = _bsDom.getStyle(this.obj, prop);
		if (typeof v == 'string') {
			this.unit = (v.charAt(v.length-1) == '%') ? 
			   this.unit = '%' : v.substring(v.length-2, v.length);
			if (prop == 'opacity' || prop == 'zIndex')
				this.unit = '';
		}
		else this.unit = '';		
		
		_bsDom.setStyle(this.obj, prop, from + this.unit);
		
		this.animateCE.setInterval(this.STEP_T);
	},

	// Preset methods
	fadein: function (len)
	{
		if (!len) len = 500;
		this.start('opacity', 0, 1, {lbl: 'fadein', dur: len});
	},

	fadeout: function (len)
	{
		if (!len) len = 500;
		this.start('opacity', 1, 0, {lbl: 'fadeout', dur: len});
	},

	cancel: function ()
	{
		this.animateCE.clearInterval();
		this._end();
	}
};

