Motionobjects = new Array();

function Motion(obj, property, unit, round, startValue, endValue, duration, startDelay, computation) {
	this.obj = obj;
	this.property = property;
	this.startValue = startValue;
	this.endValue = endValue;
	this.duration = duration;
	this.unit = (typeof unit == 'string') ? unit : '';
	this.round = round;
	this.lastValue = this.startValue;
	this.timeouts = new Array();
	this.startDelay = (typeof startDelay != 'undefined') ? startDelay : 0;
	this.rgbMode = false;
	
	var date = new Date();
	var firstrelease = date.getTime() + this.startDelay;
	
	for (var i = 0; i < Motionobjects.length; i++) {
		if (Motionobjects[i] != null && Motionobjects[i].obj == this.obj && Motionobjects[i].property == this.property) {
			var wasfinished = true;
			for (var j = 0; j < Motionobjects[i].timeouts.length; j++) {
				if (firstrelease <= Motionobjects[i].timeouts[j].release) {
					window.clearTimeout(Motionobjects[i].timeouts[j].id);
					wasfinished = false;
				}
			}
			if (!wasfinished)
				this.startValue = Motionobjects[i].lastValue;
			Motionobjects[i] = this;
			this.id = i;
			break;
		}
	} 
	
	if (typeof this.id == 'undefined')
		this.id = Motionobjects.push(this) - 1;



	this.computation = (typeof computation != 'undefined') ? computation : 'ramp';
	if (this.property == 'opacity') this.computation = 'linear';

	if (typeof startValue == 'string' && startValue.substr(0,1) == '#') {
		this.rgbMode = true;
	} else if (typeof startValue == 'string') {
		this.obj.style[this.property] = startValue;
		window.setTimeout('Motionobjects['+this.id+'].obj.style[\''+this.property+'\'] = \''+endValue+'\';', this.duration + this.startDelay);
		return;
	}	
	
	
	
	switch (this.computation) {
		case 'cubic':
			this.a = -(2*(-this.startValue+this.endValue))/Math.pow(this.duration,3);
			this.b = (3*(-this.startValue+this.endValue))/Math.pow(this.duration,2);
			this.d = this.startValue;
			break;
		case 'linear':
			this.a = (this.endValue-this.startValue)/this.duration;
			this.b = this.startValue;
			break;
		case 'ramp':
			this.s_ges = this.endValue - this.startValue;
			this.durationSquare = Math.pow(this.duration,2);
			break;
	}
	
	this.start();
}


Motion.prototype.value = function (t) {
	switch (this.computation) {
		case 'cubic':
			return (t < this.duration) ? this.a*Math.pow(t,3) + this.b*Math.pow(t,2) + this.d : this.endValue;
		case 'linear':
			return (t < this.duration) ? this.a*t + this.b : this.endValue;
		case 'ramp':
			if (t < (1/3)*this.duration)
				return (9/4)*this.s_ges*Math.pow(t,2)/this.durationSquare + this.startValue;
			else if (t <= (2/3)*this.duration) {
				return (3/2)*this.s_ges*t/this.duration-(1/4)*this.s_ges + this.startValue;
			} else if (t < this.duration)
				return -(9/4)*this.s_ges*Math.pow(t,2)/this.durationSquare+(9/2)*this.s_ges*t/this.duration-(5/4)*this.s_ges + this.startValue;
			else
				return this.endValue;
	}
}

Motion.prototype.start = function (t) {
	var date = new Date();
	var now = date.getTime();
	var value;
	var lastvalue = null;
	for (var t = 0; t <= this.duration; t += 25) {
		if (this.rgbMode)
			value = "'"+Motion.gradient(this.startValue, this.endValue, (t / this.duration) * 100)+"'";
		else
			value = (this.round) ? Math.round(this.value(t)) : this.value(t);
		if (!lastvalue || value != lastvalue) {
			var timeout = window.setTimeout('Motionobjects['+this.id+'].set('+value+');', t + this.startDelay);
			this.timeouts.push( {'id': timeout, 'release' : now + t + this.startDelay} );
		}
		lastvalue = value;
	}
}

Motion.prototype.set = function (value) {
	this.lastValue = value;
	this.obj.style[this.property] = value+this.unit;
}

Motion.gradient = function (from, to, percent) {
	var out = new Object();
	var fromRGB = Motion.hex2rgb(from);
	var toRGB = Motion.hex2rgb(to);
	for (var c in fromRGB) {
		out[c] = fromRGB[c] + Math.round((percent / 100) * (toRGB[c] - fromRGB[c])); 
	}
	return Motion.rgb2hex(out);
}

Motion.hex2rgb = function (hex) {
	return {	r: parseInt(hex.substr(1,2), 16),
				g: parseInt(hex.substr(3,2), 16),
				b: parseInt(hex.substr(5,2), 16)	};
}

Motion.hex = '0123456789abcdef';
Motion.rgb2hex = function (rgb) {
	var dec,tmp;
	var out = '#';
	for (var c in rgb) {
		dec = rgb[c];
		tmp = '';
		for(var i = 0; i < 2; i++) {
			tmp = Motion.hex.charAt(dec%16) + tmp;
			dec = dec >> 4;
		}
		out += tmp;
	}
	return out;
}