	/**
	* _basicFx : namespace
	*/
var 	_basicFx = {};

	// ----------------------------------------------------------------------------
	
	/**
	* _basicFx.colors : namespace
	*/
	_basicFx.colors = {
		/**
		* hex2rgb : convert hex string rgb
		* @param (String hex string)
		* @return (Object {r,g,b})
		*/
		hex2rgb : function(str){
			var 	str = str.replace(/#/,'').toUpperCase(),
				x = parseInt(str.substr(0,2), 16),
				y = parseInt(str.substr(2,2), 16),
				z = parseInt(str.substr(4,2), 16);
			return {r:x,g:y,b:z};
		},
		/**
		* rgb2hex : convert rgb values to hex String
		* @param (Int rred, Int green, Int blue)
		* @return (String hex string)
		*/
		rgb2hex : function(r,g,b){
			var hex = function(n) {
				var data = "0123456789ABCDEF";
				if (n == null) return "00";
				n = parseInt(n); 
				if (n == 0 || isNaN(n)) return "00";
				n = Math.round(Math.min(Math.max(0,n),255));
				return data.charAt((n-n%16)/16) + data.charAt(n%16);
			};
			return hex(r)+hex(g)+hex(b);
		},
		/**
		* rgbStyle2rgb : convert rgb computed css style to rgb values
		* @param (String computed css style)
		* @return (Object {Int red, Int green, Int blue})
		*/
		rgbStyle2rgb : function(str){
			var c = str.toString().replace(/[^0-9,]/g,'').split(',');
			return {r:parseInt(c[0]),g:parseInt(c[1]),b:parseInt(c[2])};
		}
	};
	
	// ----------------------------------------------------------------------------
	
	/**
	* _basicFx.easing namespace
	* easing formulas
	*/
	_basicFx.easing = {
		linear 		: function(t,b,c,d){return c*t/d+b;},
		quadIn 		: function(t,b,c,d){return c*(t/=d)*t+b;},
		quadOut 	: function(t,b,c,d){return -c*(t/=d)*(t-2)+b;},
		quadInOut 	: function(t,b,c,d){if((t/=d/2)<1) return c/2*t*t+b; return -c/2*((--t)*(t-2)-1)+b;},
		cubicIn 	: function(t,b,c,d){return c*(t/=d)*t*t+b;},
		cubicOut 	: function(t,b,c,d){return c*((t=t/d-1)*t*t+1)+b;},
		cubicInOut 	: function(t,b,c,d){if((t/=d/2)<1) return c/2*t*t*t+b; return c/2*((t-=2)*t*t+2)+b;},
		quartIn 	: function(t,b,c,d){return c*(t/=d)*t*t*t+b;},
		quartOut 	: function(t,b,c,d){return -c*((t=t/d-1)*t*t*t-1)+b;},
		quartInOut 	: function(t,b,c,d){if((t/=d/2)<1) return c/2*t*t*t*t+b; return -c/2*((t-=2)*t*t*t-2)+b;},
		quintIn 	: function(t,b,c,d){return c*(t/=d)*t*t*t*t+b;},
		quintOut 	: function(t,b,c,d){return c*((t=t/d-1)*t*t*t*t+1)+b;},
		quintInOut 	: function(t,b,c,d){if((t/=d/2)<1) return c/2*t*t*t*t*t+b; return c/2*((t-=2)*t*t*t*t+2)+b;},
		sineIn 		: function(t,b,c,d){return -c*Math.cos(t/d*(Math.PI/2))+c+b;},
		sineOut 	: function(t,b,c,d){return c*Math.sin(t/d*(Math.PI/2))+b;},
		sineInOut 	: function(t,b,c,d){return -c/2*(Math.cos(Math.PI*t/d)-1)+b;}
	};
	/**
	* implement _each method in _basicFx.easing
	*/
	_main._implement(_basicFx.easing,{_each:_main._each});
	
	// ----------------------------------------------------------------------------
	
	/**
	* _basicFx.run main transition transform class
	* @param (parent,element,duration,time,step,trans,cssRule,a)
	* @return (Object) current instance
	*/
	_basicFx.run = function(parent,element,duration,time,step,trans,cssRule,a){
		// obvious
		if(this.running) return false;
		var 	self 	= this,
			interv 	= function(){return self.interval();},
			getColor = function(c){
				return c.toString().match(/rgb/) 
				? _basicFx.colors.rgbStyle2rgb(c) 
				: _basicFx.colors.hex2rgb(c);
			},
			getInt 	= function(v){
				return parseInt(v.toString().replace(/[^0-9]/g,''));
			};
		this.parent 	= parent;
		this.running 	= true;
		this.element 	= element;
		this.duration 	= duration;
		this.time 	= time;
		this.step 	= step;
		this.transition = trans;
		this.cssRule 	= cssRule;
		this.isColor 	= cssRule.match(/color/) ? true : false;
		this.from 	= this.isColor ? getColor(a[0]) : getInt(a[0]);
		this.to 	= this.isColor ? getColor(a[1]) : getInt(a[1]);
		this.timer 	= setInterval(interv,this.step);
		
		/**
		* apply changes to element in loop
		*/
		this.set = function(now){
			// if transform target is color
			if(this.isColor) this.element._style(this.cssRule,'rgb('+now+')');
			// else
			else this.element._style(this.cssRule,Math.floor(now));
		};
		
		/**
		* loop
		*/
		this.interval = function(){
			var time = _main._getTime();
			// if not reached end
			if (time < this.time + this.duration){
				// if transform target is color
				if(this.isColor) this.set(this.compute(time,'r')+','+this.compute(time,'g')+','+this.compute(time,'b'));
				// else
				else this.set(this.compute(time));
			// if end reached
			}else{
				// if transform target is color
				if(this.isColor) this.set(this.to.r+','+this.to.g+','+this.to.b);
				// else
				else this.set(this.to);
				// stop transform
				this.stop();
			}
		};
		
		/**
		* compute values
		*/
		this.compute = function(time,v){
			// if transform target is color
			if(v) 	return Math.floor(this.transition((time-this.time),this.from[v],(this.to[v]-this.from[v]),this.duration));
			// else
			else 	return this.transition((time-this.time),this.from,(this.to-this.from),this.duration);
		};
		
		/**
		* stop transform
		*/
		this.stop = function(){
			this.cancel();
			this.parent.stop();
		};
		
		/**
		* clear transform
		*/
		this.cancel = function(){
			this.running = false;
			clearInterval(this.timer);
		};
		return this;
	};
	
	// ----------------------------------------------------------------------------
	
	/**
	* _basicFx.run transition class
	* @param (parent,{fps,duration})
	* @return (Object) current instance
	*/
	_basicFx.transition = function(element,o){
		// if element is id string or HTML element
		this.element = typeof element === 'string' 
			? document._getById(element) 
			: element ;
		// default frame per seconds
		this.fps = 100;
		// default duration in mms
		this.duration = 500;
		// implement argument's object in class instance
		for(var i in o) this[i] = o[i];
		
		/**
		* start
		* @param (Arrays[Css Rule, from, to],[Css Rule, from, to],...)
		* @return (Object) current instance
		*/
		this.start = function(o){
			this.done 	= false;
			this.time 	= 0;
			this.step 	= Math.round(1000/this.fps);
			this.time 	= _main._getTime() - this.time;
			this.trans 	= [];
			if(this.onStart && typeof this.onStart == 'function') this.onStart();
			// init all css rules sended as arguments
			for(var i=0;i<arguments.length;i++)
				this.trans[i] = new _basicFx.run(
					this,
					this.element,
					this.duration,
					this.time,
					this.step,
					this.transition,
					arguments[i][0],
					[arguments[i][1],arguments[i][2]]
				);
			return this;
			/* for(var t in o){
				if(t=='fps ' || t=='duration') continue;
				this.trans[i] = new _basicFx.run(
					this,
					this.element,
					this.duration,
					this.time,
					this.step,
					this.transition,
					t,[o[t][0],o[t][1]]
				);
			}
			return this; */
		};
		
		/**
		* stop and run callback (if exists)
		*/
		this.stop = function(){
			if(this.onComplete && typeof this.onComplete == 'function' && !this.done){
				this.onComplete();
				this.done = true;
			}
		};
		
		/**
		* stop all transforms
		*/
		this.cancel = function(){
			if(!this.trans) return false;
			for(var i=0;i<this.trans.length;i++) this.trans[i].cancel();
		};
		return this;
	};
	/**
	* default transition formula
	*/
	_basicFx.transition.prototype.transition = _basicFx.easing.quadOut;
	
	// ----------------------------------------------------------------------------
	
	/**
	* window scroll (extend _basicFx.transition)
	*/
	_basicFx.smoothScroll = function(element,o){
		_basicFx.transition.apply(this,arguments);
		this.srollWindow =  typeof element == 'object' 
			&& (element.toString().match('Window') || element == '[object Window]') 
			? true : false;
		this.element = this.srollWindow || typeof element != 'string'
			? element 
			: document.getElementById(element) ;
		this.set = function(now){
			if(this.srollWindow) this.element.scrollTo(0,Math.ceil(now));
			else this.element.scrollTop = Math.floor(now);
		};
	};
	/**
	* default window scroll transition formula
	*/
	_basicFx.smoothScroll.prototype.transition = _basicFx.easing.quadOut;
	// ----------------------------------------------------------------------------
	
	
	/**
	* implement transition formulas as sub-object in all transition classes
	*/
	_basicFx.easing._each(function(trans,i){
		[_basicFx.transition,_basicFx.smoothScroll]._each(function(fn){
			fn[i] = function(element,o){fn.apply(this,arguments);};
			fn[i].prototype.transition = _basicFx.easing[i];
		});
	});
