
//var PJs = {};

//var PCss = {};

//function UnpackCss(css){document.write('<style type="text\/css">/*'+css+'<\/style>');}

//function UnpackJs(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}

(function(){
var DEBUG = false;

if(DEBUG){
	Log.init('./',10,{
		width : 850,
		height : 600
		});	
	}
else{
	Log = function(){return false}
	}/*
 * TODO:将PyPaJs作为外部项目引入此项目,与js读取一个配置文件
 * TODO:将JsLog作为外部项目引入此项目,增加输出调试信息
 */


//document.domain = 'pplive.com';

var Config = {};
//发布到window命名空间下的名称
Config.PUBLISHNAME = 'JsLoader';
//最大存储userdata数据个数(0-9文件为保留使用文件)
Config.MAXSTORE = 30;
Config.INDEXSTARTWITH = 10;
//存储项前缀
Config.DATAPREFIX = 'userdata';
//版本信息存储文件 前缀+索引
Config.VERSIONFILENAME = Config.DATAPREFIX + 0;
//索引表文件 前缀+索引
Config.INDEXTABLENAME = Config.DATAPREFIX + 1;
//默认请求文件的压缩等级
Config.DEFAULTCOMPRESSLEVEL = 2;

//Loader的版本,主要用于控制客户端存储的文件版本
var VERSION = 2;

// Figure out what browser is being used by jQuery
var userAgent = navigator.userAgent.toLowerCase();
var browser = {
    version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
    safari: /webkit/.test( userAgent ),
    opera: /opera/.test( userAgent ),
    msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
    mozilla: /mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)
};
var isIE = browser.msie;
var isFF = browser.mozilla;

//数组和HashTable遍历函数
function $each(a,fn){
	//Array
	if(a instanceof Array){
		for(var i=0,ilen=a.length;i<ilen;i++){
			fn(a[i],i);
			}
		return false;
		}
	//HashTable
	else if(a instanceof Object){
		for(var p in a){
			fn(a[p],p);
			}
		return false
		}	
	}
//var tosavejs = PJs;

//var tosavecss = PCss;


var UserData = new function(){
	if(isIE){
		Log('debug','UserData::init:isIE');
		document.documentElement.style.behavior = "url('#default#userData')"; 
		document.documentElement.addBehavior("#default#userdata");
		}		

	//存储名字为k,值为v的userdata,成功返回存储的值,失败返回false	
	this.set = function(k,v){
		v = v + '';
		if(isIE){
			try{
				Log('debug','Enter UserData::set in IE');
				Log('info','Key:',k);
				Log('info','Value length:',v.length);
				var DE = document.documentElement;
				DE.load(k);
				DE.setAttribute("value", v);
				//DE.expires = new Date(EXPIREDATE).toUTCString();
				DE.save(k);
				Log('info','Set Succeed');
				return true;
				}
			catch(e){
				Log('error',e,'Error occur in UserData::set');
				//alert(e)
				return false;				
				}
			}
		else if(isFF){//for firefox 2.0+
			//暂时不在firefox下使用此功能,已在loader中实现
			//return false;
			try{
				window.globalStorage[document.domain][k] = v;
				return true;
				}
			catch(e){
				return false;
				}
			}
		else{
			//alert("当前浏览器不支持userdata或者sessionStorage特性")
			return false;
			}
		//not even here
		return false;		
		};
	
	//读取名字为k的userdata,返回k的值,若k不存在,返回null	
	this.get = function(k){
		Log('debug','Enterf UserData::get:',k);
		if(isIE){
			try{
				var DE = document.documentElement;
				DE.load(k);
				var value = DE.getAttribute("value");
				Log('info','Get Value:',value.length);
				return value;
				}
			catch(e){
				return null;
				}
			}
		else if(isFF){//for firefox 2.0+
			try{
				return window.globalStorage[document.domain][k].value;
				}
			catch(e){
				return null;
				}
			}
		else{
			//alert("当前浏览器不支持userdata或者sessionStorage特性")
			return null;
			}
		//not even here
		return null;		
		};
	
	//删除名字为k的userdata,成功返回true,否则返回false	
	this.del = function(k){
		if(isIE){
			try{
				var DE = document.documentElement;
				DE.load(k);
				DE.setAttribute("value", '');
				//DE.expires = new Date(315532799000).toUTCString();
				DE.save(k);
				return true;
				}
			catch(e){
				return false;
				}
			}
		else if(isFF){//for firefox 2.0+
			try{
				delete window.globalStorage[document.domain][k];
				return true;
				}
			catch (e){
				return false;
				}
			}
		else{
			//alert("当前浏览器不支持userdata或者sessionStorage特性")
			return false;
			}		
		};
	};

function IndexTable(tableName){
	Log('debug','Create IndexTable instance');
	var _tbname = tableName;
	var _tbstr = UserData.get(tableName);
	var _rows = [];
	if(_tbstr){
		_initRows_();
		}	
	
	function _initRows_(){
		Log('debug','Enter IndexTable::_iniRows_');
		var tmpRows = DataTable.LineSplit(_tbstr);
		$each(tmpRows,function(a,i){
			tmpRows[i] = DataTable.RowSplit(a);
			});
		$each(tmpRows,function(a,i){
			Log('info','('+i+')',a[0],a[1],a[2]);
			});
		_rows = tmpRows;
		}
	
	function _wrapKey(key){
		return '{' + key + '}';
		}
	
	function _compareUpdateTime(time1,time2){
		time1 = parseInt(time1,10);
		time2 = parseInt(time2,10);
		if(time1<time2){
			return -1;
			}
		if(time1 == time2){
			return 0;
			}
		if(time1 > time2){
			return 1;
			}		
		}
	
	function _sync(){
		var tmpRows = [];
		$each(_rows,function(a,i){
			tmpRows.push(DataTable.RowJoin(a));
			});
		var tmpSaveStr = DataTable.LineJoin(tmpRows);
		if(!tmpSaveStr){
			tmpSaveStr = ' ';
			}	
		UserData.set(_tbname,tmpSaveStr);
		}	
	
	this.deleteAll = function(){
		_rows = [];
		_sync();
		};
	
	this.insert = function(key,saveKey){
		key = _wrapKey(key);
		_rows.push([key,saveKey,new Date().getTime()]);
		_sync();
		};
	this.getSaveKey = function(key){
		Log('debug','Enter IndexTable::getSaveKey');
		Log('info','Arguments->key:',key);
		key = _wrapKey(key);
		Log('info','WrapedKey:',key);
		var saveKey = null;
		$each(_rows,function(a,i){
			if(a[0] == key){
				a[2] = new Date().getTime();
				saveKey = a[1];
				_sync();
				}
			});
		Log('info','Get Save Key:',saveKey);	
		return saveKey;	
		};
	this.getNewSaveKey = function(){
		Log('debug','Enter IndexTable::getNewSaveKey');
		var tmpIndex = null;
		var tmpLastTime = null;
		var tmpSaveKey = null;
		//Store is full kit some item
		if(_rows.length >= (Config.MAXSTORE-Config.INDEXSTARTWITH)){
			$each(_rows,function(a,i){
				if(!tmpLastTime || _compareUpdateTime(a[2],tmpLastTime)<0){
					tmpLastTime = a[2];
					tmpIndex = i;
					tmpSaveKey = a[1];
					}
				});
			if(tmpIndex !== null){
				_rows[tmpIndex] = ''; 
				return tmpSaveKey;
				}	
			return false;
			}
		var keyArr = [];
		$each(_rows,function(a,i){
			var saveKey = parseInt(a[1],10);
			keyArr[saveKey] = true;
			});
		for(var i=Config.INDEXSTARTWITH,ilen=Config.MAXSTORE;i<=ilen;i++){
			if(!keyArr[i]){
				Log('info','Get A New Save Key:',i);
				return i;
				}
			}	
		};		
	}

//将所有存入行中的数据的空格进行encode
var DataTable = new function(){};
DataTable.RowJoin = function(arr){
	var tmpArr = [];
	$each(arr,function(a,i){
		tmpArr.push(encodeURIComponent(a));
		});
	return tmpArr.join(' ');
	};

//将数据中的空格decode
DataTable.RowSplit = function(line){
	var tmpArr = line.split(' ');
	$each(tmpArr,function(a,i){
		tmpArr[i] = decodeURIComponent(a);
		});
	return tmpArr;	
	};

//将各行连接成一个字符串
DataTable.LineJoin = function(arr){
	var tmpArr = [];
	$each(arr,function(a,i){
		if(a){
			tmpArr.push(a);
			}
		});
	return tmpArr.join('\n');
	};
	
//将字符串转为成行
DataTable.LineSplit = function(str){
	return str.split('\n');
	};
	

//版本信息 类
/*
 * 版本信息文件格式
  	// 	VersionInfo.FLAG\n	\\
 	\\ 	ver				 	//
 */	
function VersionInfo(infoName){
	var _infoName = infoName;
	var _infoStr = UserData.get(infoName);
	//var _lines = _infoStr.split('\n')
	this.getVersion = function(){
		if(!_infoStr || _infoStr.indexOf(VersionInfo.FLAG) != 0){
			return false;
			}
		var lines = _infoStr.split('\n');	
		var version = parseInt(lines[1],10);
		return version;
		};
	this.setVersion = function(ver){
		var verStr = VersionInfo.FLAG + '\n' + ver;
		UserData.set(_infoName,verStr);
		};	
	this.versionCompare = function(){
		
		};	
	}
VersionInfo.FLAG = '%^&var#$;*@;!#_PPLIVE_USERDATAFILE_VERSION_1.1';			function CacheControl(){
	var versionInfo = new VersionInfo(Config.VERSIONFILENAME);
	var ver = versionInfo.getVersion();
	if(!ver || ver != VERSION){
		Log('warn','Version Not Match');
		//indexTable.deleteAll();
		_flush();
		versionInfo.setVersion(VERSION);
		}
	var indexTable = new IndexTable(Config.INDEXTABLENAME);	
	
	/*
	 * TODO : 在dataTable中增加saveKeys接口,获取所有savekey
	 * 完成此同步功能
	 */
	function _sync(){
		
		}
	
	//清空所有userdata file中的内容(包括0-9号保留文件)
	function _flush(){
		var tmpKey;
		for(var i=0,ilen=Config.MAXSTORE;i<=ilen;i++){
			tmpKey = Config.DATAPREFIX + i;
			UserData.del(tmpKey);
			}
		}
		
	this.get = function(url){
		Log('debug','Enter CacheControl::get');
		Log('info','Arguments->url:',url);
		var savekey = indexTable.getSaveKey(url);
		if(savekey!==0 && !savekey){
			return false;
			}
		var realKey = Config.DATAPREFIX + savekey;
		var cache = UserData.get(realKey);
		return cache;	
		};
					
	this.set = function(url,cache){
		Log('debug','Enter CacheCotrol::set');
		Log('info','Arguments->url',url);
		var saveKey = indexTable.getNewSaveKey();
		Log('info','Get SaveKey From IndexTable:',saveKey);
		if(!saveKey){
			return false;
			}
		var realKey = Config.DATAPREFIX + saveKey;
		Log('info','Produce realKey:',realKey);
		Log('info','Cache Length To Save:',cache.length);
		var result = UserData.set(realKey,cache);
		Log('info','Save Result:',result);
		if(result){
			indexTable.insert(url,saveKey);
			}	
		};
		
	this.testfn = function(){
		UserData.set('test','kkkkkkkkddddd');
		};
		
	this.testfn2 = function(){
		alert(UserData.get('test'));
		};		
	}var Loader = new function(){
	//在安全模式下将不使用loader的缓存加载功能
	var _safeMode = 0;
	//压缩等级
	var _compressLevelTable = {
		'{0}' : '',
		'{1}' : '[min]',
		'{2}' : '[packed]'
		};
	var _compressLevel = Config.DEFAULTCOMPRESSLEVEL;
	
	var _cacheControl = null;
	
	function _cacheControlInit(){
		_cacheControl = new CacheControl();
		}
	
	//根据压缩等级,将url转为响应文件的实际url
	//e.g http://res.pplive.com/a.js -> http://res.pplive.com/a[packed].js
	function _getRequestUrl(url){
		function _getCompressLevel(level){
			var tmpLevel = _compressLevelTable['{'+level+'}'];
			return tmpLevel ? tmpLevel : '';
			}
		var tmpUrlArray = url.split('.');
		var tmpFileExt = tmpUrlArray.pop();
		var mark = _getCompressLevel(_compressLevel);
		if(mark){
			tmpUrlArray.push(mark);
			}
		tmpUrlArray.push(tmpFileExt);
		return tmpUrlArray.join('.');
		}
		
	function _outjs(reqUrl,direct){
		//组织输出script标签
		function _formatScriptTag(reqUrl){
			var tmpArr = ['<script type="text/javascript" '];
			tmpArr.push('src="'+reqUrl+'" ');
			if(!_safeMode&&!direct){
				tmpArr.push('onload="'+
					Config.PUBLISHNAME+
					'.scriptLoaded(this);" ');
				tmpArr.push('onreadystatechange="'+
					Config.PUBLISHNAME+
					'.scriptLoaded(this);" ');
				}
			tmpArr.push('><\/script>');
			return tmpArr.join('');	
			}
		//var reqUrl = _getRequestUrl(url);
		document.write(_formatScriptTag(reqUrl));		
		};
	
	//Boolean direct 是否直接输出url 
	this.js = function(url,direct){
		Log('debug','Enter loader:js');
		Log('info','Arguments->url:',url);
		if(direct){
			Log('info','Direct Output the url');
			_outjs(url,true);
			return false;
			}
		var reqUrl = _getRequestUrl(url);
		Log('info','reqUrl:',reqUrl);
		if(_safeMode){//如果是安全模式直接输出标签
			_outjs(reqUrl);
			return false;
			}
		if(!_cacheControl){_cacheControlInit()}	
		var cache = _cacheControl.get(reqUrl);
		Log('info','cache:',cache&&cache.length);
		if(cache){
			document.write(
				'<script type="text/javascript">' +
					cache +
				'<\/script>'
				);			
			}
		else{
			_outjs(reqUrl);
			}		
		};
		
	this.css = function(url){
		var reqUrl = _getRequestUrl(url);
		if(_safeMode){//如果是安全模式直接输出标签
			_outjs(reqUrl);
			return false;
			}
		if(!_cacheControl){_cacheControlInit()}		
		var cache = _cacheControl.get(reqUrl);
		if(cache){
			UnpackCss(cache);
			/*
			document.write(
				'<style  type="text/css">' +
				cache +
				'<\/style>')
			*/				
			}
		else{
			_outjs(reqUrl);
			}		
		};
	
	//打开/关闭安全模式	flag为true,打开安全模式,flag为false,关闭安全模式
	this.switchSafeMode = function(flag){
		flag = !!flag;
		_safeMode = flag;
		};
		
	//设置请求文件的压缩等级
	this.setCompressLevel = function(level){
		_compressLevel = level;
		};
	
	//供压缩文件将压缩后的代码存入缓存中
	//在script的onload事件触发时将缓存存入本地文件	
	var _temp;
	this.setTemp = function(temp){
		Log('debug','Enter Loader::setTemp');
		if(_safeMode){
			return false;
			}			
		_temp = temp;
		Log('info','set temp:',_temp.fileName);
		};
		
	this.scriptLoaded = function(sc){
		Log('debug',sc.readyState,sc.src);
		if(_safeMode){
			return false;
			}
		if(!_temp || !_temp.fileName){
			return false;
			}
		var url,fileName;
		if(isFF || (isIE && sc.readyState == 'complete')){
			Log('debug','Begin doing scriptLoaded');
			url = decodeURIComponent(sc.src);
			fileName = _temp.fileName;
			Log('info','url:',url);
			Log('info','fileName',fileName);
			if(url.indexOf(fileName) == -1){
				Log('info','Url do not match the filename');
				return false;
				}
			_cacheControl.set(url,_temp.cache);		
			_temp.cache = '';
			_temp = null;			
			return false;
			}
		};		
		
	this.testfn = function(){
		_cacheControlInit();
		_cacheControl.testfn();
		};	
	
	this.testfn2 = function(){
		_cacheControl.testfn2();
		};	
		
		
		
		
		
		
		
		
		
		
		
		
				
	};window[Config.PUBLISHNAME] = Loader;
window.UserData = UserData;})();