/*
Copyright 2008 ITLife, Ltd. Togliatti, Samara Oblast, Russian Federation. http://itlife-studio.ru

js.load
js.loadJS
js.loadJSON
js.loadCSS
js.loadIMG
js.bind
js.getUnick
js.unload
js.loadMulti
js.theme

js.debug

History

10.04.2010
js.load - 2 и 3 параметр func и async deprecated
js.loadJSON - 2 параметром может быть передана строчка 'reload' в этом случае кэш использоваться не будет

25.04.2010
loadMulti - вызывается с get передачей списка файлов

06.05.2010
loadMulti - сделана проверка и деление списка загружаемых файлов на 2 при ошибки. Список делится пока ошибка не исчезнет или длина get запроса не будет меньше 1000

13.05.2010
loadJSON возвращает исходную строку если произошла ошибка при интерпретации её как json и возвращает '' если файл не загружен или пустой
----------------------------------------------------------------
*/

//if (!Function.prototype.bind){ Нам не подходит оригинальная функция. Нужно чтобы в alert выдался код оригинальной функции.. для этого подменяется toString
	Function.prototype.bind = function(object,arguments){
		var that = this;
		var func=function() {
			return that.apply(object,arguments);
		}
		func.toString=function(){
			return that.toString()+'\nbinded: '+object;
		};
		return func;
	}
//}
undefined;
js={};
js.root='';
js.bind=function(object,func){
	return function() {	
		return func.apply(object,arguments) 
	}
}
js.debug=false;
/*Без браузеров никуда*/
//js.IE=(цифра версия браузера 6, 7, 8 или 0)
js.IE=(function (){if(window.opera)return false; var rv = 0;if (navigator.appName == 'Microsoft Internet Explorer') {var ua = navigator.userAgent;var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");if (re.exec(ua) != null)rv = parseFloat(RegExp.$1);}return rv;})();
js.opera=/opera/.test(navigator.userAgent)||window.opera;
js.chrome=/Chrome/.test(navigator.userAgent)
js.webkit=/WebKit/.test(navigator.userAgent);
js.safari=(js.webkit&&!js.chrome);
/**/
js._getTransport=function(){
	var result = !1;
	var actions = [
		function() {return new XMLHttpRequest()},
		function() {return new ActiveXObject('Msxml2.XMLHTTP')},
		function() {return new ActiveXObject('Microsoft.XMLHTTP')}
	];
	for(var i = 0; i < actions.length; i++) {
		try{
			result = actions[i]();
			break;
		} catch (e) {}	
	}
	return result
}
js.last_unick=0;//time последней точки
js.first_unick=new Date().getTime();//Начало отсчёта для всех точек
js.getUnick=function(){//Возвращаем всегда уникальную метку, цифры
	var m=new Date().getTime();
	m-=js.first_unick;//Отсчёт всего времени идёт с момента загрузки страницы в миллисекундах
	var last_unick=js.last_unick||m;
	while(last_unick>=m)m++;
	js.last_unick=m;
	return m;
}

/*js.multi=function(){//Загружает сразу несколько файлов, возвращает массив результата
	var a=arguments;
	var rpaths=[];
	for(var i=0,l=a.length;i<l;i++){
		rpaths.push(a[i]);
	}

}*/

amvar={
	/*
	   Концепция переменной с мульти значениями.  
	   Можно добавлять значения, 
	   убирать значения, смотреть все значения. 
	   Можно добавлять другие значения и наборы значений и убирать значения и наборы значений;
	   После объединения наборы не различаются
		push 
		pop	
		replace
	   each 
	   have - есть такое значени или нет

	   Как скорректировать все данные или создать копию 

	   Задача иметь возможность записывать prop:'asdf' и prop:['asdf','asw'] так
	   Также prop:somevar prop:[somevar,[som1,som3]]
	   Просто так нельзя сохранять переменную.. нужно вызывать amvar.make(); тогда можно сохранять как ссылку

	*/
	/*
	   */
	have:function(nv,v){
		return !this.each(v,function(n){
			if(n==nv)return false;
		});
	},
	is:function(v){
		return (v&&v.constructor==Array);
	},
	make:function(v){
		if(v===undefined){
			v=[];
		}else if(!this.is(v)){
			v=[v];
		}
		return v;
	},
	each:function(elem,callback,group,key){
		return js.each.apply(this,arguments);
	 }
}




js.foroa=function(){//depricated
	return js.forx.apply(this,arguments);
}
js.exec=function(callback,name,context,args,msgs){
	args=args||[];
	try{
		var r=callback.apply(context,args);
		return r;
	}catch(e){
		if(js.IE)em=e.name+':'+e.message;
		else em=e;
		if(js.debug){
			alert('Ошибка в '+name+'\n'+em+'\ncallback:\n'+callback+'\nargs:\n'+args+'\ncontext:'+context+'\nИНФО:\n'+msgs.join('\n'));
			throw e;
		}
	}
}
/*
	fory - Бежим рекурсивно по массиву объектов, а потом по свойствам объектов y - Oo
	forx - Бежим по объекту а потом по его свойствам как по массивам рекурсивно x - multi
	
	fori - Бежим по объекту рекурсивно - for (var i 
	fora - Бежим по массиву рекурсивно (for Array)
	
	foru - Бежим без разницы объекту или массиву нерекурсивно
	
	//Низкий уровень
	foro - Бежим по объекту (for Object)
	forr - Бежим по массиву (for aRRay)
	
	val,key,group,i
	
	undefined везде пропускается, любой return обрывает цикл
*/
js.fory=function(obj,callback,back){
	return js.fora(obj,function(v,i){
		return js.foro(v,function(el,key,group){
			return js.exec(callback,'js.fory',this,[el,key,group,i],['back:'+back]);
		},back);
	},back);
}
js.forx=function(obj,callback,back){//Бежим сначало по объекту а потом по его свойствам как по массивам
	return js.foro(obj,function(v,key){
		return js.fora(v,function(el,i,group){
			return js.exec(callback,'js.forx',this,[el,key,group,i],[back]);//callback,name,context,args,more
		},back);
	},back);
}
js.foru=function(obj,callback,back){//Бежим без разницы объекту или массиву
	if(obj&&typeof(obj)=='object'&&obj.constructor==Array){
		return js.forr(obj,callback,back);//Массив
	}else{
		return js.foro(obj,callback,back);//Объект
	}
}

js.fori=function(obj,callback,back,key,group){//Бежим по объекту рекурсивно
	var r,i;
	if(obj&&typeof(obj)=='object'){
		r=js.foro(obj,function(v,key){
			r=js.fori(v,callback,back,key,obj)
			if(r!==undefined)return r;
		},back);
		if(r!==undefined)return r;
	}else if(obj!==undefined){
		r=js.exec(callback,'js.fori',this,[obj,key,group],[back]);//callback,name,context,args,more
		if(r!==undefined)return r;
	}
}

js.fora=function(el,callback,back,group,key){//Бежим по массиву рекурсивно
	var r,i;
	if(el&&el.constructor===Array){
		r=js.forr(el,function(v,i){
			r=this.fora(v,callback,back,v,i);
			if(r!==undefined)return r;
		},back);
		if(r!==undefined)return r;
	}else if(el!==undefined){//Если undefined callback не вызывается, Таким образом можно безжать по переменной не проверя определена она или нет.
		r=js.exec(callback,'js.fora',this,[el,key,group],[back]);//callback,name,context,args,more
		if(r!==undefined)return r;
	}
}

js.forr=function(el,callback,back){//Бежим по массиву
	if(!el)return;
	var r,i;
	if(back){
		for(i=el.length-1;i>=0;i--){
			r=js.exec(callback,'js.forr',this,[el[i],i],[back]);//callback,name,context,args,more
			if(r!==undefined)return r;
		}
	}else{
		for(i=0;i<el.length;i++){
			r=js.exec(callback,'js.forr',this,[el[i],i],[back]);//callback,name,context,args,more
			if(r!==undefined)return r;
		}
	}
}
js.foro=function(obj,callback,back){//Бежим по объекту
	if(!obj)return;
	var r,ar=[],key,el,fn=back?'pop':'shift';
	for(key in obj){
		if(obj.hasOwnProperty(key))ar.push({key:key,val:obj[key]});
	}
	while(el=ar[fn]()){
		r=js.exec(callback,'js.foro',this,[el.val,el.key],[back]);//callback,name,context,args,more
		if(r!==undefined)return r;
	}
}








js.each=function(elem,callback,back,group,key){//Возвращает undefined или то что было возвращено callback
	var r;//depricated
	if(elem&&elem.constructor===Array){
		if(back){
			for(var i=elem.length-1;i>=0;i--){
				r=this.each(elem[i],callback,back,elem,i);
				if(r!==true)return r;
			}
		}else{
			for(var i=0;i<elem.length;i++){
				r=this.each(elem[i],callback,back,elem,i);
				if(r!==true)return r;
			}
		}
	}else if(elem!==undefined){//Если undefined callback не вызывается, Таким образом можно безжать по переменной не проверя определена она или нет.
		try{
			r=callback.apply(this,[elem,group,key]);
			if(r!==undefined)return r;
		}catch(e){
			if(js.debug)alert('Ошибка в js.each\n'+e+'\nelem:\n'+elem+'\ncallback:\n'+callback+'\nback:\n'+back);
			throw e;
		}
	}
	return true;
}


js.buffer=[];
js.buffer_load=[];
js.bufferOn=function(){
	js.buff=true;
}
js.bufferAdd=function(type,path){
	js.buffer.push({type:type,path:path,toString:function(){return path}});
	js.buffer_load.push(path);
}
js.bufferOff=function(){
	js.buff=false;
	js.loadMulti(js.buffer_load);
	js.buffer_load=[];
	js.forr(js.buffer,function eachbuffer(o){
		try{
			js[o.type](o.path);
		}catch(e){
			if(js.debug)alert('Ошибка js.bufferOff\n'+o.type+' '+o.path+'\n'+e);
		}
	});
}
js.loadMulti=function(path1,path2){//path1,path2,path3,...,func,async
	var rpaths=[];
	var ans={};
	var async=undefined;
	var func=false;
	js.loadJS('core/lib/jquery/jquery.js');
	if(typeof(path1)=='object'){
		var a=path1;
		var func=path2;
	}else{
		a=arguments;
	}
	for(var i=0,l=a.length;i<l;i++){
		var path=a[i];
		
		if(typeof(path)=='function'){
			func=path;
		}else if(typeof(path)=='string'&&js.load[path]===undefined){
			rpaths.push(path);
		}else if(typeof(path)=='boolean'){
			async=path;
		}
	}
	if(async==undefined){
		async=!!func;
	}
	if(!rpaths.length){
		if(func)func();
	/*}else if(rpaths.length==1){
		js.load(rpaths[0],function(data){
			if(func)func()
		},async);*/
	}else{
		try{
		$.ajax({
			url:js.theme('core/infra/load.php')+'?'+encodeURIComponent(rpaths.join('|')),
			timeout:120000,
			async: async,
			type:'get',
			dataType: 'json',
			success: function(ans) {
				if(ans){
					for(var i in ans){
						js.load[i]=ans[i];
					}
				}
				if(func)func();
			},
			error: function(){
				if(func)func();
			}
		});
		}catch(e){//Ошибка могла произойти из-за слишком большого get запроса из-за количества файлов для загрзузки...
			var l=encodeURIComponent(rpaths.join('|').length);
			if(l>1000){
				var l=rpaths.length;
				var newrpaths=[];
				for(var i=0;i<l/2;i++){
					newrpaths.push(rpaths.pop());
				}
				var loaded=-1;
				var f=function(){
					loaded++;
					if(loaded&&func)func();
				}
				this.loadMulti(newrpaths,f,async);
				this.loadMulti(rpaths,f,async);
			}
		};
	}
	return;
}
js.unload=function(path){
	delete this.load[path];
	delete this.loadJSON[path];
	delete this.loadCSS[path];
	delete this.loadJS[path];
	if(this.loadIMG.images){
		delete this.loadIMG.images[path];
	}
}
js.unloadFind=function(pattern){
	for(var path in js.load){
		if(pattern.test(path)){
			this.unload(path);
		}
	}
}
js.theme=function(src){
	if(/^\*+/.test(src)){//Начинаемся со звёздочки... значит настоящий путь надо вычислить этим занимается файл theme.php
		src=src.replace(/^\*+/,'*');//Оставляем одну звёздочку
		src='core/infra/theme.php?'+encodeURIComponent(src);//Это нужно когда путь до php с несколькоими параметрами * передаётся через theme.php Без кодирования путь будет портится, так как автоматически этот путь второй раз кодироватьс яне будет, а надо бы.. 
		//src='core/infra/theme.php?'+src;
	}else{
		//src=encodeURI(src);
		src=src;
	}
	return js.root+src;
}
js.prop=function(obj,prop,def){//Считываем из obj prop если нет вернётся def
	/*
		var p='asdf';
		prop={'have':1}[p];

	   - Считывание в переменную с именем аргумента функции (var не важен)
	   - неизвестного свойства объекта (об этом появляется notice в Консоли ошибок)
	   - имя свойства указано в переменной
	   0.003ms против 2.5ms
	*/
	if(!obj)return def;
	if(obj.hasOwnProperty(prop))return obj[prop];
	return def;
}
js.replacepath=function(oldp,newp){//понадобилось для переноса core/lib/session/session.js в core/plugins/session/session.js (*session/session.js)
	var self=js.replacepath;
	if(newp){
		self[oldp]=newp;
	}else{
		newp=js.prop(self,oldp,oldp);//Считываем из self oldp если нет будет oldp 
	}
	return newp;
}
js.load=function(save_path,func,async) {//func и async deprecated
	if(js.buff){
		js.bufferAdd('load',save_path);
		return;
	}
	/*if(typeof(func)=='string'||typeof(save_path)=='object'){
		return js.loadMulti.apply(this,arguments);
	}else if(save_path===true){
		return '';
	}*/
	save_path=js.replacepath(save_path);

	if(typeof(save_path)!=='string')return;
	if(async==undefined){
		async=!!func;
	}
	
	if(js.load[save_path]!==undefined){
		if(func){
			func(js.load[save_path]);
			return;
		}else{
			return js.load[save_path];
		}
	}
	var load_path=this.theme(save_path);	
	var transport = this._getTransport();
	transport.open('GET', load_path, async);
	transport.setRequestHeader("Content-Type", "text/plain; charset=UTF-8");
	if(async){
		transport.onreadystatechange=function(){
			var state = transport.readyState;
			if(state==4){
				if(transport.status == 200){
					js.load[save_path]=transport.responseText;
				}else{
					js.load[save_path]=null;
				}
				if(func)func(js.load[save_path]);
			}
		}
	}
	transport.send(null);
	if(!async){
		if(transport.status == 200){
			js.load[save_path]=transport.responseText;
		}else{
			js.load[save_path]=null;
		}
		if(func)func(js.load[save_path]);
		return js.load[save_path];
	}
}
js.loadJS = function(path,nocache,call) {//nocache используется для статистики на itlife-studio.ru
	if(js.buff){
		js.bufferAdd('loadJS',path);
		return;
	}
	path=js.replacepath(path);
	var script=false;
	if(this.loadJS[path]==undefined){
		this.loadJS[path]=true;
		if(/^http:/.test(path)){//Это крос доменный запрос
			script=document.createElement('script');
			script.type='text/javascript';
			var head = document.getElementsByTagName("head")[0] || document.documentElement;
			if(call){
				var callback=function(){
					callback=function(){};
					call();
				};
				script.onreadystatechange= function () {     
				   if (this.readystate == 'complete' || this.readystate == 'loaded') {     
					  callback();
				   }
				}
				script.onload = script.onerror = callback 
			}
			script.src=path;
			head.insertBefore(script,head.firstChild);
			head.removeChild(script);
		}else{
			var code=js.load(path);
			this.globalEval(code);
		}
	}
	if(!script&&call)call();
	if(nocache==='nocache')delete js.load[path];//Удалили метку о загрузки файла... хотя метка о выполнение скрипта осталась.
	return;
}

js.globalEval = function(data) {
	if(!data)return;
	// Inspired by code by Andrea Giammarchi
	// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
	
	if(js.IE==false&&js.safari==false){
		window.eval(data);
	}else{
		var head = document.getElementsByTagName("head")[0] || document.documentElement, script = document.createElement("script");
		script.type = "text/javascript";
		script.text = data;
		head.insertBefore( script, head.firstChild );
		head.removeChild( script );
	}
}


/*var s=document.getElementsByTagName('script');
for(var i=0;i<s.length;i++){
	if(s[i].type=='text/data'){
		js.load[s[i].getAttribute('path')]=s[i].text;
		s[i].parentNode.removeChild(s[i]);i-=1;
	}
}*/


js.loadJSON=function(path,r){//load, eval, nocache
	if(js.buff){
		js.bufferAdd('loadJSON',path);
		return;
	}
	path=js.replacepath(path);
	//if(r=='reload'){//depricated
	//	js.unload(path);
	//}
	if(typeof(path)!=='string') return;

	if(r=='load'){//Пофиг на всё просто загружаем снова
		js.unload(path);
	}
	if(r=='eval'){//Нужно заного выполнить оригинал
		delete js.loadJSON[path];
	}

	if(js.loadJSON[path]==undefined){
		var data=js.load(path);
		if(data){
			try{
				data=eval('('+data+')');
			}catch(e){
				if(this.debug)alert('JSON ошибка '+path+'\n'+e+'\n'+data);// Если json не получился будем считать что это просто строка
				data=data;
			}
		}else{
			data='';
		}
		js.loadJSON[path]=data;
	}
	var res=js.loadJSON[path];
	//if(r){//depricated
	//	delete js.loadJSON[path];
	//}
	if(r=='copy'){//Возвращает копию, которую можно изменять, Будут изменяться и все предыдущие полученные объекты. А будущие уже не будут изменяться... 
		delete js.loadJSON[path];
	}
	if(r=='nocache'){
		delete js.load[path];
	}
	return res;
}
js.loadCSS=function(path,link){//Ассинхронно нельзя иначе порядок собъётся
	if(js.buff){
		js.bufferAdd('loadCSS',path);
		return;
	}
	path=js.replacepath(path);
	if(js.loadCSS[path])return;
	js.loadCSS[path]=true;

	if(link){
		var link=document.createElement('link');
		link.rel="stylesheet";
		link.href=js.theme(path);
		var head = document.getElementsByTagName("head")[0] || document.documentElement;
		head.insertBefore(link,head.lastChild);//добавили css на страницу
	}else{
		var code=js.load(path);
		js.style(code);
	}
}
js.style=function(code){
	if(js.style[code])return;//Почему-то если это убрать после нескольких перепарсиваний стили у слоя слетают.. 
	js.style[code]=true;
	var style=document.createElement('style');//создани style с css
	style.type = "text/css";
	if (style.styleSheet){//
		style.styleSheet.cssText=code;
	}else{
		style.appendChild( document.createTextNode(code) );
	}
	var head = document.getElementsByTagName("head")[0] || document.documentElement;
	head.insertBefore(style,head.lastChild);//добавили css на страницу
}
js.loadIMG=function(path,func,func2){//Всегда ассинхронно
	path=js.replacepath(path);
	path=js.theme(path);
	//if(/^\*/.test(path)){
	//path='core/plugins/'+path.replace(/^\*/,'');
	//}
	if(!js.loadIMG.check){
		js.loadIMG.process={};
		js.loadIMG.images={};
		js.loadIMG.listen={};
		js.loadIMG.listen2={};
		js.loadIMG.check=function(path){
			if(js.loadIMG.images[path]!==undefined){
				if(js.loadIMG.images[path]){
					js.loadIMG.listen2[path]=[];
					while(js.loadIMG.listen[path].length){
						var f=js.loadIMG.listen[path].shift();
						f(js.loadIMG.images[path]);
					}
				}else{
					js.loadIMG.listen[path]=[];
					while(js.loadIMG.listen2[path].length){
						var f=js.loadIMG.listen2[path].shift();
						f();
					}

				}
			}
		}
	}
	if(!js.loadIMG.listen[path]){
		js.loadIMG.listen[path]=[];
		js.loadIMG.listen2[path]=[];
	}
	if(func)js.loadIMG.listen[path].push(func);
	if(func2)js.loadIMG.listen2[path].push(func2);
	if(js.loadIMG.process[path]==undefined){
		js.loadIMG.process[path]=1;
		var img=new Image();
		img.onload=function(){
			js.loadIMG.process[path]=2;
			js.loadIMG.images[path]=this;
			img.onload=function(){};//delete в ie6 приводит к ошибке
			js.loadIMG.check(path);
		};
		img.src=path;
		return;
		setTimeout(function(){
			if(js.loadIMG.process[path]!==2){
				js.loadIMG.process[path]=0;
				js.loadIMG.images[path]=false;
				js.loadIMG.check(path);
			}
		},15000);
	}else{
		js.loadIMG.check(path);
	}
}

