/*
Utilities js file - all contents (c) chetch 2007
author: bill
created: 2007-01-24
description:
Contains useful funcs, name-prefixed by Utilities_ or Event_ to simulate static class functions.
Utilities_ funcs are general purpose, Event_ funcs are for broadcasting and registering events.
Event_ is included here given the ubiquity of usage.
*/

/* GENERAL USEFUL FUNCS */
function Utilities_escape(str){
	if(Utilities_isDefined(str) && str != null){
		str = escape(str);
		str = str.replace(/%u2122/g, '%99');
		str = str.replace(/%E2%84%A2/g, '%99');
		str = str.replace(/\+/g, '%2B');
		return str;
	} else {
		return '';
	}
}
function Utilities_unescape(str){
	if(str){
		str = str.replace(/\+/g,"%20");
		str = str.replace(/%99/g, '%u2122');
		return unescape(str);
	} else {
		return '';
	}
}

function Utilities_isDefined(v){
	return typeof v != 'undefined';
}

function Utilities_arrayLength(ar){
	var i = 0;
	for(var p in ar){
		i++;
	}
	return i;
}
function Utilities_trim(s){
	s = s.replace(/^ +/g, "");
	s = s.replace(/ +$/g, "");
	return s;
}
function Utilities_removeRepeatWhiteSpace(s){
	return s.replace(/ +/g, " ");
}

function Utilities_removeWhitespace(s){
	return s.replace(/ /g, "");
}

function Utilities_stripTags(s){
	return s.replace(/(<([^>]+)>)/ig,""); 
}

function Utilities_nl2br(str){
	return str.replace(/([^>])\n/g, '$1<br/>');
}

function Utilities_makePageName(s){
	var pn = Utilities_removeRepeatWhiteSpace(s.toLowerCase());
	pn = pn.replace(/ /g, '_');
	pn = pn.replace(/\//g, '-');
	pn = pn.replace(/[!"£$%^&*()+={}:;@'~#|\\,<.>?]/g, "");
	if(pn.match(/[^a-z0-9_-]/) != null){
		return null;
	} else {
		return pn;
	}
}

function Utilities_getTitleCase(s){
	var parts = s.split(' ');
	var r = '';
	for(i = 0; i < parts.length; i++){
		r += (i > 0 ? ' ' : '') + parts[i].substr(0,1).toUpperCase() + parts[i].substr(1, parts[i].length).toLowerCase();
	}
	return r;
}

function Utilities_appendToURL(url, qs){
	return url + (url.indexOf('?') == -1 ? '?' : '&') + qs;
}

function Utilities_parseQueryString(qs){
	if(qs.indexOf('?') != -1){
		qs = qs.substr(qs.indexOf('?') + 1, qs.length);
	}
	var ar = qs.indexOf('&') == -1 ? new Array(qs) : qs.split('&');
	var params = new Array();
	for(var i = 0; i < ar.length; i++){
		ar2 = ar[i].split('=');
		params[ar2[0]] = ar2.length > 1 ? ar2[1] : null;
	}
	return params;
}

function Utilities_makeQueryString(obj){
	var qs = '';
	for(var p in obj){
		qs += (qs ? '&' : '') + p + (obj[p] ? '=' + obj[p] : '');
	}
	return qs;
}

//if an element of arrayA doesn't exist in arrayB record it and at the end return array of missing elements
function Utilities_arrayComp(arrayA, arrayB, compFunc){
	try{
		var missing = new Array();
		for(var i = 0; i < arrayA.length; i++){
			var objA = arrayA[i];
			var found = false;
			for(var j = 0; j < arrayB.length; j++){
				var objB = arrayB[j];
				if(compFunc(objA, objB)){
					found = true;
					break;
				}
			}
			if(!found){
				missing[missing.length] = objA;
			}
		}
		return missing;
	} catch (e) {
		alert('Utilities_arrayComp exception ' + e.message);
	}
}

//join array ar using delimiter and a property of array objects if specifed
function Utilities_joinAsc(delimiter, ar, prop){
	var s = '';
	for(var p in ar){
		s += (s ? ',' : '') + (prop ? ar[p][prop] : ar[p]);
	}
	return s;
}

//use curly braces to perform eval on
function Utilities_evalReplace(s){
	while(s.indexOf('{') != -1){
		var openB = s.indexOf('{');
		var closeB = s.indexOf('}');
		var prepend = s.substring(0, openB);
		var append = s.substring(closeB + 1, s.length);
		var evalon = s.substring(openB + 1, closeB);
		var evaled;
		eval('evaled=' + evalon);
		s = prepend + evaled + append;
	}
	return s;
}
function Utilities_macroReplace(s, vals){
	try{
		if(Utilities_arrayLength(vals) == 0)return s;
		
		while(s && s.indexOf('{') != -1){
			var openB = s.indexOf('{');
			var closeB = s.indexOf('}');
			var prepend = s.substring(0, openB);
			var append = s.substring(closeB + 1, s.length);
			var toReplace = s.substring(openB + 1, closeB);
			var replaced = vals[toReplace];
			s = prepend + replaced + append;
		}
		return s;
	} catch (e) {
		alert(e.message);
	}
}

function Utilities_pad(number, maxLength, padWith){
	var s = new String(number);
	if(s.length >= maxLength){
		return s.substring(0, maxLength);
	}
	padWith = padWith ? padWith : '0';
	var pad = '';
	for(var i = 0; i < maxLength - s.length; i++){
		pad += '0';
	}
	return pad + s;
}

function Utilities_formatDate(dt, formatString, asObject){
	var formats = new Array();
	formats['Y'] = dt.getFullYear();
	formats['m'] = Utilities_pad(dt.getMonth() + 1, 2);
	formats['d'] = Utilities_pad(dt.getDate(), 2);
	formats['H'] = Utilities_pad(dt.getHours(), 2);
	formats['i'] = Utilities_pad(dt.getMinutes(), 2);
	formats['s'] = Utilities_pad(dt.getSeconds(), 2);
	
	var s = formatString;
	var a = new Array();
	for(var p in formats){
		if(asObject){
			var n = formatString.indexOf(p);
			if(n != - 1){
				var g = null;
				if(p.match(/Y|y|m|d/)){
					g = 'date';
				} else if(p.match(/H|i|s/)){
					g = 'time';
				}
				a[a.length] = {value: formats[p], position: n, code: p, group: g};
			}
		} else {
			var re = new RegExp(p, 'g');
			s = s.replace(re, formats[p]);
		}
	}
	
	if(asObject){
		a.sort(function(v1, v2){ return v1.position < v2.position ? -1 : 1;});
		return a;
	} else {
		return s;
	}
}

function Utilities_parseDate(dateStr, formatStr, dDelimiter, tDelimiter){
	var dd = dDelimiter ? dDelimiter : '-';
	var td = tDelimiter ? tDelimiter : ':';
	var da = dateStr.split(' ');
	var fa = formatStr.split(' ');
	if(da.length != fa.length){
		throw {message: 'Utilities_parseDate exception: date and format strings are incompatible'};
	}
	
	var dt = new Date();
	var d = da[0].split(dd); //split with date delimiter
	var f = fa[0].split(dd); 
	if(d.length != f.length){
		throw {message: 'Utilities_parseDate exception: date and format strings have incompatible date syntax'};
	}
	for(var i = 0; i < d.length; i++){
		switch(f[i]){
			case 'Y':
			case 'y':
				dt.setFullYear(parseInt(d[i], 10)); 
				break;
			case 'm':
				dt.setMonth(parseInt(d[i], 10) - 1); break;
			case 'd':
				dt.setDate(parseInt(d[i], 10)); break;
		}		
	}
	
	if(da.length == 2){
		d = da[1].split(td); //split with time delimiter
		f = fa[1].split(td); 
		if(d.length != f.length){
			throw {message: 'Utilities_parseDate exception: date and format strings have incompatible time syntax'};
		}
		for(var i = 0; i < d.length; i++){
			switch(f[i]){
				case 'H':
					dt.setHours(d[i]); break;
				case 'i':
					dt.setMinutes(d[i]); break;
				case 's':
					dt.setSeconds(d[i]); break;
			}
		}
	}
	
	return dt;
}

function Utilities_formatNumber(n, p, td, dp){
	if(p){
		n = parseFloat(n);
		nStr = n.toFixed(p);
	} else {
		nStr = parseInt(n, 10);
	}
	
	nStr += '';
	if(!td)td = ',';
	if(!dp)dp = '.';
	x = nStr.split(dp);
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + td + '$2');
	}
	return x1 + x2;
}

function Utilities_parseURL(url){
	var ret = new Object();
	var n = url.indexOf('://');
	ret.protocol = n >= 0 ? url.substring(0, n) : null;
	var m = url.indexOf('?');
	ret.location = url.substring(n >= 0 ? n : 0, (m >= 0 ? m : url.length));
	ret.queryString = m >= 0 ? url.substring(m, url.length) : null;
	return ret;
}

//an xml mimic
function _XMLNode(tag){
	this.tag = tag;
	this.attributes = new Array();
	this.childNodes = new Array();
}

_XMLNode.prototype.setAttribute = function(name, val){
	this.attributes[name] = val;
}
_XMLNode.prototype.getAttribute = function(name){
	return this.attributes[name] ? this.attributes[name] : null;
}
_XMLNode.prototype.appendChild = function(xmlNode){
	this.childNodes[this.childNodes.length] = xmlNode;
	return xmlNode;
}
_XMLNode.prototype.getElementsByTagName = function(tag){
	var ar = new Array();
	for(var i = 0; i < this.childNodes.length; i++){
		if(this.childNodes[i].tag == tag){
			ar[ar.length] = this.childNodes[i];
		}
	}
	return ar;
}

function Utilities_createXMLNode(tag){
	return new _XMLNode(tag);
}
/* END GENERAL USEFUL FUNCS */

/* DOM STUFF */
function Utilities_getMousePosition(hWin, e){
	if(!e)e = hWin.event;
	var mouseX = (e.clientX ? e.clientX : e.pageX);
	var mouseY = (e.clientY ? e.clientY : e.pageY);
	if(navigator.userAgent.indexOf('Safari') == -1){ //make scroll correction for all browsers EXCEPT safari
		mouseX += hWin.document.body.scrollLeft;
		mouseY += hWin.document.body.scrollTop;
	}
	return {x: mouseX, y: mouseY};
}

function Utilities_getKeyCode(hWin, e){
	if(hWin.event){
		e = hWin.event;
		return e.keyCode;
	} else {
		return e.which;
	}
}

function Utilities_getKeyChar(hWin, e){
	return String.fromCharCode(Utilities_getKeyCode(hWin, e));
}

function Utilities_getDocSize(hWin, includeScroll){
	if(!hWin)hWin = window;
	var docwidth = null;
	var docheight = null;
	//opera Netscape 6 Netscape 4x Mozilla 
	if (hWin.innerWidth || hWin.innerHeight){ 
		docwidth = hWin.innerWidth; 
		docheight = hWin.innerHeight;
	} 
	//IE Mozilla 
	if (hWin.document.body.clientWidth || hWin.document.body.clientHeight){ 
		docwidth = includeScroll ? hWin.document.body.scrollWidth : hWin.document.body.clientWidth; 
		docheight = includeScroll ? hWin.document.body.scrollHeight : hWin.document.body.clientHeight; 
	} 
	return {width: docwidth, height: docheight};
}

function Utilities_getAbsolutePosition(elt){
	var left = elt.offsetLeft;
	var top = elt.offsetTop;
	var w = elt.offsetWidth;
	var h = elt.offsetHeight;
	while(elt && elt.offsetParent && (elt.offsetParent != null)){
		left += elt.offsetParent.offsetLeft;
		top += elt.offsetParent.offsetTop;
		elt = elt.offsetParent;
	}
	return {left: left, top: top, right: left + w, bottom: top + h, width: w, height: h};
}

function Utilities__getElementsByAttribute(elt, attr, elts){
	for(var i = 0; i < elt.childNodes.length; i++){
		var cn = elt.childNodes[i];
		if(cn.getAttribute && cn.getAttribute(attr) != null){
			elts[elts.length] = cn;
		}
		Utilities__getElementsByAttribute(cn, attr, elts);
	}
}

function Utilities_getElementsByAttribute(elt, attr){
	var elts = new Array();
	Utilities__getElementsByAttribute(elt, attr, elts);
	return elts;
}

function Utilities_insertElementAfter(eltToInsert, elt){
	try{
		if(!eltToInsert){
			alert('No element to insert');
			return;
		}
		if(!elt){
			alert('No element to insert after');
			return;
		}
		var parentElt = elt.parentNode;
		if(!parentElt){
			alert('Cannot find parent node for element with id ' + elt.id);
			return;
		}
		
		for(var i = 0; i < parentElt.childNodes.length; i++){
			if(parentElt.childNodes[i] == elt){
				if(parentElt.childNodes.length > i + 1){
					parentElt.insertBefore(eltToInsert, parentElt.childNodes[i + 1]);
				} else {
					parentElt.appendChild(eltToInsert);
				}
				break;
			}
		}
	} catch(e){
		alert('Utilities_insertElementAfter exception ' + e.message);
	}
}

function Utilities_createTableElement(hWin, rows, cols){
	try{
		var tbl = hWin.document.createElement("TABLE");
		tbl.cellSpacing = "0";
		tbl.cellPadding = "0";
		var tBody = hWin.document.createElement("TBODY");
		for(var i = 0; i < rows; i++){
			var tr = hWin.document.createElement("TR");
			for(var j = 0; j < cols; j++){
				tr.appendChild(hWin.document.createElement("TD"));
			}
			tBody.appendChild(tr);
		}
		tbl.appendChild(tBody);
		return tbl;
	} catch(e){
		throw e;
	}
}

function Utilities_getTableCell(tbl, row, col){
	try{
		var row = Utilities_getTableRow(tbl, row);
		return row.childNodes[col];
	} catch(e){
		alert('Utilities_getTableCell exception ' + e.message);
	} 
}


function Utilities_getTableRow(tbl, row){
	try{
		var tBody = tbl.firstChild;
		return tBody.childNodes[row];
	} catch(e){
		alert('Utilities_getTableRow exception ' + e.message);
	}
}

function Utilities_removeChildren(elt){
	if(elt && elt.childNodes && elt.childNodes.length){
		while(elt.lastChild)elt.removeChild(elt.lastChild);
	}
}

function Utilities_copyChildren(fromElt, toElt){
	Utilities_removeChildren(toElt);
	for(var i = 0; i < fromElt.childNodes.length; i++){
		toElt.appendChild(fromElt.childNodes[i]);
	}
}

function Utilities_hasParentOfType(elt, nodeName){
	if(!elt)return null;
	while(elt.nodeName != 'BODY'){
		if(elt.nodeName == nodeName){
			return elt;
		}
		elt = elt.parentNode;
	}
	return null;
}

function Utilities_getFlashMovie(hWin, movieName){
    if (navigator.appName.indexOf("Microsoft") != -1) {
		return hWin[movieName];
    } else {
        return hWin.document[movieName];
    }
}

function Utilities_getMetaData(hWin){
	var obj = new Object();
	var ar = hWin.document.getElementsByTagName('title');
	obj.title = ar[0].innerHTML ? true : false;
	ar = hWin.document.getElementsByTagName('meta');
	for(var i = 0; i < ar.length; i++){
		var m = ar[i];
		if(m.getAttribute('name')){
			var name = m.getAttribute('name').toLowerCase();
			switch(name){
				case 'keywords':
					obj.keywords = m.getAttribute('content');
					break;
				case 'description':
					obj.description = m.getAttribute('content');
					break;
			}
		}
	}
	return obj;
}
/* END DOM STUFF */

/* CSS STUFF */
function Utilities_getStyleProperty(elt, property, type){
	try{
		//first look directly at element if not there return css property
		if(!type)type = 'id';
		return elt.style[property] ? elt.style[property] : Utilities_getCSSProperty(elt.ownerDocument, type == 'id' ? elt.id : elt.className, property, type);
	} catch(e) {
		alert('Utilities_getStyleProperty exception: ' + e.message);
		return null;
	}
}

function Utilities_getCSSProperty(doc, idText, property, type){
	try{
		var selectorText;
		switch(type){
			case 'id':
				selectorText = navigator.userAgent.indexOf('Safari') != -1 ? '*[ID"' + idText + '"]' : '#' + idText; break;
			case 'class':
				selectorText = "." + idText; break;
		}
		var styleSheets = doc.styleSheets;
		for(var i = 0; i < styleSheets.length; i++){
			var ss = styleSheets[i];
			var cssRules = navigator.appName == 'Microsoft Internet Explorer' ? ss.rules : ss.cssRules;
			for(var j = 0; j < cssRules.length; j++){
				var cssRule = cssRules[j];
				var labels = cssRule.selectorText.split(',');
				for(var k = 0; k < labels.length; k++){
					if(labels[k] == selectorText){
						//here we have found what we are looking for
						return cssRule.style[property];
					}
				}
			}
		}
		return '';
	} catch(e){
		alert('Utilities_getCSSProperty exception: ' + e.message);
	}
}
/* END CSS STUFF */

/* XML STUFF */
function _processStateChange(req, url){
	if (req.readyState == 4){
		// only if "OK"
		try{
			//broadcast an event depending on status
			if(_xmlRequests[url]){
				var xmlReq = _xmlRequests[url];
				if(xmlReq.callBack != null){
					//Utilities_log('info', 'xml returned: ' + url);
					if(req.status == 200 && req.responseXML){
						var errors = req.responseXML.getElementsByTagName('error');
						xmlReq.callBack(xmlReq.obj, errors.length == 0 ? 1 : 0, req.responseXML, xmlReq.data);
						if(errors.length){
							Event_broadcast('ERROR_LOAD_XML', errors);
						}
					} else {
						xmlReq.callBack(xmlReq.obj, 0, null);
						Event_broadcast('ERROR_LOAD_XML', null);
					}
				}
				delete _xmlRequests[url];
			} else if(req.status != 200){
				Event_broadcast('ERROR_LOAD_XML', null);			
			}
		} catch (e) {
			Utilities_log('error', 'Utilities_processStateChange exception: ' + e.message);
		}
	}
}//end function


var _xmlRequests = new Array();
var _lastXMLCall = null;
function Utilities_loadXML(url, obj, callBack, method, postData){
	var req;
	try{
		if(!method)method = 'GET';
		method = method.toUpperCase();
		if (window.XMLHttpRequest){
			// branch for native XMLHttpRequest object
			req = new XMLHttpRequest();
		} else if (window.ActiveXObject){
			 // branch for IE/Windows ActiveX version
			req = new ActiveXObject("Microsoft.XMLHTTP");
		}
		
		var dt = new Date();
		if(url.indexOf('?') == -1){
			url += '?';
		} else {
			url += '&';
		}
		url += "epochtime=" + dt.getTime();
		if(req && _processStateChange){
			req.onreadystatechange = function(){ _processStateChange(req, url); };
		}
		
		req.open(method, url, true);
		
		if(method == 'POST'){
			req.setRequestHeader("Content-Type","application/x-www-form-urlencoded") ;
			req.setRequestHeader("Accept","text/xml,application/xml,text/plain") ;
			req.send(postData);
		} else {
			req.send(null);
		}
		
		_xmlRequests[url] = {obj: obj, callBack: callBack, data: new Object()};
		
		var loadTime;
		_lastXMLCall = dt.getTime();
		//Utilities_log('info', 'xml requested: ' + url);
		Event_broadcast('LOAD_XML', url);
		
		return _xmlRequests[url];
	} catch (e){
		alert('Utilities_loadXML exception ' + e.message);
	}
}

function Utilities_cancelXML(obj){
	for(var u in _xmlRequests){
		if(_xmlRequests[u].obj == obj){
			//Utilities_log('info', 'xml cancelled: ' + u);
			_xmlRequests[u].callBack = null;
		}
	}
}

function Utilities_getLastXMLCall(){
	return _lastXMLCall;
}

function Utilities_processXMLErrors(hWin, xml){
	try{
		if(xml){
			errors = xml.getElementsByTagName('error');
			for(var i = 0; i < errors.length; i++){
				var e = errors[i];
				var usrMsg = Utilities_unescape(e.getAttribute('usermsg'));
				var code = parseInt(e.getAttribute('code'), 10);
				if(code == 0){
					hWin.alert(usrMsg);
				}
				Utilities_log('error', usrMsg);
			}
			return errors.length;
		} else {
			hWin.alert('Utilities_processXMLErrors no xml object found');
			return false;
		}
	} catch(e) {
		top.Utilities_log('error', 'Utilities_processXMLErrors exception: ' + e.message);
		return false;
	}
}

function Utilities_processXMLResponse(hWin, xml){
	try{
		if(xml){
			confirms = xml.getElementsByTagName('confirm');
			for(var i = 0; i < confirms.length; i++){
				var c = confirms[i];
				return {confirmed: hWin.confirm(c.getAttribute('usermsg')), confirmOn: c.getAttribute('confirmon')};
			}
			Utilities_processXMLErrors(hWin, xml);
			return null;
		} else {
			hWin.alert('Utilities_processXMLResponse no xml object found');
			return false;
		}
	} catch(e) {
		top.Utilities_log('error', 'Utilities_processXMLResponse exception: ' + e.message);
		return false;
	}
}

function Utilities_getNode(nodeName, parentNode){
	try{
		var nodeName = nodeName.toLowerCase();
		if(parentNode.childNodes.length){
			for(var i = 0; i < parentNode.childNodes.length; i++){
				var node = parentNode.childNodes[i];
				if(nodeName == node.nodeName.toLowerCase()){
					return node;
				}
			}
		}
		return null;
	} catch (e){
		alert('Utilities_getNode exception ' + e.message);
	}
}

function Utilities_getNodes(nodeName, parentNode, deepSearch){
	try{
		var nodeName = nodeName.toLowerCase();
		var nodes = new Array();
		if(parentNode.childNodes.length){
			for(var i = 0; i < parentNode.childNodes.length; i++){
				if(deepSearch){
					var ar = Utilities_getNodes(nodeName, parentNode.childNodes[i]);
					for(var j = 0; j < ar.length; j++){
						nodes[nodes.length] = ar[j];
					}
				}
				var node = parentNode.childNodes[i];
				if(nodeName == node.nodeName.toLowerCase()){
					nodes[nodes.length] = node;
				}
			}
		}
		return nodes;
	} catch (e){
		alert('Utilities_getNodes exception ' + e.message);
	}
}
/* END XML STUFF */

/* UI STUFF */
function Utilities_openPopup(hWin, url, name, width, height, xtras){
	try{
		var left = (screen.width - width)/2;
		var top = (screen.height - height)/2;
		var features = "status=yes,resizable=no,scrollbars=1,";
		features += "left=" + left + ",top=" + top + ",width=" + width + ",height=" + height;
		name = name.replace(/\//g, '_');
		var hPWin = hWin.open(url, name, features);
		hPWin.focus();
		return hPWin;
	} catch(e){
		alert('Utilities_openPopup exception ' + e.message);
		throw e;
	}
}

function Utilities_resize(hWin, width, height){
	try{
		var left = (screen.width - width)/2;
		var top = (screen.height - height)/2;
		hWin.moveTo(left, top);
		hWin.resizeTo(width, height);
	} catch(e){
		alert('Utilities_openPopup exception ' + e.message);
		throw e;
	}
}

function Utilities_addButtonRollovers(hWin, def, hil){
	try{
		var buttons = hWin.document.getElementsByName('button');
		for(var i = 0; i < buttons.length; i++){
			var btn = buttons[i];
			var ar = btn.src.split("/");
			var filename = ar[ar.length - 1];
			var path = btn.src.substring(0, btn.src.length - filename.length);
			var prefix = filename.substring(0, filename.length - def.length);
			btn.fileData = {prefix: path + prefix, def: def, hil: hil};
			if(filename.indexOf(hil) == -1){
				btn.onmouseover = function(){
					this.src = this.fileData.prefix + this.fileData.hil;
				}
				btn.onmouseout = function(){
					this.src = this.fileData.prefix + this.fileData.def;
				}
			}
			btn.border = 0;
			
			//preload
			var img = new Image();
			img.src = btn.fileData.prefix + btn.fileData.hil;
		}
	} catch(e){
		alert('Utilities_addButtonRollovers exception: ' + e.message);
	}
}

function Utilities_appendCover(hWin, className, contentElt){
	try{
		var cover = new Object();
		var elt = hWin.document.createElement("DIV");
		elt.className = className;
		elt.innerHTML = '&nbsp;';
		elt.style.position = "absolute";
		elt.style.left = hWin.document.body.scrollLeft + "px";
		elt.style.top = hWin.document.body.scrollTop + "px";
		elt.style.width="100%";
		elt.style.height="100%";
		
		hWin.document.body.appendChild(elt);
		cover.bg = elt;
		elt = Utilities_createTableElement(hWin, 1, 1);
		elt.style.position = "absolute";
		elt.style.left = hWin.document.body.scrollLeft + "px";
		elt.style.top = hWin.document.body.scrollTop + "px";
		elt.style.width="100%";
		elt.style.height="100%";
		var td = Utilities_getTableCell(elt, 0, 0);
		td.valign = "middle";
		td.align = "center";
		td.appendChild(contentElt);
		hWin.document.body.appendChild(elt);
		cover.fg = elt;
		return cover;
	} catch (e) {
		alert("Utilities_appendCover exception " + e.message);
	}
}

function Utilities_removeCover(cover){
	try{
		if(cover){
			if(cover.bg && cover.bg.parentNode){
				cover.bg.parentNode.removeChild(cover.bg);
			}
			if(cover.fg && cover.fg.parentNode){
				cover.fg.parentNode.removeChild(cover.fg);
			}
		}
	} catch (e) {
		alert("Utilities_removeCover exception " + e.message);
	}
}

//EVENTS STUFF
_events = new Array();
function Event_register(eventNames, obj){
	try{
		if(!obj.handleEvent){
			alert('Event_reigster passed object does not have a handleEvent method');
			return false;
		}
		
		if(typeof eventNames == 'string'){
			eventNames = [eventNames];
		}
		
		for(var j = 0; j < eventNames.length; j++){
			var eventName = eventNames[j];
			var exists = false;
			for(var i = 0; i < _events.length; i++){
				var e = _events[i];
				if(e.name == eventName && e.obj == obj){
					_events[i] = {name: eventName, obj: obj};
					exists = true;
					break;
				}
			}
			if(!exists){
				_events[_events.length] = {name: eventName, obj: obj};
			}
		}
		return true;
	} catch(e) {
		alert('Event_reigster exception ' + e.message);
	}
}
function Event_unregister(eventNames, obj){
	try{
		if(typeof eventNames == 'string'){
			eventNames = [eventNames];
		}
		
		for(var j = 0; j < eventNames.length; j++){
			var eventName = eventNames[j];
			for(var i = 0; i < _events.length; i++){
				var e = _events[i];
				if(e.obj == obj && e.name == eventName){
					_events.splice(i, 1);
				}
			}
		}
	} catch(e) {
		alert('Event_unreigster exception ' + e.message);
	}
}

var _eventQueue = new Array();
function Event_broadcast(eventName, eventData, delay){
	_eventQueue[eventName] = {eventName: eventName, eventData: eventData};
	if(delay){
		setTimeout("Event_broadcastQueueMember('" + eventName + "')", delay);
	} else {
		var hitCount = 0;
		for(var i = 0; i < _events.length; i++){
			var e = _events[i];
			if(e.name == eventName && e.obj){
				e.obj.handleEvent(eventName, eventData);
				hitCount++;
				top.Utilities_log('info', 'event ' + eventName);
			}
		}
		return hitCount;	
	}
}
function Event_broadcastQueueMember(eventName){
	var eventData = _eventQueue[eventName].eventData;
	if(eventData){
		Event_broadcast(eventName, eventData);
		delete _eventQueue[eventName];
	}
}
//END EVENTS STUFF

//LOG
var _log = new Array();
var _logIdx = 0;
var _logSize = 100;
function Utilities_log(msgType, msg){
	var dt = new Date();
	var t = (dt.getHours() < 10 ? '0' : '') + dt.getHours();
	t += ':' + (dt.getMinutes() < 10 ? '0' : '') + dt.getMinutes();
	t += ':' + (dt.getSeconds() < 10 ? '0' : '') + dt.getSeconds();
	_log[_logIdx] = {time: t, type: msgType, msg: msg};
	_logIdx = _logIdx == _logSize - 1 ? 0 : _logIdx + 1;	
}
function Utilities_getLog(){
	var ar = new Array();
	for(var i = 0; i < _logSize; i++){
		var idx = _logIdx - i - 1;
		if(idx < 0){ 
			if(_log.length == _logSize){
				idx = _logSize + idx;
			} else {
				break;
			}
		}
		ar[ar.length] = _log[idx];
	}
	return ar;
}
function Utilities_clearLog(){
	_log = new Array();
	_logIdx = 0;
}
//END LOG

//PERMISSIONS BASED STUFF
function Utilities_hasPermission(pType, pVal){
	switch(pType){
		case 'select':
			return ((pVal & 1) == 1);
		case 'insert':
			return ((pVal & 2) == 2);
		case 'update':
			return ((pVal & 4) == 4);
		case 'delete':
			return ((pVal & 8) == 8);
		case 'publish':
			return ((pVal & 16) == 16);
	}
	return false;	
} 
//END PERMISSIONS BASED STUFF

//COOKIES
function Utilities_setCookie(name, value, days, path){
	var exdate=new Date();
	exdate.setDate(exdate.getDate()+days);
	var s = name+ "=" +escape(value)+((days==null) ? "" : ";expires="+exdate.toGMTString()) + (path ? ";path=" + path : '');
	document.cookie= s
}
function Utilities_getCookie(c_name){
	if (document.cookie.length>0){
  		var c_start=document.cookie.indexOf(c_name + "=");
		if (c_start!=-1){ 
			c_start=c_start + c_name.length+1; 
			c_end=document.cookie.indexOf(";",c_start);
			if (c_end==-1) c_end=document.cookie.length;
			return unescape(document.cookie.substring(c_start,c_end)); 
		}
	}
	return null;
}
//END COOKIES
