/*** Tween animation for layer properties top, left, width, height, alpha 					***/
/*** usage example xxx = new Tween(id,'width',null,35,1.5,20,null) xxx.animate()			***/
/*** null is used for current values of properties											***/
/*** Control point should be an Array with xy coordinates of middle point of Bezier curve.	***/
/*** If you want tween with ease 0 use null for control point								***/

var Tweens = new Array();
function Tween(id, property, start, end, time, smoothness, controlPoint) {
	var alowed_properties = new Array("top", "left", "width", "height", "alpha");
	if (!in_array(property,alowed_properties)) return;
	var obj = document.getElementById(id);
	var speed;
	if (!obj) return;
	
	//properties
	this.id = Tweens.push(this) -1;
	this.onMotitionFinished = null;
	this.animation_allowed = true;
	this.in_animation = false;
	this.obj = obj;
	
	
	this.objId = id;
	this.property = property;
	this.start = start;
	this.end = end;
	this.time = time;
	this.smoothness = smoothness;
	this.controlPoint = controlPoint;

	this.desired = null; // desired value of animated property
	this.steps = 0;
	this.speed = 0;
	this.current_step = 0;
	this.intervalID = null;
	
	//methods
	this.animate = animate;
	this.getAlpha = _getAlpha;
	this.setAlpha = _setAlpha;
	this.dStep = dStep;
	this.calculateAnimation = calculateAnimation;
}
 
function _getAlpha() {
	if (!this.obj) return -1;
		var browser = navigator.appName;
	if (browser == "Microsoft Internet Explorer") {
		var re=/(alpha)(.{1})(opacity=)(\d{1,})(.{1})/;
		var result = re.exec(this.obj.style.filter);
		return (result != null)  ? parseFloat(result[4]) : 100;
	} else {
		if (this.obj.style.MozOpacity != undefined) return (this.obj.style.opacity == '') ? 100 : parseFloat(this.obj.style.opacity)*100;
		if (this.obj.style.MozOpacity != undefined) return (this.obj.style.MozOpacity == '') ? 100 : parseFloat(this.obj.style.MozOpacity)*100;
		if (this.obj.style.KhtmlOpacity != undefined) return (this.obj.style.KhtmlOpacity == '') ? 100 : parseFloat(this.obj.style.KhtmlOpacity)*100;
	}
	return -1;
}
 
function _setAlpha(alpha) {
	if (!this.obj) return;
	var browser = navigator.appName;
	if (browser == "Microsoft Internet Explorer") {
		this.obj.style.filter = "alpha(opacity="+alpha+")";
	} else {
		this.obj.style.opacity = alpha*0.01;
		this.obj.style.MozOpacity = alpha*0.01;
		this.obj.style.KhtmlOpacity = alpha*0.01;
	}
}

function calculateAnimation() {
	this.start = ((this.start == undefined || this.start == null)) ? ((this.property == "alpha") ? this.getAlpha() : parseInt(this.obj.style[this.property],10)) : parseInt(this.start,10);
	this.end = ((this.end == undefined || this.end == null)) ? ((this.property == "alpha") ? this.getAlpha() : parseInt(this.obj.style[this.property],10)) : parseInt(this.end,10);
	this.time = (this.time == undefined || this.time == null) ? 1000 : parseFloat(this.time)*1000;
	this.smoothness = (this.smoothness == undefined || this.smoothness == null) ?  10 : parseInt(this.smoothness,10);
	this.controlPoint = (this.controlPoint == undefined || this.controlPoint == null || typeof(this.controlPoint) != "object") ?  new Array() : this.controlPoint;
	this.speed = (this.end-this.start)/this.time*this.smoothness;
	this.desired = this.start;
	this.steps = Math.floor(this.time/this.smoothness);
	this.animation_allowed = (!this.speed) ? false : this.animation_allowed;
}
 
function animate(delay) {
 	var id = this.id;
	if (delay && delay > 0) {
		setTimeout(function() {Tweens[id].animate(0)}, delay*1000);
		return;
	}
	if (this.in_animation) return;
	this.calculateAnimation();
	if (!this.animation_allowed) return;
	this.in_animation = true;
 	this.intervalID = setInterval(function() {Tweens[id].dStep()},this.smoothness);
}

function dStep() {
	var current = this.desired;/*(this.property == "alpha") ? this.getAlpha() : parseInt(this.obj.style[this.property],10);*/
	var next = Math.round(current+this.speed);
	if (this.current_step < this.steps) {
		// Bezier Curve
		if (this.controlPoint.length == 2) {
			var t = this.current_step/this.steps;
			var P = new Array({x:0,y:this.start},{x:this.controlPoint[0],y:this.controlPoint[1]},{x:this.steps,y:this.end});
			var resultPoint = PointOnQuadraticBezier(P, t);
			next = resultPoint["y"];
		}
		
		if (this.property == "alpha") this.setAlpha(next);
		else this.obj.style[this.property] = next+"px";
		
		this.current_step++;
		this.desired += this.speed;
	} else {
		// Stop Animation
		if (this.property == "alpha") this.setAlpha(this.end);
  		else this.obj.style[this.property] = this.end+"px";
  
  		this.start = this.end;
		this.in_animation = false;
		clearInterval(this.intervalID);
		
		// On Motion Finished Event;
		if (this.onMotionFinished) this.onMotionFinished(this.property);
	}
}
 
function PointOnQuadraticBezier(P, t) {
	if (t<0 || t>1) {
		alert("t value is invalid (t[0,1])");
		//t=0 is for start point
		//t=1 is for end point
		return;
	}
	 
	if (typeof(P) != 'object' || P.length != 3) {
		alert("cp must be an array with 3 values");
		//P Format is:
		//P[0]['x'] = start value x\nP[0]['y'] = start value y
		//P[1]['x'] = control point value x
		//P[1]['y'] = control point value y;
		//P[2]['x'] = end value x
		//P[2]['y'] = end value y
		return;
	}
	 
	var result = new Array();
	var a = (1-t);
	var aa = a*a;
	var tt = t*t;
	
	result["x"] = P[0]["x"]*aa + 2*P[1]["x"]*t*a + P[2]["x"]*tt;
	result["y"] = P[0]["y"]*aa + 2*P[1]["y"]*t*a + P[2]["y"]*tt;
	
	return result;
}
 
function in_array(needle,haystack) {
	for (var i in haystack) {
		if (haystack[i] == needle) return true;
	}
	return false;
}
