/*
 * JavaScript base framework: js
 * Version 0.2.0a
 * Dmitrij Sosnovsenko
 * biodiscus@gmail.com
 *
 * last update: 2011-12-13
 */

 /**
 * Tipps:
 *
 * - IF
 * var tmp;
 * if(tmp != undefined){} // quickly
 * if(!tmp){} // 40% slow
 *
 * - ==
 * undefined ==  null -> true
 * undefined !== null -> true
 *
 * round to integer: 0|x; quickly as Math.floor, -5.99 => -5; 5.1 => 5
 * 10000: 1e4; shoter as 1000, speed is same
 *
 */

;(function(){
	window.js= function(sel, type){
		return new get(sel, type);
	};

	var get= function(sel, type){

			/* ID or HTML */
			if(typeof sel == 'string' ){
				// get object from collection if that exist
				// profiled+
				if(type == null){
					var obj= js.$[sel];
					this.id= sel;

					if(obj != null){
						if(obj.elm == null){

							obj.elm= document.getElementById(sel);
						}
						this.elm= obj.elm;
						return this;
					}


					// profiled+
					//if(/head|body/.test(sel)){ // ERROR by header_container!!!
					if(sel == 'head' || sel == 'body'){
						this.elm= document.getElementsByTagName(sel)[0];
					}else{
						this.elm= document.getElementById(sel);
					}
				}else{

					switch(type){

						case 'obj':
							this.elm= null;
							this.id= sel;
							if(js.$[sel] != null){
								return this
							}
							js.$[sel]= {id:sel, elm:null};
							return this;
						break;

						// reserved
						case 'name':
							this.elm= document.getElementsByName(sel);
						break;

						// reserved
						case 'tag':
							this.elm= document.getElementsByTagName(sel);
						break;

						// profiled+
						case 'html':
							var elm= document.createElement('div');
							elm.innerHTML= sel;
							elm= this.elm= elm.firstChild;

							var id= elm.id;
							if(id == ''){
								id= elm.id= 'id'+js.uniqId();
							}
							this.id= id;
							if(js.$[id] != null){
								return this
							}
							js.$[id]= {id:id, elm:elm};
							return this;
						break;

						default:
					}
				}

				js.$[sel]= {id:sel, elm:this.elm};
				return this;
			}

			/* Object or Element */
			else {
				if(sel == null){sel= document}

				// document
				// profiled+
				if(sel == document){
					var id= this.id= 'document';
					if(js.$[id] == null){
						js.$[id]= {id:id, elm:sel};
					}
					this.elm= sel;
					return this;
				}else

				// DOM element
				if(sel.nodeType != null){
					var id= sel.id;
					if(js.$[id] != null){
						this.id= id;
						this.elm= sel;
						return this
					}
					this.elm= sel;

					// element
					// profiled+
					if(!id){
						id= this.id= sel.id= js.uniqId();
					}
					js.$[id]= {id:id, elm:sel};
					this.elm= sel;
					return this;
				}else

				// window
				// profiled+
				if(sel == window){
					this.elm= sel;
					return this;
				}else{

				// object
				// profiled+
					var id= sel.id;
					if(id && js.$[id] != null){
						this.id= id;
						this.elm= null;
						return this;
					}
					if(!id){
						id= sel.id= js.uniqId();
					}
					this.id= id;
					this.elm= sel.elm= null;
					js.$[id]= sel;
					return this;
				}
			}
			return this;
	}

	get.prototype= window.js;

})();


/**
* $ - is cache of objects with methods to manipulation
*/
js.$= {
	// get object from cache, if one not exist, than create it
	// is in 2 times quickly as js(id)
	// @param string id
	get: function(id){
		return js.$[id] != undefined ? js.$[id] : js(id).$[id];
	},

	// obj is {elm: DOM element or null}
	add: function(id, obj){
		var $= js.$[id];

		// if object exist return id
		if($ != null){
			if($.elm != null){
				return id;
			}
			js.$[id].elm= obj.elm || null;
			return id;
		}

		// if object not exist, add object and return id

		// if id not setted than create that
		if(!id){
			id= 'id'+js.uniqId();
			if(obj.elm != null){
				obj.elm.id= id;
			}
		}

		// save new object to collection
		js.$[id]= obj;
		return id;
	},

	remove: function(id){
		if(js.$[id] != undefined){
			delete js.$[id];
		}
	},

	swap: function(elm1, elm2){
		var el1= js(elm1).elm;
		var el2= js(elm2).elm;
		var id1= el1.id;
		var id2= el2.id;
		js.$[id1].elm= el2;
		js.$[id2].elm= el1;
		js.$[id1].elm.id= id1;
		js.$[id2].elm.id= id2;
	}

}

/**
 * Detect browser
 */
js.browser= (function(){
	var is= function(str){return (navigator.userAgent.indexOf(str) != -1)};
	return {
		check: is,
		ie: is('MSIE'),
		opera: is('Opera'),
		ff: is('Firefox'),
		chrome: is('Chrome'),
		safari: is('Safari')&& !is('Chrome'),
		konqueror: is('konqueror'),

		webkit: is('WebKit'), // Safari
		khtml: is('KHTML'),
		mozilla: is('Mozilla'),
		gecko: is('Gecko')
	}
})();

/**
 * usefull ist for: array, object
 * return undefined, array, boolean, string, number, object, function
 */
js.typeOf= function(o){
	if(typeof o == 'object' && o.pop){return 'array'}
	return typeof o;
}

// All is-function work without object quickly as with object
// Note: if(!js.isObject(obj)){} is quickly as if(js.isArray(arr)) in 2 times!
js.isDefined= function(o){return o != undefined}
js.isBool= function(o){return typeof o == 'boolean'}
js.isOBool= function(o){return (o instanceof Boolean)} // o= new Boolean; typeof o == object
//js.isOBool= function(o){return (o && (o.constructor === Boolean))} // slow // o= new Boolean; typeof o == object
js.isArray= function(o){return (typeof o == 'object' && o.pop)} // == [] == (new Array)
//js.isArray1= function(o){return o instanceof Array} // == [] == (new Array)
js.isObject= function(o){return (typeof o == 'object' && !o.pop)}   // quickly // == {} == (new Object) == (new function(){}) == (new Date) == (new String) == (new XLMHtpReques).. != [] != 1 ..
js.isOObject= function(o){return (o && (o.constructor === Object))} // slow    // == {} == (new Object) != (new function(){}) != (new Date) != (new String) != (new XLMHtpReques).. != [] != 1 ..
// Native typeof
js.isString= function(o){return typeof o == 'string'}
js.isNumber= function(o){return typeof o == 'number'}
js.isFunction= function(o){return typeof o == 'function'}

js.formatOf= function(){
	var val= arguments.length ? arguments[0] : this;
	val= val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/);
	if(!val[3]){val[3]='px'}
	return val;
}

js.toInt= function(){
	var val= arguments.length ? arguments[0] : this;
	return parseInt(val,10) || 0;
}

js.toFloat= function(){
	var val= arguments.length ? arguments[0] : this;
	return parseFloat(val) || 0;
}

/* @param:
 * function,
 * state (only for Elements and not for document!):
 * 	load 		- wait to HTML is only loaded and not initialized/rendered
 * 	init		- wait to HTML is loaded and rendered (width || height > 0), can be hidden, wait 10 sec. (Default)
 * 	infinite	- wait to HTML is visible, same as by styte create but w/o timeout
 */
js.onReady=
js.ready= function(){
	var self= this;
	var fn= null;
	var state= 'init'; // default
	for(var i=0; i<arguments.length&&i<2;i++){
		if(typeof arguments[i] == 'function'){fn= arguments[i];}
		else{state= arguments[i];}
		if(state.length){state= state.toLowerCase();}
	}
	if(!fn){return false;}

	var timeout= 10; // sec.
	var delay= 5; // delay in ms
	var count= timeout * ((0|1e3/delay) || 1);// count of steps
	var tReady= 0;

	var visible= true;
	if(state == 'load'){
		visible= false;
	}else
	if(state == 'infinite'){
		timeout= 0;
	}

	// for document
	// IE6/7, FF3.5, Opera 9.2, Chrome 3, Safari 3, SeaMonkay 1.1
	// wait on load all DOM Elements, but not on full load of Images! it is ready!
	var nodesLen= 0;

	var isReady= (self.elm == document) ?
	function(){
		var body= document.getElementsByTagName('body')[0];
		if(body == null){
			return false;
		}
		var curNodesLen= body.childNodes.length;
		if(curNodesLen > nodesLen){
			nodesLen= curNodesLen;
			return false;
		}
		return true;
	}:
	function(){
		self.elm= document.getElementById(self.id);
		return ( (visible && self.elm != null && self.elm.offsetHeight) || (!visible && self.elm) );
	}

	var loop=  function(){
		if(isReady()){
			clearInterval(tReady);
			fn.call(self,self.elm);
			return;
		}else if(timeout){
			if(count < 1){
				clearInterval(tReady);
				alert('SYSERROR: Timeout > '+timeout+' sec.\nElement "#'+self.id+'" not found!');
				return;
			}
			count--;
		}
	}
	tReady= setInterval(function(){loop()},delay);
	loop();
}

/**
* Timer
*/

js.timer= function(opt){
	var id= this.id;
	var obj= js.$[id];
	if(obj.timer == null){
		obj.timer = {};
	}
	var uid = (opt.uid != null) ? opt.uid : js.uniqId();
	obj.timer[uid] = opt;
	obj.timer[uid].data = {}; // user data
	obj.timer[uid].pid = id;
	obj.timer[uid].uid = uid;

	if(opt.autoStart || typeof opt.autoStart == 'undefined'){
		js.timer.start(id, uid);
	}
	return uid;
};

js.timer.start= function(pid, uid){
	var obj= js.$[pid];

	var _start= function(){
		var timer = this;
		//var uid = timer.uid;
		if(timer.id){return}

		var onStep= timer.onStep.fn;
		var args= timer.onStep.args;
		timer.stop=0;
		var delay= timer.onStep.delay || 75;

		function stop(callback){
			var timer= this;
			clearInterval(timer.id);
			js.timer.clear(timer.pid, timer.uid);
			js.timer._callback.call(timer, callback);
		};

		function loop(){
			//var msg = '<div>'+timer.pid + '.' + timer.uid+'</div>';
			//js('debug').addFirst(msg);

			if(timer.lock == 1){return}

			if(timer.stop == 1){
				stop.call(timer, 'onStop');
				return
			}

			if(timer.pause == 1){return}

			if(onStep.call(timer, args) === false){
				//stop.call(timer, 'onFinish');return; // BUG!!! not clearInterval!!

				/*if(timer.uid == 'fadeOutInfo'){
					alert(timer.pid+', '+timer.uid+' tID: '+timer.id);
				}*/
				clearInterval(timer.id);
				js.timer.clear(timer.pid, timer.uid);
				js.timer._callback.call(timer, 'onFinish');
			}
		};

		js.timer._callback.call(timer, 'onStart');
		loop();
		timer.id= setInterval(loop, delay);
	}

	// start one timer
	if(uid != null){
		var oTimer= obj.timer[uid];
		return _start.call(oTimer);
	}

	// start all timers
	var timerList= obj.timer;
	for(uid in timerList){
		var oTimer= timerList[uid];
		_start.call(oTimer);
	}
};

js.timer._callback= function(callback){
	//var obj= js.$[id];
	//callback= obj.timer[callback];
	var timer = this;
	//var obj= js.$[timer.pid];
	callback= timer[callback];

	if(callback == null || typeof callback.fn != 'function'){return false}
	var delay= callback.delay || 0;
	if(delay){
		setTimeout(function(){
			try{return (function(){callback.fn.call(timer, callback.args)})() }catch(e){}
		}, delay);
	}else{
		try{return callback.fn.call(timer, callback.args)}catch(e){}
	}
};

js.timer.clear= function(pid, uid){
	var obj= js.$[pid];
	if(obj == null){
		return;
	}
	var _clear = function(){
		var timer = this;

		clearInterval(timer.id);
		//clearTimeout(timer.timeoutId);

		//delete obj.timer[timer.uid]; // bug/feature: lösch alle unregestrierte timers die per uniqId gemacht wurde, darf nicht sein

		timer.id= null;
		timer.timeoutId= null;
		//timer.stop=0;
		timer.pause=0;
		timer.timeout=0;
	}

	// clear one timer
	if(uid != null){
		var oTimer= obj.timer[uid];
		return _clear.call(oTimer);
	}

	// clear all timers
	var timerList= js.$[pid].timer;
	for(uid in timerList){
		var oTimer= timerList[uid];
		_clear.call(oTimer);
	}

}

js.timer.stop= function(pid, uid){
	var obj= js.$[pid];
	if(obj == null){
		return;
	}
	var _stop = function(){
		this.stop = 1;
	}

	// stop one timer
	if(uid != null){
		var oTimer= obj.timer[uid];
		return _stop.call(oTimer);
	}

	// stop all timers
	var timerList= js.$[pid].timer;
	for(uid in timerList){
		var oTimer= timerList[uid];
		_stop.call(oTimer);
	}
}

js.timer.pause= function(pid, uid){
	var obj= js.$[pid];
	if(obj == null){
		return;
	}
	var _pause = function(){
		var timer = this;
		timer.pause = 1;
		js.timer._callback.call(timer, 'onPause');
	}

	// pause one timer
	if(uid != null){
		var oTimer= obj.timer[uid];
		return _pause.call(oTimer);
	}

	// pause all timers
	var timerList= js.$[pid].timer;
	for(uid in timerList){
		var oTimer= timerList[uid];
		_pause.call(oTimer);
	}
}

js.timer.resume= function(pid, uid){
	var obj= js.$[pid];
	if(obj == null){
		return;
	}
	var _resume = function(){
		var timer = this;
		timer.pause = 0;
		js.timer._callback.call(timer, 'onResume');
	}

	// resume one timer
	if(uid != null){
		var oTimer= obj.timer[uid];
		return _resume.call(oTimer);
	}

	// resume all timers
	var timerList= js.$[pid].timer;
	for(uid in timerList){
		var oTimer= timerList[uid];
		_resume.call(oTimer);
	}
}

// lock timer, prio 1
js.timer.lock= function(pid, uid){
	var obj= js.$[pid];
	if(obj == null){
		return;
	}
	var _lock = function(){
		var timer = this;
		timer.lock = 1;
		js.timer._callback.call(timer, 'onLock');
	}

	// lock one timer
	if(uid != null){
		var oTimer= obj.timer[uid];
		return _lock.call(oTimer);
	}

	// lock all timers
	var timerList= js.$[pid].timer;
	for(uid in timerList){
		var oTimer= timerList[uid];
		_lock.call(oTimer);
	}
}

// unlock timer
js.timer.unlock= function(pid, uid){
	var obj= js.$[pid];
	if(obj == null){
		return;
	}
	var _unlock = function(){
		var timer = this;
		timer.lock = 0;
		js.timer._callback.call(timer, 'onUnlock');
	}

	// unlock one timer
	if(uid != null){
		var oTimer= obj.timer[uid];
		return _unlock.call(oTimer);
	}

	// unlock all timers
	var timerList= js.$[pid].timer;
	for(uid in timerList){
		var oTimer= timerList[uid];
		_unlock.call(oTimer);
	}
}


/**
* Redirect the site to the url
*/
js.redirect= function(url){
	url+= url.indexOf('?') < 0 ? '?' : '&';
	window.location.replace(url+js.uniqId());
}

/**
 * return milliseconds
 * profiled+
 */
js.msec= function(){
	return (new Date).getTime();
}

/**
 * return timestamp
 * profiled+
 */
js.tstamp= function(){
	return 0|js.msec()/1e3;
}

/**
 * Generate a unique ID
 * return integer Id
 * profiled+
 */
js.uniqId= function(){
    return 0|Math.random()*1e6;
}

js.test= function(){
	var elm= this.elm;
	return this.id
}

//JS Extensions

//trim
if (typeof String.prototype.trim == 'undefined') {
	String.prototype.trim= function(){return this.replace(/^\s+/, '').replace(/\s+$/, '')}
}

//ftrim - fullTrim: left + inner + right
if (typeof String.prototype.ftrim == 'undefined') {
	String.prototype.ftrim= function(){return this.replace(/^\s+/, '').replace(/\s{2,}/, ' ').replace(/\s+$/, '')}
}

//itrim - innerTrim, " ABC  QWE ERT  " =>  " ABC QWE ERT "
if (typeof String.prototype.itrim == 'undefined') {
	String.prototype.itrim= function(){return this.replace(/\s{2,}/, ' ')}
}

//ltrim
if (typeof String.prototype.ltrim == 'undefined') {
	String.prototype.ltrim= function(){return this.replace(/^\s+/, '')}
}

//rtrim
if (typeof String.prototype.rtrim == 'undefined') {
	String.prototype.rtrim= function(){return this.replace(/\s+$/, '')}
}

//indexOf - find index of value in array
if(!Array.prototype.indexOf){
	Array.prototype.indexOf= function(value, offset){
		for(var i= offset||0, length= this.length; i<length; i++){
			if(this[i] === value) return i;
		}
		return -1
	};
}


