(function(){
var DEBUG = true;
//var VER="7b33826940ed7d44e444751e5636cca4";

window.ET={
	/**
	 * 如果没找到指定的dom， 则返回null
	*/
	get: function(el){
		try{
			return el instanceof Element? el: new Element(el);
		}catch(e){
			return null;
		}
	},
	/**
	 * 如果没找到指定的dom， 则返回[]
	*/
	gets: function(tagName){
		var els=[];
		$(tagName).each(function(idx,dom){
			els.push(new Element(dom));
		});
		return els;
	},
	/**
	 * 如果没找到指定的dom， 则返回[]
	*/
	getByJQSelector: function(selector){
		var els=[];
		$(selector).each(function(idx,dom){
			els.push(new Element(dom));
		});
		return els;
	},
	/**
	 * 动态加载js文件, 加载完成并且执行完成后, 回调callback
	 */
	getScript: function(url, callback){
		$.getScript(url, callback);
	},
	onReady: function(fn){
		$(document).ready(fn);
	},
	createDom: function(tagname, props, doc){
		doc = doc || document;
		var el = doc.createElement(tagname);
		if(props){
			for(var k in props){
				el[k] = props[k];
			}
		}
		return el;
	},
	namespace: function () {
		var a = arguments, o = null, i, j, d, rt;
		for (i = 0; i < a.length; ++i) {
			d = a[i].split(".");
			rt = d[0];
			eval("if (typeof " + rt + " == \"undefined\"){" + rt + " = {};} o = " + rt + ";");
			for (j = 1; j < d.length; ++j) {
				o[d[j]] = o[d[j]] || {};
				o = o[d[j]];
			}
		}
	},
	getDom :function(id){
		return document.getElementById(id);
	},
	filterUrl :function (url){
	  if(url.indexOf("://")==-1){
	  	url="http://"+url;
	  }
	  return url;
	},
	checkUrl :function (url){
		if(!url||!url.trim()){
			return false;
		}
		if(url.indexOf("://")!=-1){
			if(url.indexOf("http")!=0&&url.indexOf("https")!=0&&url.indexOf("ftp")!=0){return false;}
		}else{
			url=this.filterUrl(url);
		}
		if(/.*\/\/$/.test(url)){
			return false;
		}
		var check=/((^http)|(^https)|(^ftp)):\/\/([\w-]+\.\w)*/;
		if(check.test(url)){
			return url;
		}
		return false;
	},
	stringToArray :function (str){
		if(!str){
			return [];
		}
		str=str.replace(/;/gm,",");
		str=str.replace(/；/gm,",");
		str=str.replace(/:/gm,",");
		str=str.replace(/：/gm,",");
		str=str.replace(/，/gm,",");
		var strArr=str.split(",");
		
		var strMap={};
		var new_array=[];
		for(var i=strArr.length;i>=0;i--){
			try{
				var strArr_value=strArr[i].trim();
				
				if(strArr_value==""){
					
				}else{
					if(strMap[strArr_value]){
					
					}else{
						new_array.push(strArr_value);
					}
					strMap[strArr_value]=strArr_value;
				}
			}catch(e){}
		}
		return new_array;	
	},
	/**
	 * 浏览器内核标识。依据 navigator.userAgent 判断。
		可用值: 
			safari 
			opera 
			msie 
			mozilla 
		用法
		if ( $.browser.msie )
 			alert( $.browser.version ); 
	 */
	browser :$.browser
};
/**
 * 如果没找到指定的dom， 则返回null
 *  1. var el = new Element("id");
*/
function Element(id){
	
	if(!id){
		throw "cannot find dom by specified id!";
	}
	
	if ( !(this instanceof Element) ){
		return Element(id);
	}
	var jq = typeof(id) == 'string' ? $("#"+id):$(id);
	var dom=jq.get(0);
	if(!dom){
		throw "cannot find dom ["+(typeof(id) == 'string' ? "#"+id : id)+"]"+Element.caller;
	}

	this.dom = dom;
	this.jq = jq;
}

var E = Element;

Element.prototype={
	equals: function(element){
		if(element instanceof Element){
			return this.dom == element.dom;
		}
		else{
			return false;
		}
	},
	setData: function(key,value){
		this.jq.data(key,value);
	},
	getData: function(key){
		return this.jq.data(key)
	},
	removeData: function(key){
		this.jq.removeData(key);
	},
	addClass: function(cls){
		this.jq.addClass(cls);
		return this;
	},
   	focus: function(){
   		this.dom.offsetHeight>0&&this.dom.offsetWidth>0&&this.jq.focus();
   		return this;
   	},
    hide: function(){
   		this.jq.hide();
   		return this;
   	},
   	show: function(){
   		this.jq.show();
   		return this;
   	},
	removeClass: function(cls){
		this.jq.removeClass(cls);
		return this;
	},
	replaceClass: function(oldCls,newCls){
		this.removeClass(oldCls);
		this.addClass(newCls);
		return this;
	},
	setClass: function(cls){
		this.jq.attr("class",cls);
		return this;
	},
	getClass: function(){
		return this.jq.attr("class");
	},
	hasClass: function(cls){
		return this.jq.hasClass(cls);
	},
	removeAttr: function(name){
		this.jq.removeAttr(name);
		return this;
	},
   
	/*---------JQ style interface-----------*/
	val: function(val){
		return val==null || val== undefined ? this.jq.val():this.jq.val(val);
	},
	css: function(key,val){
		return val==null || val== undefined ? this.jq.css(key):this.jq.css(key,val);
	},

	html: function(html){
		return html==null || html==undefined? this.jq.html():this.jq.html(html);
	},
	/*
	 * content 可以是html, dom, Element 
	*/
	append: function(content){
		//如果是Eucita Element， 则取其dom， 否则就是dom或者html
		this.jq.append(content.dom || content);
		return this;
	},
	appendTo: function(content){
		//如果是Eucita Element， 则取其dom， 否则就是dom或者html
		this.jq.appendTo(ET.get(content).dom);
		return this;
	},
	/*
	 * content 可以是html, dom, Element 
	*/
	insertBefore: function(content){
		//如果是Eucita Element， 则取其dom， 否则就是dom或者html
		this.jq.before(content.dom || content);
		return this;
	},
	/*
	 * content 可以是html, dom, Element 
	*/
	insertAfter: function(content){
		//如果是Eucita Element， 则取其dom， 否则就是dom或者html
		this.jq.after(content.dom || content);
		return this;
	},
	/**
	 * 把自己从父节点中删除
	 */
	remove: function(){
		this.jq.remove();
		return this;
	},
	/*
	 * 返回的对象包含两个整形属性：top 和 left。此方法只对可见元素有效。
	*/
	xy: function(){
		return this.jq.offset();
	},
   
	width: function(w){
		//w=0也为false， 故不用w?jq.width(w):jq.width();
		return w==null || w== undefined ? this.jq.width():this.jq.width(w);
	},
   
	height: function(h){
		//h=0也为false， 故不用w?jq.height(h):jq.height();
		return h==null || h== undefined ? this.jq.height():this.jq.height(h);
	},
	/*---------end-----------*/
   
	next: function(){
		return new Element(this.jq.next().get(0));
	},
	prev: function(){
		return new Element(this.jq.prev().get(0));
	},
	childs: function(){
		var els=[];
		this.jq.children().each(function(idx,dom){
			els.push(new Element(dom));
		});
		return els;
	},
	/**
	 * 根据孩子标签获取, 第一级孩子, 返回值是数组
	 */
	childsByTagName: function(tagName){
		var els=[];
		this.jq.children(tagName).each(function(idx,dom){
			els.push(new Element(dom));
		});
		return els;
	},
	/**
	 * 根据后代标签获取, tagName匹配的所有后代, 返回值是数组
	 */
	find: function(tagName){
		var els=[];
		this.jq.find(tagName).each(function(idx,dom){
			els.push(new Element(dom));
		});
		return els;
	},
	parent: function(){
		return new Element(this.jq.parent().get(0));
	},
   
	/**
	 * 返回第一个匹配的parent
	 * tagName: 父节点的tag名字
	 * up: 向上找多少层, 如果不指定, 则直到找到为止 
	 */
	parentByTagName: function(tagname, up){
		if(up){
			var p = this.dom;
			while((p=p.parentNode)&&(--up>=0)){
				if(p.tagName==tagname.toUpperCase()){
					return new Element(p);
				}
			}
			return null;
		}
		return new Element(this.jq.parents(tagname).get(0));
	},
   
	/**
	 * 返回第一个匹配的parent
	 * cls: 父节点的class名字
	 * up: 向上找多少层, 如果不指定, 则直到找到为止 
	 */
	parentByClass: function(cls, up){
		if(up){
			var p = this.dom.parentNode;
			while(!!p && (--up>=0)){
				var cname = p.className;
   
				if(cname){
					var cns = cname.split(" ");
					for (var i=0;i<cns.length;i++){
						if(cns[i]==cls){
							return new Element(p);
						}
					}
				}
   
				p= p.parentNode;
			}
			return null;
		}
   
		return new Element(this.jq.parents("."+cls).get(0));
	},
   
	bind: function(eve, fn){
		
		//此处的event对象， 我们暂时用jq的
		
		//here add a globle event to deal with iframe events in one event
		var event=eve;
		try{
			if(event.indexOf("global")==0){
				event=eve.substring(6);
				ET.globalEvent.add(this,event,fn);
			}
		}catch(e){}
		
		//if(event=="tip"||event=="help"){
		//	Tip.reg(this,fn,event);
		//	return;
		//}
		
		this.jq.bind(event, fn);
		return this;
	},
	/**
	 * 触发事件, 参数
	 *    event：事件名称
	 *    data：指定事件的回调函数的第二个参数
	*/
	trigger: function(event,data){
		this.jq.trigger(event, data);
		return this;
	},
	/*
	 * 1. 如果没有参数，则删除所有绑定的事件。
	 * 2. 如果提供了事件类型作为参数，则只删除该类型的绑定事件。
	 * 3. 如果把在绑定时传递的处理函数作为第二个参数，则只有这个特定的事件处理函数会被删除。
	*/
	unbind: function(eve, fn){
		var event=eve;
		if(!event){
			//如果没有参数，则删除所有绑定的事件。
			this.jq.unbind();
		}else if(!fn){
			//如果提供了事件类型作为参数，则只删除该类型的绑定事件。
			try{
				if(event.indexOf("global")==0){
					event=eve.substring(6);
					ET.globalEvent.unbind(this,event);
				}
			}catch(e){}
			this.jq.unbind(event); 
		}else{
			//如果把在绑定时传递的处理函数作为第二个参数，则只有这个特定的事件处理函数会被删除。
			try{
				if(event.indexOf("global")==0){
					event=eve.substring(6);
					ET.globalEvent.remove(this,event,fn);
				}
			}catch(e){}
			this.jq.unbind(event, fn);
		}
		return this;
	},
	create: function(segment){
		throw "not impl";
	},
	datePicker: function(params){
		this.jq.datePicker(params);
		return this;
	},
	closeDatePicker: function(){
		if(this.jq && this.jq.dpClose){
			this.jq.dpClose();
		}
		return this;
	}
}

/*   
* 我们event对象，仿jq的封装， 故直接用
* event.originalEvent: 浏览器原始event
* event.type: 消息的名字， 例如click
* event.target：消息源
* event.pageX/Y：触发消息的鼠标坐标
* event.preventDefault()：阻止默认行为
* event.stopPropagation()：停止此事件
*/
var Event = function(){
	/*
	//我们event对象，仿jq的封装， 故直接用，暂不定义属性（JQ中都有）
	this.originalEvent
	this.type;
	this.target;
	this.pageX;
	this.pageY;
	this.preventDefault=function(){}
	this.stopPropagation=function(){}
	*/
}

window.Ajax = function(){
	var map={},suffix="";
	
	function clearSid(sid){
		delete map[sid];		
	}

	var filters = [];
	return{
		/**
		 * 用来filter返回的请求, 此方法通过之后, 才进入callback方法, 
		 * 如果filter通过, 必须返回true, 
		 * 如果filter失败, 必须返回false, 
		 */
		addFilter: function(fn){
			filters.push(fn);
		},
		updateSuffix:function(s){
			suffix=s;
		},
		post: function(param){
			param.type="POST";			
			if(!param.data){
				param.data={};
			}
			param.data._method="post";
			return this.request(param);
		},
		put: function(param){
			param.type="POST";
			if(!param.data){
				param.data={};
			}
			param.data._method="put";
			return this.request(param);
		},
		del: function(param){
			param.type="POST";
			if(!param.data){
				param.data={};
			}
			param.data._method="delete";
			return this.request(param);
		},
		get: function(param){
			param.type="POST";
			if(!param.data){
				param.data={};
			}
			param.data._method="get";
			//param.data._rnd=Math.random()+"-"+Math.random();
			return this.request(param);
		},
		/*
		 * param中要包含：
		 *  opt：用户要在回调中使用的参数对象，这个对象ajax request不做任何处理，只在回调的时候返回
		 * 	url (String) : 发送请求地址。
		 * 	data (Map) : (可选) 待发送 Key/value 参数。
		 *  dataType (String) : 预期服务器返回的数据类型。可用值: 
				"xml": 返回 XML 文档，
				"html": 返回纯文本 HTML 信息；包含 script 元素。 
				"script": 返回纯文本 JavaScript 代码。不会自动缓存结果。除非设置了"cache"参数
				"json": 返回 JSON 数据 。
				"jsonp": JSONP 格式。
				"text": 返回纯文本字符串, 默认
		 *  callback有以下三种情况:
		 		complete: (可选)发送成功时回调函数。
		              * XMLHttpRequest, opt, textStatus
		 	  	success: (可选)请求成功后回调函数。参数：服务器返回数据，数据格式。
		              * 指定格式的数据data, opt, textStatus
		 		error: (可选)请求失败时调用
		              * XMLHttpRequest, opt, textStatus, errorThrown
		*/
		request: function(param){
			var sid=UUID.generate("v4");
			
			if(!param.type){
				param.type="POST";
			}

			//if(param.opt){
			var opt=param.opt;
			delete param.opt;
			if(param.complete){
				var complete = param.complete;
				param.complete=function(xhr, textStatus){
					clearSid(sid);

					var ret = true;
					$(filters).each(function(idx, fn){
						ret = fn(xhr);
						return ret;
					});

					if(ret){
						complete.call(param, xhr, opt, textStatus);
					}
				}
			}
			if(param.success){
				var success = param.success;
				param.success=function(data, textStatus){
					clearSid(sid);
					var ret = true;
					$(filters).each(function(idx, fn){
						ret = fn(xhr);
						return ret;
					});

					if(ret){
						try{
							success.call(param, data, opt, textStatus);
						}finally{
							//EventBus.trigger("guess-error", data);
						}
					}
				}
			}

			var error = param.error;
			param.error=function(xhr, textStatus, errorThrown){
				var mess;
				try{
					mess = xhr.responseText?eval("("+xhr.responseText+")"):{};
				}catch(ex){
					mess = xhr.responseText;
				}
				try{
					if(error){
						error.call(param, mess, xhr, opt, textStatus, errorThrown);
					}
				}finally{
					clearSid(sid);
					EventBus.trigger("system-error", mess);
				}
			}
				
			if(!param.complete){
				param.complete=function (){
					clearSid(sid);
				}
			}
			//}
			if(param.data){
				var pd = param.data;

				//很久以前为了达到为null或者是undefined的属性不发给后台的目的而做的hack!
				//有时间一定去去掉! param.data应该就是要发送的数据! 不发的不要加进来
				if(pd.tagName != 'FORM'){
					for(var name in pd){
						if(pd[name] == null || pd[name] == 'undefined' || (pd[name] instanceof Array && pd[name].length==0)/*空数组作为参数是不会发送的, 要重写为''*/){
							pd[name]="";
						}
					}
				}
			}
			param.url+=suffix;
			var xhr = $.ajax(param);
			map[sid]=xhr;
			return sid;
		},
		abort: function(id){
			var xhr = map[id];
			//垃圾回收
			map[id] = undefined;
			try{
				delete map[id];
			}catch(ex){
			}

			if(xhr){
				xhr.abort();
				return true;
			}
		},
		debug:function(){
			for(var k in map){
				ET.logger.log(k+"="+map[k]);
			}
		}
	}
}();

var Logger=function(id){
	var mc;
	var id = id || "messagelog";
	var info=true, error=true;

	return {
		init: function(dom){
			mc = ET.get(id);
			if(!mc){			
				ET.get(dom || document.body).append("<div id='"+id+"'><b>Message log:</b></div>");
				mc = ET.get(id);
			}
		},
		log: function(){
			if(!mc){
				this.init();
			}
			if(info){
				mc.append("<br>");

				var args = Array.prototype.slice.call(arguments);
				mc.append(args.join(", "));
			}
		},
		error: function(){
			if(!mc){
				this.init();
			}
			if(error){
				mc.append("<br>");
				var args = Array.prototype.slice.call(arguments);
				mc.append(args.join(", "));
				
				if(DEBUG){
					alert(mc.html().replace(/<br>/gm,"\n"));
				}
			}
		}
	}
};

var log = ET.logger = new Logger("messagelog"); 

/*--------UUID-----------*/
/*
 *	Source: Javascript mailing list
 *	Source URL: http://www.techlists.org/archives/web/javascript/2006-07/msg00004.shtml
 * 	Date: 2008-06-10
 *	Author: Gang Li
 */
var UUID = {generate:function (type) {
	switch ((type || "v4").toUpperCase()) {
	  case "V4":
		var tl = this._randomHexString(8);
		var tm = this._randomHexString(4);
		var thav = "4" + this._randomHexString(3);
		var cshar = Math.randomInt(0, 255);
		cshar = ((cshar & ~(1 << 6)) | (1 << 7)).toString(16);
		var csl = this._randomHexString(2);
		var n = this._randomHexString(12);
		return "HId-o-"+(tl + "-" + tm + "-" + thav + "-" + cshar + csl + "-" + n);
	  case "NIL":
		return "HId-o-"+("00000000-0000-0000-0000-000000000000");
	}
	return (null);
}, _randomHexString:function (len) {
	var random = Math.randomInt(0, Math.pow(16, len) - 1);
	return (random.toString(16).pad(len, "0", String.PAD_LEFT));
}};
String.PAD_LEFT = 0;
String.PAD_RIGHT = 1;
String.PAD_BOTH = 2;
String.prototype.pad = function (len, pad, type) {
	var string = this;
	var append = new String();
	len = isNaN(len) ? 0 : len - string.length;
	pad = typeof (pad) == "string" ? pad : " ";
	if (type == String.PAD_BOTH) {
		string = string.pad(Math.floor(len / 2) + string.length, pad, String.PAD_LEFT);
		return (string.pad(Math.ceil(len / 2) + string.length, pad, String.PAD_RIGHT));
	}
	while ((len -= pad.length) > 0) {
		append += pad;
	}
	append += pad.substr(0, len + pad.length);
	return (type == String.PAD_LEFT ? append.concat(string) : string.concat(append));
};

Math.randomInt = function (min, max) {
	if (!isFinite(min)) {
		min = 0;
	}
	if (!isFinite(max)) {
		max = 1;
	}
	return (Math.floor((Math.random() % 1) * (max - min + 1) + min));
};
//alert("UUID v4: " + UUID.generate("v4") + "\nNil UUID: " + UUID.generate("nil"));
//UUID.generate("v4")
//40ed7d44
//7b338269

/*对原型进行扩展*/

/**
	对Array原型添加了几个方法：
	indexOf 索引数组中的元素
	insertBefore 把新元素插入到目标元素之前
	remove 从数组中删除元素
*/

Array.prototype.indexOf = function (o) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] == o) {
			return i;
		}
	}
	return -1;
};

Array.prototype.insertBefore = function (o,o2) {
	var i = this.indexOf(o2);
	if (i == -1) {
		this.push(o);
	} else {
		this.splice(i, 0, o);
	}
};

Array.prototype.remove = function (o) {
	var i = this.indexOf(o);
	if (i != -1) {
		this.splice(i, 1);
	}
};

Array.prototype.each = function (fn) {
	$(this).each(fn);
};

/**
	给Function的原型添加了两个方法
	createDelegate（obj，args，appendArgs） obj 来改变function的this，args为传入的参数
	defer 封装了setTimeout 
*/
Function.prototype.createDelegate = function(obj, args, appendArgs){
        var method = this;
        return function() {
            var callArgs = args || arguments;
            if(appendArgs === true){
                callArgs = Array.prototype.slice.call(arguments, 0);
                callArgs = callArgs.concat(args);
            }else if(typeof appendArgs == "number"){
                callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
                var applyArgs = [appendArgs, 0].concat(args); // create method call params
                Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
            }
            return method.apply(obj || window, callArgs);
        };
};
Function.prototype.defer = function(millis, obj, args, appendArgs){
      var fn = this.createDelegate(obj, args, appendArgs);
      if(millis){
          return setTimeout(fn, millis);
      }
      fn();
      return 0;
};
/**
	给String的原型添加了两个方法
	trim去除前后空格
*/
String.prototype.trim=function(){return this.replace(/(^\s*)|(\s*$)/g, "");};
}());
