function NXTransitionManager() {
	NX.None = 1;
	NX.Linear = 2;
	
	NX.EaseInRegular = 3;
	NX.EaseOutRegular = 4;
	NX.EaseInOutRegular = 5;
	
	NX.EaseInBack = 6;
	NX.EaseOutBack = 7;
	NX.EaseInOutBack = 8;

	NX.EaseInBounce = 9;
	NX.EaseOutBounce = 10;
	NX.EaseInOutBounce = 11;
	
	NX.EaseInElastic = 12;
	NX.EaseOutElastic = 13;
	NX.EaseInOutElastic = 14;
	
	NX.Move = 51;
	//NX.Size = 52;
	//NX.Fade = 53;

	var pool = [];
	var timer = null;
	
	function timeline() {
		for (var i=pool.length-1; i>-1; i--) {
			pool[i].frameAction();
			if (pool[i].progress == 1) {
				if (pool[i].onFinished) pool[i].onFinished(pool[i].element);
				pool.splice(i, 1);
			}
		}
		if (pool.length == 0) {
			clearInterval(timer);
			timer = null;
		}
	}
	
	function startTimer() {
		if (timer == null) {
			safe = 0;
			timer = setInterval(timeline, 10);
		}
	}
	
	function getEasingFunction(type) {
		switch(type) {
			case NX.Linear: {
				return linear;
			}
			case NX.EaseInRegular: {
				return quad;
			}
			case NX.EaseOutRegular: {
				return makeEaseOut(quad);
			}
			case NX.EaseInOutRegular: {
				return makeEaseInOut(quad);
			}
			case NX.EaseInBack: {
				return back;
			}
			case NX.EaseOutBack: {
				return makeEaseOut(back);
			}
			case NX.EaseInOutBack: {
				return makeEaseInOut(back);
			}
			case NX.EaseInBounce: {
				return bounce;
			}
			case NX.EaseOutBounce: {
				return makeEaseOut(bounce);
			}
			case NX.EaseInOutBounce: {
				return makeEaseInOut(bounce);
			}
			case NX.EaseInElastic: {
				return elastic;
			}
			case NX.EaseOutElastic: {
				return makeEaseOut(elastic);
			}
			case NX.EaseInOutElastic: {
				return makeEaseInOut(elastic);
			}
			default: {
				return linear;
			}
		}
	}
	
	function linear(n) {
		return n;
	}
	function quad(n, x) {
		var x = (x == undefined) ? 2 : x;
		return Math.pow(n, x)
	}
	function circ(n) {
		return 1 - Math.sin(Math.acos(n))
	}
	function back(progress, x) {
		var x = (x == undefined) ? 1 : x;
		return Math.pow(progress, 2) * ((x + 1) * progress - x)
	}
	function bounce(progress) {
		for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
			if (progress >= (7 - 4 * a) / 11) {
				return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2)
			}
		}
	}
	function elastic(progress, x) {
		var x = (x == undefined) ? 1.5 : x;
		return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*x/3*progress)
	}
	function makeEaseOut(type) {  
		return function(n) {
			return 1 - type(1 - n)
		}
	}
	function makeEaseInOut(type) {  
		return function(n) {
			if (n < .5) {
				return type(2*n) / 2;
			}
			else {
				return (2 - type(2*(1-n))) / 2;
			}
		}
	}
			
	function getTypeFunction(type, element, param) {
		switch(type) {
			case NX.Move: {
				return new Move(element, param);
			}
		}
	}
		
	function Move(element, param) {
		this.element = element;
		this.to = {
			x: (param.x == undefined) ? null : param.x, 
			y: (param.y == undefined) ? null : param.y
		};
		this.from = {
			x: this.element.offsetLeft,
			y: this.element.offsetTop
		};
		this.distanceX = (this.to.x != null) ? this.to.x - this.from.x : 0;
		this.distanceY = (this.to.y != null) ? this.to.y - this.from.y : 0;
	
		this.action = function(value) {
			if (this.distanceX != null) this.element.style.left = this.from.x+(this.distanceX*value) + "px";
			if (this.distanceY != null) this.element.style.top = this.from.y+(this.distanceY*value) + "px";
		}
	}
	
	this.addToTimeline = function(object) {
		for (var i=0, c=object.effects.length; i<c; i++) {
			var efx = object.effects[i];
			
			var timeLineElement = {
				element: object.element,
				duration: efx.duration||1000,
				type: getTypeFunction(efx.type, object.element, efx.param),
				easing: getEasingFunction(efx.easing),
				onFinished: efx.onFinished,
				timeStart: new Date,
				timePassed: null,
				progress: null,
				frameAction: function() {
					this.timePassed = new Date - this.timeStart;
					this.progress = this.timePassed / this.duration;
					if (this.progress > 1) this.progress = 1;
					var value = this.easing(this.progress);
					this.type.action(value);
				}
			}
		}
		
		pool.push(timeLineElement);
		startTimer();
	}
};
NXTransitionManager = new NXTransitionManager;

function NXTransition(element, effects) {
	if (!element) return 1;	
	
	this.element = element;
	this.effects = (effects.constructor == Array) ? effects : [effects];
}

NXTransition.prototype = {
	addEffect: function(effect) {
	},
	start: function() {
		NXTransitionManager.addToTimeline(this)
	},
	//stop: function() {},
}

