(function(){
var s = navigator.userAgent;
var isIE = s.indexOf("MSIE")>=0;
var isGecko = s.indexOf("Gecko")>=0;
var isFirefox = s.indexOf("Firefox")>=0;
var isOpera = s.indexOf("Opera")>=0;
var isSafari = s.indexOf("Safari")>=0;

var Browser = [];
if (isIE){Browser.push("MSIE");Browser.isIE = true;}
if (isGecko){Browser.push("Gecko");Browser.isGecko = true;}
if (isFirefox){Browser.push("Firefox");Browser.isFirefox = true;}
if (isOpera){Browser.push("Opera");Browser.isOpera = true;}
if (isSafari){Browser.push("Safari");Browser.isSafari = true;}

var cpoint = function(x,y){
	return {
		0 : x,1 : y,'x':x,'y' : y,'left':x,'top':y,
		toString : function(){return "("+x+","+y+")";}	
	}
}
var nullpoint = cpoint(-9999,-9999);
var cdims = function(w,h){
	return {
		0 : w,1 : h,'w':w,'h' : h,'width':w,'height':h,
		toString : function(){return "["+w+","+h+"]";}	
	}
}

var canInsertDom,insertDom,insertHTML,createRange,addRange,each,clear;
each = function(dom,handle){
	var n = dom.childNodes.length;
	for(var i=0;i<n;i++) 
	{
		var ch = dom.childNodes[i];
		if (ch.tagName){ if(handle(ch,i)===false) return ch;}
	}
}
clear = function(el){
	var n = el.childNodes.length;
	for(var i=0;i<n;i++){
		el.removeChild(el.firstChild);
	}
}
createRange = function(tags){
	var ret = [];
	for (var i=0; i<tags.length ; i++ )
	{
		ret.push(document.createElement(tags[i]));
	}
	return ret;
}
var createRanges = function(){
    var ret = [],n = arguments.length;
	for (var i=0; i<n ; i++ )
	{
		ret.push(document.createElement(arguments[i]));
	}
	return ret;
}
addRange = function(p,range){
	for (var i=0; i<range.length ; i++ )
	{
		p.appendChild(range[i]);
	}
}

if (window.HTMLElement){
	canInsertDom = function(p){
		var tag = p.tagName.toLowerCase();
		switch(tag){
            case "area":case "base":case "basefont":case "col":case "frame":case "hr":case "img":case "br":case "input":case "isindex":case "link":case "meta":case "param":
            return false;
        }
        return true;
	}
	insertDom = function(elem,ins,sWhere){
		if (!sWhere) elem.appendChild(ins); 
		sWhere = String(sWhere).toLowerCase();
		switch (sWhere) {
			case "beforebegin":
				elem.parentNode.insertBefore(ins, elem);
				break;
			 case "afterbegin":
				elem.insertBefore(ins, elem.firstChild);
				break;
			 case "beforeend":
				elem.appendChild(ins);
				break;
			 case "afterend":
				elem.parentNode.insertBefore(ins, elem.nextSibling);
				break;
		 }
	}
	insertHTML = function(elem,sHTML,sWhere){
		var df; var r = this.ownerDocument.createRange();
		
		sWhere = sWhere?String(sWhere).toLowerCase() : "afterend";
		switch (String(sWhere).toLowerCase()) {
			 case "beforebegin":
				r.setStartBefore(elem);
				df = r.createContextualFragment(sHTML);
				elem.parentNode.insertBefore(df, elem);
				break;
			 case "afterbegin":
				r.selectNodeContents(elem);
				r.collapse(true);
				df = r.createContextualFragment(sHTML);
				elem.insertBefore(df, elem.firstChild);
				break;
			 case "beforeend":
				r.selectNodeContents(elem);
				r.collapse(false);
				df = r.createContextualFragment(sHTML);
				elem.appendChild(df);
				break;
			 case "afterend":
				r.setStartAfter(this);
				df = r.createContextualFragment(sHTML);
				elem.parentNode.insertBefore(df, elem.nextSibling);
				break;
		 }
		 r.detach();
	}
}else if (window.event){
	canInsertDom = function(node) {return node.canHaveChildren();}
	insertDom = function(elem,ins,sWhere){
		if (!sWhere) elem.appendChild(ins); 
		elem.insertAdjacentElement(sWhere,ins);
	}
	insertHTML = function(elem,ins,sWhere){
		sWhere = sWhere || "afterend";
		elem.insertAdjacentHTML(sWhere,ins);
	}
}else{
	canInsertDom=insertDom=insertHTML= function(){
		throw "Not implement!your browser is not attached!";
	}
}

var hasCss,addCss,removeCss,toggleCss,getCss,setCss,getStyle,setStyle,getOpacity,setOpacity,getXY,setXY,getDims,setDims,getZ,setZ;
hasCss = function(nd,css){
	var reg = new RegExp('(\\s|^)'+css+'(\\s|$)');
	return reg.test(nd.className);
}
addCss = function(nd,css){
	if(css && !new RegExp('(\\s|^)'+css+'(\\s|$)').test(nd.className))nd.className+=" " + css;
}
removeCss = function(el,css){
	var strCss = el.className;
	if (!css || !strCss) return this;
	var Csss = strCss.split(' ');
	var j = Csss.length;
	var rs  = "";
	for(var i = 0;i<j;i++){
		if(Csss[i]==css)continue;
		rs += ' ' + Csss[i];
	}
	el.className=rs;
}

toggleCss = function(el,css){
	if (new RegExp('(\\s|^)'+css+'(\\s|$)').test(el.className)) this.removeCss(css);
	else el.className+=" " + css;
	return this;
}
setStyle = function(nd,name, value){
	if(typeof name == "string"){
		if(name == 'opacity') setOpacity(nd,value);
		else nd.style[name] = value;
    }else{
		for(var n in name)setStyle(nd,n, name[n]);
    }
}
getCss = function(el){
	return el.style.cssText;
}
setCss = function(el,cssText){
	el.style.cssText = cssText;
}
	
setXY = function(el,pos,abPos,s){
	var abPos = abPos ? abPos : getXY(el,s);
	if(!abPos) return false;
	if(getStyle(el,"position") == "static")setStyle(el,"position", "relative");
	
	var x = (el.offsetLeft||0) + pos[0] - abPos[0];el.style.left = x + "px";
	var y = (el.offsetTop||0) + pos[1] - abPos[1];el.style.top = y + "px";
	//if(s)alert(el.offsetLeft);
}
getDims = function(el){
	return cdims(el.clientWidth,el.clientHeight);
}
setDims = function(el,w,h){
	if(w.w!==undefined) {h = w.h;w = w.w;};
	var css  = {
		width : w + "px",
		height : h + 'px'
	}
	var stroll = getStyle(el,'overflow');
	if (stroll!=='auto' && stroll!=='stroll') css.overflow = "auto";
	setStyle(el,css);
}
getZ = function(el){
	var p = el,last;
	while(p){
		var pos = getStyle(p,'position');
		if (pos=='absolute' || pos=='relative'){
			last = p;
		}
		p = p.offsetParent;
	}
	if (last){return getStyle(last,'zIndex');}
	return;
}
setZ = function(el,z){
	var p = el,last;
	while(p){
		var pos = getStyle(p,'position');
		if (pos=='absolute' || pos=='relative'){
			last = p;
		}
		p = p.offsetParent;
	}
	if (last){setStyle(last,'zIndex',z);return true;}
	return false;
}
if (isIE){
	getOpacity = function(el){
		var value = el.style.filter || '';
		if (value=( value.match(/alpha\(opacity=(.*)\)/) ) )
			if (value[1]) return parseFloat(value[1] / 100);
		return 1.0;
	}
	setOpacity = function(el,value){
		var filter = el.style.filter || "";
		if (value == 1 || value === '') {
			el.style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
			return el;
		} else if (value < 0.00001) value = 0;
		el.style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +'alpha(opacity=' + (value * 100) + ')';
		return this;
	}
	getStyle = function(el,name){
		if (name==='opacity') return getOpacity(el,name);
		if(name == 'float')name = "styleFloat";
		if(v = el.style[name])return v;
        else return el.currentStyle[name];
        return null;
	}
	getXY = function(el){
		if(el.parentNode === null || el.style.display == 'none')return [-99999,-99999];                  
		b = el.getBoundingClientRect();
		var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
		var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
		return cpoint(b.left + scrollLeft, b.top + scrollTop);
	}
}else {
	var propCache = {};
	getOpacity = function(el){
		return parseFloat(el.style.opacity) || parseFloat(el.style.MozOpacity) || 1;
	}
	setOpacity = function(el,value) {
		el.style.opacity = el.style.MozOpacity = (value == 1) ? 0.999999 :(value === '') ? '' : (value < 0.00001) ? 0 : value;
	}
	getStyle = function(el,name){
		if(name == 'float')name = "cssFloat";
		if(v = el.style[name])return v;
        if(cs = document.defaultView.getComputedStyle(el, "")){
			if(!(camel = propCache[name])) camel = propCache[name] = name.replace(/([A-Z])/g,"-$1").toLowerCase();
            return cs && cs.getPropertyValue(camel);
        }
        return null;
	}

	if (isSafari || isOpera){
		getXY = function(el,s){
			if(el.parentNode === null || el.style.display == 'none')return false;   
			var p = null,x,y,b;     
			x = el.offsetLeft, y = el.offsetTop;  
			
			p = el.offsetParent;    
			
			if (parent != el) {
				
				while (p && p!=document.body && p!= document.documentElement) { 
					
					x += p.offsetLeft; 
					y += p.offsetTop; 
					
					p = p.offsetParent;
				}  
			} 
			
			if (isOpera || ( isSafari && el.style.position === 'absolute' )) { 
				x -= document.body.offsetLeft;
				y -= document.body.offsetTop;         
			}    
			
			if (el.parentNode)p = el.parentNode; else p = null;
			while (p && p != document.body && p != document.documentElement) { // account for any scrolled ancestors
				x -= parent.scrollLeft || 0;
				y -= parent.scrollTop || 0;
				//alert([parent.scrollLeft,parent.scrollTop]);
				p = p.parentNode;
				
			}
			
			return cpoint(x,y);
		}
		
	}else if (isGecko){
		getXY = function(el){
			
			if(el.parentNode === null || el.style.display == 'none')return false;                  
			b = el.getBoundingClientRect();
			var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
			var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
			return cpoint(b.left + scrollLeft, b.top + scrollTop);

			if(el.parentNode === null || el.style.display == 'none')return false;   
			var p = null,x,y,b;     
			b = document.getBoxObjectFor(el); 
			var borderLeft = (el.style.borderLeftWidth)?parseInt(el.style.borderLeftWidth):0; 
			var borderTop = (el.style.borderTopWidth)?parseInt(el.style.borderTopWidth):0; 
			x = b.x - borderLeft, y = b.y - borderTop;
						
			if (el.parentNode)p = el.parentNode; else p = null;
			while (p && p.tagName != 'BODY' && p.tagName != 'HTML') { // account for any scrolled ancestors
				x -= parent.scrollLeft;
				y -= parent.scrollTop;
				p = p.parentNode;
			}
			return cpoint(x,y);
		}
	}
}

//统一事件处理
var addEvent,removeEvent,notifyEvent
if (window.attachEvent){
	addEvent = function(target,t,f){target.attachEvent('on' + t, f);}
	removeEvent = function(target,t,f){target.detachEvent('on' + t, f);}
	notifyEvent = function(target,t){return target.fireEvent('on' + t);}
}else if (window.addEventListener){
	addEvent = function(target,t,f){target.addEventListener( t, f , false);}
	removeEvent = function(target,t,f){target.removeEventListener( t, f , false);}
	notifyEvent = function(target,t){
		var e = document.createEvent("Events");   
		e.initEvent(t);   
		target.dispatchEvent(event);
	}
}else{
	addEvent = function(target,t,f){
		var en = 'on' + t;
		var handlers = target[en];
		var t = typeof(handlers);
		if (t==='object'){
			var id = f.$$EVTID;
			if (!id){
				id = f.$$EVTID = addEvent.$$EVTCOUNT++;
				handlers[id] = f;
				return;
			}else{
				if(!handlers[id]) handlers[id] = f;
				return;
			}
		}
		var fn;
		if(t==='function'){
			fn = handlers,handlers = {};
		}else if (t==='string'){
			var cmdText = handlers,handlers = {};
			fn = function(event){return eval(cmdText);}
		}
		if (fn){
			fn.$$EVTID = addEvent.$$EVTCOUNT++;
			handlers[fn.$$EVTID] = fn;
			f.$$EVTID = addEvent.$$EVTCOUNT++;
			handlers[f.$$EVTID] = f;
			target[en] = handlers;
		}
	}
	removeEvent = function(target,t,f){
		var en = 'on' + t;
		var handlers = target[en];
		if (!handlers) return;
		if (handlers===f) target[en] = null;
		else{
			delete handlers[f.$$EVTID]
		}
	}
	notifyEvent = function(target,t){
		var en = 'on' + t;
		var handlers = target[en];
		var t = typeof(handlers);
		if (t==='function'){
			return handlers();
		}else if (t==='string'){
			return eval(t);
		}else if (t==='object'){
			for(var n in handlers){
				var fn = handlers[n];
				fn();
			}
		}
	}
	addEvent.$$EVTCOUNT = 1;
}


//Selection
//这部分参考了 http://www.quirksmode.org/dom/range_intro.html
//http://www.never-online.net/blog/article.asp?id=114
// 12月10日,这部分的代码终于在4款浏览器上通过了...safari的图片没有src的话,就一点都不显示,我还以为是代码写错了呢.
//safari和opera都要本document create的Element才能insert,否则报个thread错.

/**** 
 类说明:
	获取一个selection 对象(自定义)，该对象表示文档中选中的内容
	给document添加了一个getSelection 操作,该操作返回本窗体中或指定窗体中选中的部分.
	UserSelection只能由该函数调用并返回给用户
	不推荐用户自己new UserSelection.
 相关的函数有
	get_Document : 返回这个selection关联的document.
	createElement : 在这个选中区域关联的document上创建一个网页元素.
	createRange : 创建在这个选中区域上的range对象
	get_Text : 返回选中区域的文本内容
	surround :	把选中区域放到一个网页元素中去.
	replaceNode : 把选中区域替换成指定的元素.
	pasteHTML : 把选中区域换成sHTML的内容
 返回:
	selection 对象
****/
var UserSelection,getSelection;
if (document.createRange){
	UserSelection = function(sel){this.__sel = sel;this.__doc = sel.anchorNode.ownerDocument;}
	UserSelection.prototype = {
		/**** 
		 函数说明:
			获取和选中区域关联的文档对象
		 参数:
		 返回:
			document
		****/
		get_Document : function(){return this.__doc;},
		/**** 
		 函数说明:
			在选中区域创建一个range对象,范围就是本选中区域
			IE返回TextRange对象
			其他浏览器返回标准Range对象
		 参数:
		 返回:
			range 对象
		****/
		createRange : function(){
			var sel = this.__sel;
			if (sel.getRangeAt)
				return sel.getRangeAt(0);
			else { // Safari!
				var range = this.__doc.createRange();
				range.setStart(sel.anchorNode,sel.anchorOffset);
				range.setEnd(sel.focusNode,sel.focusOffset);
				return range;
			}
		},
		/**** 
		 函数说明:
			在选中区域的文档对象中,创建一个元素
		 参数:
			tag 对象的标签
		 返回:
			
		****/
		createElement : function(tag){
			return this.__doc.createElement(tag);
		},
		get_Text : function(){ return this.__sel.toString();},
		surround : function(tag,attrs){
			var oRange = this.createRange();
			//var oFragment = oRange.extractContents();
			var oCtn = this.__doc.createElement(tag);
			for(var n in attrs)oCtn.setAttribute(n,attrs[n]);
			oRange.surroundContents(oCtn);
			oRange.detach();
		},
		/**** 
		 函数说明:
			把选中区域用某个元素替换掉
		 参数:
			oNode(must) 要替换的元素.该元素必须是跟selection对象一致的document对象创建或所有
			oRange(重载) 如果有range了就不再createRange ,使用这range.
						该参数主要是做内部调用,不推荐用户使用
		 返回:
			
		****/
		replaceNode : function(oNode,oRange){			
			var sel = this.__sel;
			oRange = oRange || this.createRange();
			oRange.extractContents();
			oRange.insertNode(oNode);
			oRange.detach();
		},
		/**** 
		 函数说明:
			用指定的HTML替换选中区域的HTML.
		 参数:
			sHTML 要替换选中区域的HTML代码
		 返回:
			
		****/
		pasteHTML : function(sHTML){
			var oRange = this.createRange();
			var cf = oRange.createContextualFragment(sHTML);
			this.replaceNode(cf,oRange);
		}
	}
	/**** 
	 函数说明:
		返回选中的区域
	 参数:
		oWin 要指定那个窗口.
	 返回:
		UserSelection对象
	****/
	getSelection = function(oWin){
		var sel; 
		if (oWin) sel= oWin.contentWindow?oWin.contentWindow.getSelection():oWin.getSelection();
		else sel = window.getSelection();
		return new UserSelection( sel );
	}
}else{
	UserSelection = function(sel,doc){this.__sel = sel;this.__doc = doc;}
	UserSelection.prototype = {
		createRange : function(){return this._sel;},
		createElement : function(tag){
			return document.createElement(tag);
		},
		get_Document : function(){return this.__doc;},
		get_Text : function(){ return this.__sel.text;},
		surround : function(tag,attrs){
			var oRange = this.__sel;
			var html = oRange.htmlText;
			var htm = ["<",tag];
			if (attrs){
				for(var n in attrs){
					htm.push(" ");
					htm.push(n);htm.push("=\"");htm.push(attrs[n]);htm.push("\"");
				}
			}
			htm.push(">");
			htm.push(html);
			htm.push("</");htm.push(tag);htm.push(">");
			oRange.pasteHTML(htm.join(""));
		},
		replaceNode : function(oNode){
			this.__sel.pasteHTML(oNode.outerHTML);
		},
		pasteHTML : function(sHTML){
			this.__sel.pasteHTML(sHTML);
		}
	}
	getSelection = function(oWin){
		var doc;
		if (oWin) doc =  oWin.contentWindow?oWin.contentWindow.document:oWin.document;
		else doc = document;
		//alert(win.document.selection.createRange().text);
		return new UserSelection(doc.selection.createRange(),doc);
	}
}

var visionTag,getVisionDom,getVisionDims,getVisionScrolls;
//if (isIE){
	var c = document.compatMode;visionTag = (c && c!="BackCompat")? "documentElement" : "body";
//}else{
//	visionTag = "documentElement";
//}
getVisionDims = function(){
	var elem = document[visionTag];
	return cdims(elem.clientWidth,elem.clientHeight);
}

getVisionScrolls = function(){
	var elem = document[visionTag];
	return {
	    w : elem.scrollWidth,
	    h : elem.scrollHeight,
	    x : elem.scrollLeft,
	    y : elem.scrollTop
	};
}

var Grid = {
	create : function(p,row,cell){
		for(var y = 0; y <row;y++){
			var tr = document.createElement('tr');
			for(var x =0;x<cell;x++)tr.appendChild(document.createElement('td'));
			p.appendChild(row);
		}
	},
	get : function(tb,x,y){return tb.rows[y].cells[x];},
	set : function(tb,x,y,el){
		var cell = tb.rows[y].cells[x];
		(typeof(el)==='object')?cell.appendChild(el):cell.innerHTML = el;
	}
}

var over = function(el,ov,out){
	addEvent(el,'mouseover',function(){
		if (out) removeCss(el,out);
		addCss(el,ov);
	});
	addEvent(el,'mouseout',function(){
		if (out) addCss(el,out);
		removeCss(el,ov);
	});
}


Eanyee.Dom = {
	Browser : Browser,
	cPoint : cpoint,
	cDims	:cdims,
	each : each,
	createRange : createRange,
	createRanges : createRanges,
	canInsertDom : canInsertDom,
	addRange : addRange,
	insertDom : insertDom,
	insertHTML : insertHTML,
	clear : clear,
	hasCss : hasCss,
	addCss : addCss,
	removeCss : removeCss,
	toggleCss : toggleCss,
	getCss : getCss,
	setCss	: setCss,
	getStyle : getStyle,
	setStyle : setStyle,
	getOpacity : getOpacity,
	setOpacity : setOpacity,
	getXY : getXY,
	setXY	: setXY,
	getZ : getZ,
	setZ : setZ,
	addEvent:addEvent,
	removeEvent : removeEvent,
	notifyEvent : notifyEvent,
	getSelection : getSelection,
	VisionTagName	: visionTag,
	getVisionDims : getVisionDims,
	getVisionScrolls : getVisionScrolls,
	Grid : Grid,
	over : over
};
})();