(function(){
window.pf = {
	//taken form JavaScript Design Patterns by RossHarmes & Dustin Diaz
	inherit: function(sb,superClass){
		var F = function(){};
		F.prototype = superClass.prototype;
		sb.prototype = new F();
		sb.prototype.constructor = sb;
		sb.superClass = superClass.prototype;
		if(superClass.prototype.constructor === Object.prototype.constructor){
			superClass.prototype.constructor = superClass;
		}
	},
	extend: function(o,d){
		o = o || {};
		for (var prop in d){
			if (typeof o[prop] == 'undefined') {
				o[prop] = d[prop];
			}
		}	
		return o;
	},
	q: function(s,c){
		return new pf.Q(s,c);
	},
	Q: function(s,c){
		this.stack = [];
		if (typeof c == 'string') {
			c = document.getElementById(c);
		}
		this.setArray((c)?[c]:[document]);
		return ((typeof s == 'object') ? this.setArray((!s.clearInterval && !s.tagName) && (s.length || s.length === 0)? s : [s]) : this.find(s,c));		
	},
	a: function(a){
		return new pf.A(a);
	},
	A: function(a){
		this.setArray(a);
	}
};
pf.A.prototype = {
	inArray: function(c){
		var r = false;
		for(var i = 0, len = this.length; i<len; i++){
			if(this[i] === c){
				r = true;
				break;
			}
		}
		return r;
	},
	length: 0,
	/* taken form jQuery */
	setArray: function( a ) {
		this.length = 0;
		Array.prototype.push.apply( this, a );
		return this;
	},
	each: function(fn, num){  
	  if(typeof num == 'number'){
	  	if (this[num]) {
			fn.call(this[num], num);
		}
	  } else {
		  var start = (typeof num != 'string' || !num.match(/(\d+)\+/))? 0 : parseInt(num.match(/(\d+)\+/)[1], 10);
		  var len = (typeof num != 'string' || !num.match(/(\d+)\-/))? this.length : parseInt(num.match(/(\d+)\-/)[1], 10);
		  for ( var i = start; i<len; ++i ) {
			if(fn.call(this[i], i) === false){
				break;
			}
		  }
	  }
	  return this;
	}
};
var Apro = pf.A.prototype;
pf.inherit(pf.Q,pf.A);
var Qpro = pf.Q.prototype;
Qpro.pushStack = function(a){	
	var r = pf.q(a);
	r.stack = this.stack;
	r.stack.push(this.get());
	return r;
};
Qpro.each = function(fn, num){
	if(typeof num == 'number'){
		if (this[num]) {
			fn.call(this[num], num);
		}
	} else {
		var start = (typeof num != 'string' || !num.match(/(\d+)\+/))? 0 : parseInt(num.match(/(\d+)\+/)[1], 10);
		var len = (typeof num != 'string' || !num.match(/(\d+)\-/))? this.length : parseInt(num.match(/(\d+)\-/)[1], 10);
		for ( var i = start; i<len; ++i ) {
			if(!this[i] || fn.call(this[i], i) === false){
				break;
			}
		}
	}
	return this;
};
Qpro.find = function(s,c){
	var htmlStack = [], o, elms, i, len, elmsLen;

	if(c === null || this[0] === null){
		return this.pushStack([null]);
	}

	o = filter.extractSel(s);
	
	var get = function(){
		var sel;
		if(o[1]){
			sel = o[1];
			o[1] = false;
			return {
				elementBy: function(that){
					return [that.getElementById(sel)];
				}
			};
		} else if(document.getElementsByClassName && o[2] && o[2][0] && o[2][0][1]) {
			sel = o[2][0][1];
			o[2].shift();
			if(!o[2].length){
				o[2] = false;
			}
			return {
				elementBy: function(that){
					return that.getElementsByClassName(sel);
				}
			};
		} else {
			sel = o[0];
			o[0] = false;
			return {
				elementBy: function(that){
					return that.getElementsByTagName(sel);
				}
			};
		}
	}();
	len = this.length;
	for(i = 0;i < len; i++){
		if(this[i].querySelectorAll){
			elms = this[i].querySelectorAll(s);
			elmsLen =  elms.length;
			for(i = 0; i<elmsLen;i++ ){
				htmlStack.push(elms[i]);
			}
		} else {
			elms = get.elementBy(this[i]);
			htmlStack = filter.elements(elms, o, htmlStack);
		}
	}
	
	if (len > 1) {
		var n = [], d = {};
		for(i = 0, elmsLen = htmlStack.length; i<elmsLen;i++){
			if (!d[id = filter.getId(htmlStack[i])]) {
				n.push(htmlStack[i]);
				d[id] = true;
			}
		}
		htmlStack = n;
	}
	return this.pushStack(htmlStack);
};
Qpro.get = function(n){
	if(n || n === 0){
		return (this[n] && this.length > n)?this[n]:null;
	}
	var a = [];
	for(var i = 0, len = this.length; i < len; i++){
		a.push(this[i]);
	}
	return a;
};
var pfExpando = "pf" + (new Date()).getTime();
pf.filter = {
	id: 0,
	add: function(expr,hasF){
		filter.exp.push(expr);
		filter.has.push(hasF);
	},
	exp: [
			/([a-z][-_a-z0-9]*)*/i,
			/#([a-z][-_a-z0-9]*)*/i,
			/\.([a-z][-_a-z0-9]*)*/gi
		],
	has: [
			function(elm, na){return (na === '*' || elm.tagName.toLowerCase() === na);},
			function(elm, ni){return (elm.getAttribute('id') == ni);},
			function(elm, sC){
				var rVal = true, eCl = elm.className, p;
				
				if(typeof sC == 'string'){
					sC = [[null,sC]];
				}
				
				for(var i = 0,sClen = sC.length; i<sClen; i++){
					if(eCl.indexOf(sC[i][1]) === -1){
						rVal = false;
						break;
					}else{
						if(!pf.a(eCl.split(' ')).inArray(sC[i][1])){
							rVal = false;
							break;
						}
					}
				}
				return rVal;
			}
		 ],
	extractSel: function(s){
		if(!s){
			return null;
		}
		var o = [], tmp, ex = filter.exp;
		o[0] = ex[0].exec(s);
		o[0] =  o[0][1] || '*';
		o[1] = ex[1].exec(s);
		o[1] = o[1] ? o[1][1] : false;
		for(var i = 2, exLen = ex.length; i < exLen; i++){
			while ((tmp = ex[i].exec(s))) {
			  if(tmp && !o[i]){
			  	o[i] = [];
			  }         
			  o[i].push(tmp);
			}
		}
		return o;
	},
	getId: function(elem){
		var id = elem[ pfExpando ];
		if (!id) {
			id = elem[pfExpando] = ++filter.id;
		}
		return id;
	},
	elements: function(elms, s, a) {
		var n = a || [], o = typeof s == 'string' ? filter.extractSel(s) : s;
		for(var i = 0, elmsLen = elms.length; i<elmsLen;i++){
			if (!o || filter.bySelector(elms[i], o)) {
				n.push(elms[i]);
			}
		}
		return n;
	},
	bySelector: function(el, o){
		var rVal = true;
		for(var i = 0, len = filter.exp.length; i < len; i++){
			if(o[i] && o[i] != '*' && !filter.has[i](el,o[i])){
				rVal = false;
				break;
			}
		}
		return rVal;
	}
};
var filter = pf.filter;
Qpro.css = function(o,num){
	if(typeof o == 'string'){
		num = num || 0;
		var cV = "";
		if(document.defaultView && document.defaultView.getComputedStyle){
			o = pf.dasherize(o);
			cV = document.defaultView.getComputedStyle(this[0], "").getPropertyValue(o);
		} else if(this[0].currentStyle){
			o = pf.camelize(o);
			o = (o === 'opacity' && window.ActiveXObject)?'filter':o;
			cV = this[0].currentStyle[o];
			if(o === 'filter'){
				var p = /opacity=([\d]+)/.exec(cV);
				cV = (p)?parseFloat(p[1])/100:1;
			}
		}
		return cV;
	} else {
		this.each(function(){
			var eS = this.style;
			for(var p in o){
				var pN = pf.camelize(p);
				if (pN == 'opacity' && window.ActiveXObject) {
					eS.filter = "alpha(opacity=" + parseFloat(o[p], 10) * 100 + ")";
				} else {
					eS[pN] = o[p];
				}
				
	        }
		},num);
	}
	return this;
};
Qpro.width = function(num){
	num = num || 0;
	var o;
	if (this[num]) {
		
		if(this[num] === window){
			
			var de = document.documentElement;
			if (window.innerWidth){
				o = window.innerWidth;
			} else if (de && de.clientWidth !== 0){
				o = de.clientWidth;	
			} else if (document.body){
				o = document.body.clientWidth;
			}
			return o;
		}		
		o = (this.css('display', num) == 'none') ? 0 : parseInt(this.css('width', num), 10);
		return (isNaN(o)) ? this[num].offsetWidth : o;
	}
};
Qpro.height = function(num){
	num = num || 0;
	var o;
	if(this[num]){
		if(this[num] === window){
			var de = document.documentElement;
			if (window.innerHeight){
				o = window.innerHeight;
			} else if (de && de.clientHeight !== 0){
				o = de.clientHeight;	
			} else if (document.body){
				o = document.body.clientHeight;
			}
			return o;
		}
		o = (this.css('display',num) == 'none')?0:parseInt(this.css('height',num), 10);
		return (isNaN(o)) ? this[num].offsetHeight : o;
	}
};
pf.interval = (function(){
	var intervals = [], running = false, intervalID;
	function internalFu(){
		for(var i = 0, len = intervals.length; i < len; i++){
			if(intervals[i]){
				intervals[i]();
			}
		}
		if(running){
			intervalID = setTimeout(internalFu, 17);
		}
		
	} 
	function clearIT(){
		var clear = true;
		for(var i = 0, len = intervals.length; i < len; i++){
			if(intervals[i]){
				clear = false;
				break;
			}
		}
		if(clear){
			running = false;
			clearTimeout(intervalID);
			intervals = [];
		}
	}
	return {
		set: function(fn){
			var r = intervals.push(fn);
			if(!running){
				running = true;
				internalFu();
			}
			
			return r-1;
		},
		clear: function(ref){
			if(intervals[ref]){
				clearIT();
				intervals[ref] = false;
			}
			return false;
		}
	};
})();

pf.extend(Qpro,{
	animate: function(s,o){
		
		var animation = new pf.fx(this,s,o);
		return this.each(function(i){
			this.pfAnim = animation;
		});
	},
	abortAnim: function(){
		return this.each(function(i){
			if(this.pfAnim){
				this.pfAnim.abort();
			}
		});
	},
	fullheight: function (num){
		num = num || 0;
		if(this[num]){
			var el = this[num],
			dis = this.css('display',num),
			eS = el.style;
			if (dis != 'none' && parseInt(eS.height, 10) !== 0) {
				return this.height(num);
			}
			var oC = {visibility: eS.visibility, position: eS.position, display: eS.display,height: eS.height },
			nC = pf.extend({visibility: 'hidden', position: 'absolute', display: 'block'}, 
				(dis == 'none')?{display: 'block'}:{height: ''});
			this.css(nC,num);
			var h = (isFinite(el.clientHeight))?el.clientHeight : parseInt($this.css('height'), 10);
			this.css(oC,num);
			return h; 
		}

	},
	fullwidth: function (num){
		num = num || 0;
		if (this[num]) {
			var el = this[num], dis = this.css('display', num), eS = el.style;
			if (dis != 'none' && parseInt(eS.width, 10) !== 0) {
				return this.width(num);
			}
			var oC = {
				visibility: eS.visibility,
				position: eS.position,
				display: eS.display,
				width: eS.width
			}, nC = pf.extend({
				visibility: 'hidden',
				position: 'absolute',
				display: 'block'
			}, (dis == 'none') ? {
				display: 'block'
			} : {
				width: ''
			});
			this.css(nC,num);
			var h = (isFinite(el.clientWidht)) ? el.clientWidht : parseInt(this.css('width',num), 10);
			this.css(oC,num);
			return h;
		}
	}
});
pf.fx = function(elms,s,o){
	this.elm = elms;
    this.o = pf.extend(o,pf.fx.defaults);
    this.start = [];
	this.end = [];
	this.reset = [];
	this.unit= {};
    this.now= 0;
    this.timer= null;
    this.time= null;
    this.props= [];
	this.unit= {};
	this.state = 0;
	this.s = (s.constructor == Array)?s:[s];
    this.init();
};
pf.fx.prototype = {
	init: function(){
		var that = this, elms = [], elm, show = [], jS, s = [], j = 0;
		this.elm.each(function(i){
			elm = pf.q(this);
			if(!that.props[i]){
				that.props[i] = [];
				that.start[i] = {};
				that.end[i] = {};
				that.unit[i] = {};
				that.reset[i] = [];
				if(that.s[i]){
					jS = pf.extend({},that.s[i]);
					s[i] = jS;
					j++;
				}else{
					s[i] = jS;
				}
			}
			for(var prop in s[i]){
				var cssProp = pf.camelize(prop);
				that.start[i][prop] = parseFloat((Qpro[cssProp])?elm[cssProp]():elm.css(cssProp));
				if (s[i][prop] == 'toggle') {
					s[i][prop] = (that.start[i][prop]) ? 'hide' : 'show';
				}
				
				var sF = /^([0-9\.]+)?(.*)/.exec(s[i][prop]);
				that.unit[i][prop] = /^show$|^hide$/.test(sF[2])?(/^height$|^width$/.test(cssProp))?'px':'':sF[2];
				that.end[i][prop] = (s[i][prop] == 'hide')
					? 0 : 
					(s[i][prop] == 'show' && (/^height$|^width$/.test(cssProp))) 
					? elm['full'+cssProp]() | that.reset[i].push(cssProp)  : 
					((s[i][prop] == 'show' || s[i][prop] == 1) && cssProp == 'opacity')
					? 0.9999 :parseFloat(sF[1]);
	            that.props[i].push(prop);
				show.push((elm.css('display')=='none')?elm:false);
	        }
			elms.push(this);	
		});
		this.s = s;
		this.elm = elms;
		this.time= new Date().getTime();
		this.computeStep();
		this.state = 1;
		for(var i = 0, len = show.length;i<len;i++){
			if(show[i]){
				show[i].css({display: 'block'});
			}
		}
        (function(){
			 that.timer = pf.interval.set(function(){
                 that.computeStep.call(that);
             });
        })(); 
		
    }, 
    step: function(num,prop){
        
		var res = ((this.end[num][prop] - this.start[num][prop]) * this.now) + this.start[num][prop];
		if (prop == 'opacity' && window.ActiveXObject) {
			this.elm[num].style.filter = "alpha(opacity=" + res * 100 + ")";
		} else {
			this.elm[num].style[prop] = res + this.unit[num][prop];
		}
    },
	computeStep: function(){
		var time = new Date().getTime(),finisched = false, i, len, j, props, porpLen;
		
        if (time < this.time + this.o.duration){
			var cTime = time - this.time;
            this.now = pf.fx.transition[this.o.easin](cTime,0,1,this.o.duration);
		} else {
			pf.interval.clear(this.timer);
            this.timer = null;
            this.now = 1;
            finisched = true;
		}
		for(j = 0, len = this.elm.length; j < len; j++){
			for(i = 0,props = this.props[j], porpLen = props.length; i<porpLen; i++){
				var prop = props[i];
	            ((this[prop])?this[prop](j, prop): this.step(j, prop));
	        }	
		}
        if (finisched) {
			var resetStyle = {};
			for(i = 0, len = this.elm.length; i < len; i++ ){
				this.elm[i].pfAnim = null;
				if (this.reset[i].length) {
					
					for(var num = 0; num<this.reset[i].length; num++){
						resetStyle[this.reset[i][num]] = '';
					}
					pf.q(this.elm[i]).css(resetStyle);
				}
				this.o.complete.call(this.elm[i],'aborted');
			}
		}
		
    },
	abort: function(){
		pf.interval.clear(this.elm[0].pfAnim.timer);
		this.elm[0].pfAnim.timer = null;
		for(var i = 0, len = this.elm.length; i < len; i++ ){
			this.elm[i].pfAnim = null;
			this.o.complete.call(this.elm[i],'aborted');
		}
		
	}
};
pf.fx.defaults = {
    duration: 500,
    complete: function(){},
	easin: 'sineInOut'
};
pf.fx.transition = {
	linear: function(t, b, c, d) { return c*t/d + b; },
	sineInOut: function(t, b, c, d) { return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; }
};
pf.dasherize = function(s){
	return s.replace(/([A-Z])/g, function (m, p1){
		return '-'+p1.toLowerCase();
	});
};
pf.camelize = function(s){
	return s.replace(/\-(\w)/g, function (m, p1){
		return p1.toUpperCase();
	});
};
})();
