// File             : utils.js
// Programmer       : John Wong
// Copyright (c) Q-Surf Computing Solutions, 2003-09. All rights reserved.
// http://www.qwebeditor.com/

// create the main name space
var JSLIB = window.JSLIB || {};

// this function is used to pre-populate namespace
JSLIB.namespace = function(name)  {
    var names = name.split("."),o,i;
    if (names[0] != "JSLIB") {
        return;
    }
    o = JSLIB;
    for (i = 1; i < names.length; i ++) {
        if (typeof o[names[i]] == "undefined") {
            o[names[i]] = {};
        }
        o = o[names[i]];
    }
}

// call parent constructor
JSLIB.callParentConstructor = function(parent, obj) {
	// Apply parent's constructor to this object
	if( arguments.length > 2 ) {
		// Note: 'arguments' is an Object, not an Array
		parent.apply( obj, Array.prototype.slice.call( arguments, 2 ) );
	}
	else {
		parent.call( obj );
	}
}

// child copies parent hierarchy
JSLIB.inherits = function(parent, child) {
	child.prototype = new parent();
	child.prototype.constructor = child;
}

// PSLIB.simpleObject class. base class for inheritance
JSLIB.namespace("PSLIB.simpleObject");
JSLIB.simpleObj = function () {
}
JSLIB.simpleObj.prototype.constructor = JSLIB.simpleObj;

// PSLIB.object class. base class for JSLIB classes
JSLIB.object = function () {
	JSLIB.callParentConstructor(JSLIB.simpleObj, this);
    this.properties = {};
}
JSLIB.inherits(JSLIB.simpleObj, JSLIB.object);

JSLIB.object.prototype.getProperty = function(name) {
    return this.properties[name];
}
JSLIB.object.prototype.setProperty = function(name, value) {
    this.properties[name] = value;
}

function LTrim(s){var str=new String(s); return str.replace(/^\s*/,""); }
function RTrim(s){var str=new String(s); return str.replace(/\s*$/,""); }
function Trim(str){return LTrim(RTrim(str))}

JSLIB.namespace("JSLIB.htmlSourceCleaner");
JSLIB.htmlSourceCleaner = function () {
	var T=true;
	this._singleTags = {img:T, input:T, br:T, hr:T, meta:T, link:T};
	this._tableTags = {table:T, tr:T, th:T, td: T};
	this._tableAttrs = {width:T, height:T, bgcolor:T, background:T, border:T, bordercolor:T};
	this._formattingTags = {
		span:T, font:T, b:T, strong:T,
		i:T, em:T, u:T, strike:T,
		big:T, small:T, sup:T, sub:T,
		col:T, colgroup:T};
	this._formattingAttrs = {
		style:T, "class":T
		};

	this._commentsToSymbols = function (str) {
		var startPos = 0, endPos, s = " " + str + " ", comments = [], idx = 0;
		// convert comments to symbols
		for (;;) {
			startPos = s.indexOf("/\*");
			if (startPos < 0) {
				break;
			}
			endPos = s.indexOf("*\/");
			idx = comments.length;
			if (endPos < 0) {
				comments[idx] = s.substring(startPos);
				s = s.substring(0, startPos - 1) + "[[comment|" + idx + "]]";
			}
			else {
				comments[idx] = s.substring(startPos, endPos + 2);
				s = s.substring(0, startPos - 1) + "[[comment|" + idx + "]]" + s.substring(endPos + 2);
			}
		}
		
		return [s, comments];
	}
		
	this._symbolsToComments = function (s, comments) {
		var i;
		for (i = 0; i < comments.length; i ++) {
			s = s.replace("[[comment|" + i + "]]", comments[i]);
		}
		return s;
	}

	this._cleanStyleValueBasic = function (s, baseHrefIn, baseHrefOut) {
		var cssStyles, output = [], i, pos, urls = [], result, idx, i;
		
		cssStyles = s.split(";");
		for (i = 0; i < cssStyles.length; i ++) {
			pos = cssStyles[i].indexOf(":");
			if (pos > 0) {
				output[output.length] = Trim(cssStyles[i].toLowerCase().substring(0, pos)) + ": " + Trim(cssStyles[i].substring(pos + 1));
			}
			else {
				if (Trim(cssStyles[i]).length > 0) {
					output[output.length] = cssStyles[i];
				}
			}
		}
		s = output.join("; ");

		// fix url()
		for (;;) {
			result = s.match(/url\s*\(([^\)]*)\)/);
			if (!result) {
				break;
			}
		
			idx = urls.length;
			s = s.replace(result[0], "[[url|" + idx + "]]");
			urls[idx] = result[1];
			if (baseHrefIn.length > 0) {
				urls[idx] = AbsUrl(urls[idx], baseHrefIn);
			}
			if (baseHrefOut && urls[idx].indexOf(baseHrefOut) == 0) {
				urls[idx] = urls[idx].substring(baseHrefOut.length);
			}			
		}
		
		for (i = 0; i < urls.length; i ++) {
			s = s.replace("[[url|" + i + "]]", "url(" + urls[i] + ")");
		}

		return s;
	}
	
	this._cleanStyleValue = function (str, baseHrefIn, baseHrefOut) {
		var s, comments, result;
		
		result = this._commentsToSymbols(str);
		s = result[0];
		comments = result[1];
	
		s = this._cleanStyleValueBasic(s, baseHrefIn, baseHrefOut);
		return this._symbolsToComments(s, comments);
	};
	
	this._cleanStyleTagContent = function (str, baseHrefIn, baseHrefOut) {
		var s, comments, result, values = [], idx = 0, startPos = 0, endPos;
		
		result = this._commentsToSymbols(str);
		s = result[0];
		comments = result[1];

		for (;;) {
			startPos = s.indexOf("{");
			if (startPos < 0) {
				break;
			}
			endPos = s.indexOf("}");
			idx = values.length;
			if (endPos > 0) {
				values[idx] = this._cleanStyleValueBasic(s.substring(startPos + 1, endPos), baseHrefIn, baseHrefOut).replace(";", ";\n");
				s = s.substring(0, startPos) + "[[value|" + idx + "]]" + s.substring(endPos + 1);
			}
		}
		
		for (i = 0; i < values.length; i ++) {
			s = s.replace("[[value|" + i + "]]", "{\n" + values[i] + "\n}");
		}

		return this._symbolsToComments(s, comments);
	}
	
	this._removeTag = function (content, startTag, endTag) {
		var startPos, endPos, startPos2 = 0;
		while (true) {
			startPos = content.indexOf(startTag, startPos2);
			if (startPos >= 0) {
				endPos = content.indexOf(endTag, startPos);
				startPos2 = content.indexOf(startTag, startPos + startTag.length);
				if (endPos >= 0 && (startPos2 < 0 || startPos2 > endPos)) {
					content = (startPos > 0 ? content.substr(0, startPos) : "") + (endPos > 0 ? content.substr(endPos + endTag.length) : "");
					startPos2 = 0;
				}
				else if (startPos2 < 0) {
					break;
				}
			}
			else {
				break;
			}
		}	
		return content;
	}
}

JSLIB.htmlSourceCleaner.prototype.process = function (str, options) {
	var pos = 0, output = "",
		reTag = /^<([A-Za-z1-9\-\_\:\/]+)([^>]*)>$/,
		reAttr = /^([ \r\n\t]*([A-Za-z0-9\-\_\:]+)(?:(\=)("([^"]*)(")|'([^']*)(')|[^ ]*))?)/,
		T = true, F = false, UD = "undefined",
		safeHtml = (typeof options["safeHtml"] == UD) ? F : options["safeHtml"],
		cleanForWord = (typeof options["cleanForWord"] == UD) ? F : options["cleanForWord"],
		cleanTableFormatting = (typeof options["cleanTableFormatting"] == UD) ? F : options["cleanTableFormatting"],
		cleanExcelAttributes = (typeof options["cleanExcelAttributes"] == UD) ? F : options["cleanExcelAttributes"],
		cleanFormatting = (typeof options["cleanFormatting"] == UD) ? F : options["cleanFormatting"],
		baseHrefIn = (typeof options["baseHrefIn"] == UD) ? "" : options["baseHrefIn"],
		baseHrefOut = (typeof options["baseHrefIn"] == UD) ? "" : options["baseHrefOut"];
//		absUrl = (typeof options["absUrl"] == UD) ? F : options["absUrl"];

	baseHrefIn = DirName(baseHrefIn);
	if (baseHrefIn.length > 0) {
		baseHrefIn += "/";
	}
	
	if (safeHtml) {
		str = str.replace(/<\/SCRIPT/gi, "</script");
	}
	
	do {
		// look for start delimiter of the tag
		var nextPos = str.indexOf("<", pos), dPos;

		// output everything as-is before the tag
		if (nextPos < 0) {
			if (str.length > pos) {
				output += str.substring(pos);
			}
			break;
		}
		else if (nextPos > pos) {
			output += str.substring(pos, nextPos);
		}
		
		// look for end delimiter of the tag
		pos = nextPos;
		nextPos = str.indexOf(">", pos);
		
		if (nextPos < 0) {
			return output + "[[ ERROR: template compilation failed - missing tag closing delimiter ]]";
		}
		
		var 
			tag = str.substring(pos, nextPos + 1),
			matches = tag.match(reTag),
			tagname, attrs,
			updatedTag = "",
			attrName, attrValue;
		
		if (matches) {
			tagname = matches[1];
			attrs = matches[2];
			
			if (tagname.indexOf(":") < 0) {
				tagname = tagname.toLowerCase();
				if (cleanForWord && tagname == "p") {
					tagname = "div";
				}
			}
			updatedTag += tagname;
			
			if (tagname.substring(0, 1) == "/") {
				if ((typeof this._singleTags[tagname.substring(1)] != UD) ||
					(cleanFormatting && typeof this._formattingTags[tagname.substring(1)] != UD)) {
					// do nothing
				}
				else {
					output += "<" + tagname + ">";
				}
			}
			else if (safeHtml && (tagname == "script")) {
				dPos = str.indexOf("</script", nextPos);
				if (dPos < 0) {
					dPos = str.indexOf("</SCRIPT", nextPos);
				}
				if (dPos >= 0) {
					dPos = str.indexOf(">", dPos);
				}
				if (dPos < 0) {
					dPos = str.length;
				}
				nextPos = dPos;
			}
			else if (cleanFormatting && typeof this._formattingTags[tagname] != UD) {
				// do nothing
			}
			else {
				while (attrs.length > 0) {
					if (matches = attrs.match(reAttr)) {
						attrName = matches[2].toLowerCase();
						if (matches[3] == "=") {
							if (matches[6] == "\"") {
								attrValue = matches[5];
							}
							else if (matches[8] == "'") {
								attrValue = matches[7];
							}
							else {
								attrValue = matches[4];
							}
						}
						else {
							attrValue = attrName;
						}
					}
					else {
						// error
						break;
					}
					attrs = attrs.substring(matches[0].length);
					if ((safeHtml && attrName.substring(0, 2) == "on") ||
						(cleanTableFormatting && 
						(typeof this._tableTags[tagname] != UD) && 
						(typeof this._tableAttrs[attrName] != UD)) ||
						(cleanExcelAttributes && attrName.substring(0,2) == "x:") ||
						(cleanFormatting && typeof this._formattingAttrs[attrName] != UD) ||
						((cleanForWord || cleanExcelAttributes) && attrName == "class" && (attrValue == "MsoNormal" || attrValue == "MsoNormalTable"))
						) {
						// do nothing
					}
					else {
						// clean style attribute
						if (attrName == "style") {
							attrValue = this._cleanStyleValue(attrValue, baseHrefIn, baseHrefOut);
						}
						// clean URL based on baseHref
						else if (attrName == "src" || attrName == "href" || attrName == "background") {
							if (baseHrefIn.length > 0) {
								if (attrValue.length > 0 && attrValue.substring(0,1) != "#") {
									attrValue = AbsUrl(attrValue, baseHrefIn);
								}
							}
							if (baseHrefOut && attrValue.indexOf(baseHrefOut) == 0) {
								attrValue = attrValue.substring(baseHrefOut.length);
							}
						}
						if (safeHtml && attrName == "href") {
							var dummy = Trim(attrValue);
							dummy = dummy.toLowerCase();
							if (dummy.substring(0,11) == "javascript:") {
								attrValue = "";
							}
						}
						updatedTag += " " + attrName + "=\"" + attrValue + "\"";
					}
				}
				output += "<" + updatedTag + (typeof this._singleTags[tagname] == UD ? ">" : " />");
			}
		}
		else {
			output += tag;
		}
		
		if (tagname == "style") {
			dPos = str.indexOf("</style", nextPos);
			if (dPos < 0) {
				dPos = str.indexOf("</STYLE", nextPos);
			}
			if (dPos >= 0) {
				output += this._cleanStyleTagContent(str.substring(nextPos + 1, dPos), baseHrefIn, baseHrefOut);
				nextPos = dPos - 1;
			}
		}
		
		pos = nextPos + 1;
	} while (pos < str.length);

	if (cleanForWord || cleanExcelAttributes) {
		output = output.replace(/(<meta[^>]*>)/gm, "");
		output = output.replace(/(<link[^>]*>)/gm, "");
		output = this._removeTag(output, "<!--[if ", "<![endif]-->");
		output = this._removeTag(output, "<o:p>", "</o:p>");
		output = this._removeTag(output, "<xml", "</xml>");
		output = this._removeTag(output, "<style", "</style>");
	}

	return output;		
};

function IsValidInteger(str){
	var n1 = new String(str);
	for (i = 0; i < n1.length; i ++){
	    if(n1.charAt(i) < "0" || n1.charAt(i) > "9")
	        return false;
	}    
	return true;
}

function AbsUrl(str, baseHref) {
	var str=new String(str),re,arr,arr2,N=null;
	if(/^(http|https|email|file|ftp|about|mailto):/.test(str)){
		return str;
	}
	else {
		if (typeof baseHref == "undefined") {
			baseHref = DirName(location.href) + "/";
		}
		if (str.charAt(0) == "/") {
			arr=baseHref.match(/(^(http|https|file):\/\/[^\/]*\/)/);
			if (arr != N) {
				return arr[1] + str.substring(1);
			}
			arr=baseHref.match(/(^file:\/\/)/);
			if (arr != N) {
				return "file://" + str;
			}
			// everything seems invalid. just return asis.
			return str;
		}
		else {
			re = /^((\.|\.\.)\/)/;
			while (true) { 
				arr = str.match(re);
				if (arr == N) {
					break;
				}
				if (arr[1] == "../") {
					arr2 = baseHref.match(/^((http|https|ftp):\/\/[^\/]*\/([^\/]*\/)*)([^\/]*\/)$/);
					if (arr2 != N) {
						baseHref = arr2[1];
					}
					else {
						arr2 = baseHref.match(/^(file:\/\/(.*\/)\/)([^\/]*\/)$/);
						if (arr2 != N) {
							baseHref = arr2[1];
						}
					}
				}
				str = str.substring(arr[1].length);
			}
			return baseHref + str;
		}
	}
}

function DirName(str) {
    var str=new String(str),re=/(.*)\/([^\/]*)$/,arr=str.match(re),UD="undefined";
    return (arr==null||typeof arr==UD||typeof arr[1]==UD)?".":arr[1];
}

 
function BaseName(str) {
    var str=new String(str),re=/(.*)\/([^\/]*)$/,arr=str.match(re),UD="undefined";
    return (arr==null||typeof arr==UD||typeof arr[2]==UD)?"":arr[2];
}

function utilsInArray(value, arr) {
	for (var i = 0; i < arr.length; i ++) {
		if (arr[i] == value) {
			return true;
		}
	}
	return false;
}

// flag - undefined or 0 - escape double quote
//        1 - do not escape double quote
//        2 - quote single quote too
function HtmlSpecialChars(str, flag){
	var mystr = new String(str),
		re;
	
	if (typeof flag=="undefined") {
		flag = 0;
	}
	re=/&/g;
	mystr=mystr.replace(re,"&amp;");
	if (flag != 1) {
		re=/\"/g;
		mystr=mystr.replace(re,"&quot;");
	}
	if (flag == 2) {
		re=/\'/g;
		mystr=mystr.replace(re,"&#039;");
	}
	re=/</g;
	mystr=mystr.replace(re,"&lt;");
	re=/>/g;
	mystr=mystr.replace(re,"&gt;");
	re=new RegExp(String.fromCharCode(160), "g")
	mystr=mystr.replace(re,"&nbsp;");
	return mystr
}

function HtmlEditAddSlashes(str){
	var mystr = new String(str), re;
	mystr=mystr.replace(/\"/g,"\\\"");
    mystr=mystr.replace(/\'/g,"\\\'");
    mystr=mystr.replace(/\t/g,"\\t");
    mystr=mystr.replace(/\r/g,"\\r");
    mystr=mystr.replace(/\n/g,"\\n");
    return mystr;
}

function IsHtmlText(str){
	var mystr = new String(str),
		re=/<(p|h1|h2|h3|h4|h5|h6|table|td|tr|ul|ol|li|b|i|u|strong|em|strike|super|sup|big|small|body|html|br|hr|font|blockquote|pre|tt|script|object|embed)/i;
	if(re.test(mystr)) return true;
	re=/(&[a-zA-Z]{2,5};|&#[0-9]{1,5};)/i;
	if(re.test(mystr)) return true;
	return false;
}

function PlainTextToHtml(str){
	var mystr = new String(str), re;
	mystr=mystr.replace(/\r\n/g,"<br />");
	mystr=mystr.replace(/\n/g,"<br />");
	mystr=mystr.replace(/\r/g,"<br />");
	mystr=mystr.replace(/  /g," &nbsp;");
	mystr=mystr.replace(/\t/g," &nbsp; &nbsp;");
	return mystr;
}

function HtmlToPlainText(str, strImage){
	var mystr = new String(str), re;
	re=/>\r\n/g;
	mystr=mystr.replace(re,">");
	re=/>\r/g;
	mystr=mystr.replace(re,">");
	re=/>\n/g;
	mystr=mystr.replace(re,">");
	re=/\r\n/g;
	mystr=mystr.replace(re," ");
	re=/\r/g;
	mystr=mystr.replace(re," ");
	re=/\n/g;
	mystr=mystr.replace(re," ");
    if(strImage){
		re=/<img[^>]*>|<object[^>]*>|<embed[^>]*>/ig;
		mystr=mystr.replace(re,strImage);
    }
	re=/<\/p[^>]*>|<\/h1[^>]*>|<\/h2[^>]*>|<\/h3[^>]*>|<\/h4[^>]*>|<\/h5[^>]*>|<\/h6[^>]*>|<\/blockquote[^>]*>|<\/ul[^>]*>|<\/ol[^>]*>/gi;
	mystr=mystr.replace(re,"\n\n");
	re=/<br[^>]*>/gi;
	mystr=mystr.replace(re,"\n");
	re=/<\/div[^>]*>/gi;
	mystr=mystr.replace(re,"\n");
	re=/<li[^>]*>/gi;
	mystr=mystr.replace(re,"\n  * ");
	re=/<\/td[^>]*>/gi;
	mystr=mystr.replace(re,"  ");
	re=/<hr[^>]*>/gi;
	mystr=mystr.replace(re,"\n-------------------------------\n");
	re=/<[^>]*>/gi;
	mystr=mystr.replace(re,"");
	// need to convert html entities back to original chars.
	// but not necessary for qwebeditor
	return mystr;
}

function CleanWindowsCharset(strValue) {
	var re = new RegExp("(["+String.fromCharCode(
		183,
		8211, 8212, 8213, 8214, 8215, 
		8216, 8217, 8218, 8219, 8220, 
		8221, 8222, 8223, 8224, 8225,
		8226, 8227, 8228, 8229, 8230)+"])","g") 
	strValue = strValue.replace(re, function($1){
			var str=new String($1)
			switch(str.charCodeAt(0)){
			case 183: return "&middot;";
			case 8211: return "-";
			case 8212: 
			case 8213: return "--";
			case 8214: return "|";
			case 8215: return "-";
			case 8216: 
			case 8217: 
			case 8218: 
			case 8219: return "'";
			case 8220: 
			case 8221: 
			case 8222: return '"';
			case 8228: return ".";
			case 8229: return ". .";
			case 8230: return "...";
			}
		});
	return strValue;
}

function GetInnerTextById(id){
    if(!document.getElementById) return "";
    var node=document.getElementById(id)
    if(node){
		if(is_ie)return node.innerText;
		else{
			var html=document.createRange();
			html.selectNodeContents(node);
			return html.toString();
		}
    }
    return "";
}
/*
function GetInnerHtmlFromNode(node,baseHref,bSafe){
	var absUrl = absUrl=(typeof(arguments[3])!="undefined"?arguments[3]:false),
	    o = new JSLIB.htmlSourceCleaner();
	return o.process(node.innerHTML, {safeHtml:bSafe, baseHref:baseHref, absUrl: absUrl});
}
*/
function GetCleanCode(node){
	// bWord - change p tag to div
	var T = true, F = false, UD = "undefined", A=arguments;
		bWord=(typeof A[1]!=UD?A[1]:F),
		bRemoveTableFormatting=(typeof A[2]!=UD?A[2]:F),
		bRemoveExcelAttributes=(typeof A[3]!=UD?A[3]:F),
		baseHrefIn=(typeof A[4]!=UD?A[4]:""),
		baseHrefOut=(typeof A[5]!=UD?A[5]:""),
		cleanFormatting=(typeof A[6]!=UD?A[6]:T),
		o = new JSLIB.htmlSourceCleaner();
	return o.process(node.innerHTML, {
		safeHtml:T, 
		cleanFormatting:cleanFormatting,
		cleanForWord:bWord,
		cleanTableFormatting:bRemoveTableFormatting,
		cleanExcelAttributes:bRemoveExcelAttributes,
		baseHrefIn:baseHrefIn,
		baseHrefOut:baseHrefOut
		});
}

function HeUtilsPopupCreate(bForceDiv){
	var D=document;
    if(window.createPopup&&!bForceDiv){
    	// IE way
        return{
        	objPopup:window.createPopup(),
        	bDiv:false};
    }
    else if(D.createElement){
    	// using DOM to create an abs pos div
        var div=D.createElement("div");
        div.style.cssText="position:absolute;left=-1000px;top=-1000px;visibility:hidden;z-index=10";
        D.body.appendChild(div);
        return{
        	objPopup:div,
        	bDiv:true
			};
    }
    return null;
}

function HeUtilsPopupGetContent(obj){
    if(!obj||!obj.objPopup)return;
    return (!obj.bDiv)?obj.objPopup.document.body.innerHTML : obj.objPopup.innerHTML;
}

function HeUtilsPopupSetContent(obj,content){
    if(!obj||!obj.objPopup)return;
    if(!obj.bDiv)
        obj.objPopup.document.body.innerHTML=content;
    else
        obj.objPopup.innerHTML=content;
}

function HeUtilsPopupShow(obj,left,top,width,height,element,bCenter){
	if(!obj||!obj.objPopup)return;
	var newLeft,newTop,width,height;
	if(!obj.bDiv){
		// has to declare display the popup first before able to get the dimension
	    obj.objPopup.show(left,top,1,1,element);
		if (width) {
			obj.objPopup.document.body.firstChild.style.width="100%";
		}
		else {
			obj.objPopup.document.body.firstChild.style.width="";
		}
		width=(width?width:obj.objPopup.document.body.firstChild.offsetWidth);
		height=(height?height+2:obj.objPopup.document.body.firstChild.offsetHeight);        
		newLeft=(bCenter)?((element.offsetWidth-width)/2):left+HeUtilsGetOffsetLeft(element);
		newTop=(bCenter)?((element.offsetHeight-height)/2):top+HeUtilsGetOffsetTop(element);
	    obj.objPopup.show(newLeft,newTop,width,height,element);
	}
	else{
		if (width) {
			obj.objPopup.firstChild.style.width="100%";
		}
		else {
			obj.objPopup.firstChild.style.width="";
		}
		width=width?width:obj.objPopup.firstChild.offsetWidth;
		height=height?height:obj.objPopup.firstChild.offsetHeight;
		newLeft=(bCenter)?((element.offsetWidth-width)/2):left;
		newTop=(bCenter)?((element.offsetHeight-height)/2):top;
		newLeft+=HeUtilsGetOffsetLeft(element);
		newTop+=HeUtilsGetOffsetTop(element);
		if(isNaN(newLeft)) newLeft=0;
		if(isNaN(newTop)) newTop=0;
		if(newLeft+width>window.innerWidth-20+window.scrollX)
		    newLeft=window.innerWidth-width-20+window.scrollX;
		if(newTop+height>window.innerHeight-20+window.scrollY)
		    newTop=window.innerHeight-height-20 +window.scrollY;
		var os=obj.objPopup.style;
		os.left=newLeft+"px";
		os.top=newTop+"px";
		os.width=width+"px";
		os.height=height+"px";
		os.visibility="visible";
	}
}

function HeUtilsPopupHide(obj){
	if(!obj || !obj.objPopup) return;
	if(!obj.bDiv)obj.objPopup.hide();
	else{
		var os=obj.objPopup.style;
		os.visibility="hidden";
		os.left="-1000px";
		os.top="-1000px";
	}
}

function HeUtilsGetOffsetTop(elm){
	var mOT=elm.offsetTop,mOP=elm.offsetParent;
	while(mOP){
		mOT+=mOP.offsetTop;
		mOP=mOP.offsetParent;
	}
	return mOT;
}

function HeUtilsGetOffsetLeft(elm){
    var mOL=elm.offsetLeft,mOP=elm.offsetParent;
    while(mOP){
		mOL+=mOP.offsetLeft;
		mOP=mOP.offsetParent;
    }
    return mOL;
}

function StyleSheetCreate(doc){
	if(!doc)return;
	if(doc.createStyleSheet){
		var e;
		try{return doc.createStyleSheet()}catch(e){}
	}
	else if(is_gecko||
        (is_safari&&g_heBrowser.version>419)||
        (g_heBrowser.browser=="opera"&&g_heBrowser.version>=9)){
		var index=doc.styleSheets.length,
			head=doc.getElementsByTagName('head').item(0),
			mystyle = doc.createElement('style');
		head.appendChild(mystyle);
		// mystyle is a style element object. need the cssstylesheet object
		return doc.styleSheets[index];
	}
    return null;
}

// url must be a abs url with protocol and domainname
function StyleSheetCreateFromUrl(doc, url){
	if(is_ie)return doc.createStyleSheet(url);
	else if(is_gecko||
        (is_safari&&g_heBrowser.version>412)||
        (g_heBrowser.browser=="opera"&&g_heBrowser.version>=9)){
		var index=doc.styleSheets.length,
			head=doc.getElementsByTagName('head').item(0),
			em = doc.createElement('link');
		em.setAttribute('rel','stylesheet');
		em.setAttribute('type','text/css');
		em.setAttribute('href',url);
		head.appendChild(em);
		// mystyle is a style element object. need the cssstylesheet object
		return doc.styleSheets[index];
	}
	return null;
}

function StyleSheetAddRule(ss,name,rule){
    if(is_ie){
        ss.addRule(name,rule);
    }
    else{
		var e;
		try{ss.insertRule(name+"{"+rule+"}",ss.cssRules.length)}catch(e){}
    }
}

function StyleSheetRemoveRule(ss,index){
    if (is_ie){
        ss.removeRule(index);
    }
    else {
		var e;
        try{ss.deleteRule(index);}catch(e){}
    }
}

// ss - stylesheet
function StyleSheetRemoveAllRules(ss){
    var e;
    if (is_ie) {
		try{
        while(ss.rules.length)StyleSheetRemoveRule(ss, 0);
        }catch(e){}
    }
    else{
        // dont know why gecko wont allow accessing cssRules for created stylesheet
        // just trying to delete rules until exception is caught
		try{
			var num=ss.cssRules.length;
			for(var i=0;i<num;i++)StyleSheetRemoveRule(ss,0);
		}catch(e){}
    }
}

function StyleSheetGetRulesArray(ss){
	if(!ss)return null;
	return is_ie?ss.rules:ss.cssRules;
}

function ObjGetCssText(o){
	if(!o)return;
	return (is_ie||is_safari)?o.style.cssText:o.getAttribute("style");
}
 
function ObjSetCssText(o,cssText){
	if(!o)return;
	if(is_ie||is_safari){
		o.style.cssText=cssText;
	}
	else {
		SetRemoveAttr(o,"style",cssText);
	}
}

function AttachEventListener(o,eventName,func){
	if(!o)return false;
	if(o.attachEvent){ // IE
		o.attachEvent("on"+eventName,func);
	}
	else if(o.addEventListener){ // Mozilla
		o.addEventListener(eventName,func,false);
	}
	return true;
}

function SetRemoveAttr(e,attr,value){
	if(typeof(e)=="undefined"||!e.removeAttribute||!e.setAttribute)return;
	if(typeof(value)=="undefined"||value==null||value.length==0){
		e.removeAttribute(attr);
	}
	else{
		e.setAttribute(attr,value);
	}
}

function utilsConvertSpanToHtmlTag(doc) {
	// get all span tag
	var arrSpans = doc.getElementsByTagName("span");
	for (var i = arrSpans.length - 1; i >= 0; i --) {
		var 
			node = arrSpans[i],
			parentNode = node.parentNode,
			strStyle = node.getAttribute("style"),
			newParent = null,topParent = null,
			elem,bIE = false,
			className = node.className;

		// safari tweak
		if (className == "Apple-style-span") {
			className = null;
		}

		if (strStyle) {
			// IE returns a style object instead. we need the string
			if (!strStyle.indexOf) {
				strStyle = new String(strStyle.cssText);
				bIE = true;
			}
			// IE returns CSS attributes in uppercase
			strStyle = Trim(strStyle.toLowerCase());
			// IE does not return semicolon for last css attribute
			if (strStyle.length > 0 && strStyle.substr(strStyle.length - 1, 1) != ";") {
				strStyle = strStyle + ";";
			}
		}

		if (strStyle) {
			// look for the following CSS attributes
			
			// b
			if (strStyle.indexOf("font-weight: bold;") >= 0) {
				elem = doc.createElement("b");
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace("font-weight: bold;", ""));
			}
			// bold under Opera 9
			if (strStyle.indexOf("font-weight: 700;") >= 0) {
				elem = doc.createElement("b");
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace("font-weight: 700;", ""));
			}
			
			// i
			if (strStyle.indexOf("font-style: italic;") >= 0) {
				elem = doc.createElement("i");
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace("font-style: italic;", ""));
			}
			
			// u
			if (strStyle.indexOf("text-decoration: underline;") >= 0) {
				elem = doc.createElement("u");
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace("text-decoration: underline;", ""));
			}

			// strike
			if (strStyle.indexOf("text-decoration: line-through;") >= 0) {
				elem = doc.createElement("strike");
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace("text-decoration: line-through;", ""));
			}

			// super
			if (strStyle.indexOf("vertical-align: super;") >= 0) {
				elem = doc.createElement("sup");
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace("vertical-align: super;", ""));
			}

			// sub
			if (strStyle.indexOf("vertical-align: sub;") >= 0) {
				elem = doc.createElement("sub");
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace("vertical-align: sub;", ""));
			}

			// font face
			var strMatch = strStyle.match(/font\-family: ([^\;]*)\;/);
			if (strMatch) {
				elem = doc.createElement("font");
				elem.setAttribute('face', strMatch[1]);
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace(strMatch[0], ""));
			}

			// font size
			var strMatch = strStyle.match(/font\-size: ([^\;]*)\;/);
			if (strMatch) {
				var value = "";
				switch (strMatch[1]) {
				case "xx-large": 
				case "-webkit-xxx-large":
					value = 7; break;
				case "x-large": value = 6; break;
				case "large": value = 5; break;
				case "medium": value = 4; break;
				case "small": value = 3; break;
				case "x-small": value = 2; break;
				case "xx-small": value = 1; break;
				}
				if (value) {
					elem = doc.createElement("font");
					elem.setAttribute('size', value);
					if (!topParent) topParent = elem;
					if (newParent) newParent.appendChild(elem);
					newParent = elem;
					strStyle = Trim(strStyle.replace(strMatch[0], ""));
				}
			}

			// font color
			var strMatch = strStyle.match(/^color:[ ]*([^\;]*)\;/);
			if (!strMatch) {
				strMatch = strStyle.match(/[ ]+color:[ ]*([^\;]*)\;/);
			}
			if (!strMatch) {
				strMatch = strStyle.match(/\;color:[ ]*([^\;]*)\;/);
			}
			if (strMatch) {
				elem = doc.createElement("font");
				elem.setAttribute('color', strMatch[1]);
				if (!topParent) topParent = elem;
				if (newParent) newParent.appendChild(elem);
				newParent = elem;
				strStyle = Trim(strStyle.replace(strMatch[0], ""));
			}

			// found replacement. restructure the DOM tree
			if (topParent) {
				// move all children to new branch
				while (node.childNodes.length > 0) {
					var oldChild = node.removeChild(node.firstChild);
					newParent.appendChild(oldChild);
				}

				// span tag is cleaned. take it out now.
				if (strStyle.length == 0 && !className) {
					if (parentNode) {
						parentNode.replaceChild(topParent, node);
					}
				}
				// span tag probably still has some css style and class name.
				// just cleaned whatever which is not needed.
				else {
					node.appendChild(topParent);
					if (bIE) {
						node.className = className;
						node.style.cssText = strStyle;
					}
					else {
						SetRemoveAttr(node,"style",strStyle);
						SetRemoveAttr(node,"class",className);
					}
				}
			}
			// no replacement and still have style or class attributes. update span tag
			else if (strStyle || className) {
				if (bIE) {
					node.className = className;
					node.style.cssText = strStyle;
				}
				else {
					SetRemoveAttr(node,"style",strStyle);
					SetRemoveAttr(node,"class",className);
				}
			}
			// no style and no class attribute. takes out the span tag
			else {
				while (node.childNodes.length > 0) {
					var oldChild = node.removeChild(node.firstChild);
					parentNode.insertBefore(oldChild, node);
				}
				parentNode.removeChild(node);
			}			
		}
		// no style and no class attribute. takes out the span tag
		else if (!className) {
			while (node.childNodes.length > 0) {
				var oldChild = node.removeChild(node.firstChild);
				parentNode.insertBefore(oldChild, node);
			}
			parentNode.removeChild(node);
		}
	}	

	// clean font tag
	var arrFonts = doc.getElementsByTagName("font");
	for (var i = arrFonts.length - 1; i >= 0; i --) {
		var node = arrFonts[i];
		var className = node.className;
		if (className == "Apple-style-span") {
			node.removeAttribute("class");
		}
	}
	
	// clean br tag
	var arrBrs = doc.getElementsByTagName("br");
	for (var i = arrBrs.length - 1; i >= 0; i --) {
		var node = arrBrs[i];
		var className = node.className;
		if (className == "khtml-block-placeholder" ||
			className == "webkit-block-placeholder") {
			node.removeAttribute("class");
		}
	}
	
}

function utilsMoveChildrenToNode(oldN, newN) {
	if (!oldN || !newN) return;
	while (oldN.firstChild) {
		var n = oldN.firstChild;
		oldN.removeChild(n);
		newN.appendChild(n);
	}
}

function utilsMoveNodesToNode(startNode, endNode, newNode) {
	var node = startNode,nextNode = startNode.nextSibling;
	do {
		node.parentNode.removeChild(node);
		newNode.appendChild(node);
		if (node == endNode) {
			break;
		}
		node = nextNode;
		nextNode = node.nextSibling;
	} while (node != null);
}

function utilsMoveNodesBeforeNode(startNode, endNode, newNode) {
	var node = startNode,
		nextNode = startNode.nextSibling,
		doc = startNode.ownerDocument;
	if (!doc) {
		doc = newNode.ownerDocument;
	}
	do {
		node.parentNode.removeChild(node);
		newNode.parentNode.insertBefore(node, newNode);
		if (node == endNode) {
			break;
		}
		node = nextNode;
		nextNode = node.nextSibling;
	} while (node != null);
}

function utilsGetFirstTextNode(n) {
	if (!n) return;
	while (n) {
		if (n.nodeType == 3) break;
		n = n.firstChild;
	}
	return n;
}

function utilsGetLastTextNode(n) {
	if (!n)return;
	while (n) {
		if (n.nodeType == 3) break;
		n = n.lastChild;
	}
	return n;
}

