
// globals to identify the current browser.
var BrowserIsIE = (navigator.appName.indexOf("Microsoft") != -1);
var BrowserIsNN4x = (navigator.appName == "Netscape" && parseInt(navigator.appVersion)==4);
var BrowserIsNN6x = (navigator.appName == "Netscape" && parseInt(navigator.appVersion)>=5);	// also describes Mozilla.
// global to identify Mac OS.
var ComputerIsAMac = navigator.platform.indexOf("Mac") != -1;

// this gives access to page elements appropriate to each browser environment.
// these references are used to change content & appearance dynamically w/o reloading the page.
function getObjectRef(aDocumentObject){
	var objRef;
	
	if (BrowserIsIE && ComputerIsAMac){
		objRef = document[aDocumentObject];
	} else if (BrowserIsNN4x) {	// note: in NN4x we can only change layers dynamically.
		objRef = eval("document." + aDocumentObject);
		//objRef = document.layers[aDocumentObject+ "-layer"];
	} else {
		objRef = document.getElementById(aDocumentObject);
	}
	return objRef;
}

// this script adds a function to an eventHandler,
// allowing us to daisy-chain functions (eg; dynamically set up initialization
// for various scripts to be triggered w onLoad).
// 
function doOnEvent(anElement, anEventName, aFunction){
	if (anElement.attachEvent){
		anElement.attachEvent("on"+anEventName, aFunction);
	} else if (anElement.addEventListener){
		anElement.addEventListener(anEventName, aFunction, false);
	} else {
		var anEventHandler = anElement["on"+anEventName];
		var prevEventHandler = function(){};
		if (anEventHandler instanceof Function) prevEventHandler = anEventHandler;
		anEventHandler = function(evt) {
			prevEventHandler.call(evt);
			aFunction.apply(args);
		}
	}
}

function showDivAtLoc(divObj, locObj){
	with (divObj.style){		
		display = "block";
		visibility = "visible";
		left = locObj[0]+"px";
		top = locObj[1]+"px";
	}
}

function hideDiv(divObj){
	with (divObj.style){	
		display = "none";
		visibility = "inherit";
	}
}

function isVisible(obj){
	if (obj.style == undefined) return false;
	if (obj.style.visibility == undefined) return false;
	
	with (obj.style){
		switch (visibility){
			case "visible":
				if (display != undefined){
					return (display != "none");
				} else {
					return true;
				}
				break;
				
			case "inherit":
				if (obj.offsetParent != undefined){
					return isVisible(obj.offsetParent);
				} else if (obj.parentElement != undefined){
					return isVisible(obj.parentElement);
				} else {
					return (display != "none");
				}
				break;
				
			default:
				return false;
				break;
		}
	}
}

function getWinCenter(){
	var parentWinWidth = (BrowserIsIE) ? (document.documentElement) ? document.documentElement.scrollWidth : document.body.scrollWidth : window.innerWidth;
	var parentWinHeight = (BrowserIsIE) ? (document.documentElement) ? document.documentElement.scrollHeight : document.body.scrollHeight : window.innerHeight;
	return [parentWinWidth/2, parentWinHeight/2];
}

function showDivCentered(divObj, divTop, xNudge){
	parentWinWidth = (BrowserIsIE) ? (document.documentElement) ? document.documentElement.scrollWidth : document.body.scrollWidth : window.innerWidth;
	parentWinHeight = (BrowserIsIE) ? (document.documentElement) ? document.documentElement.scrollHeight : document.body.scrollHeight : window.innerHeight;
	// provide default if w & h not passed in.
	if (divObj.style.top==0) divObj.style.top = "-10000px"; // hide it on first appearance while we update.
	divObj.style.display = "block";
	var r = getObjectRect(divObj);
	var divWidth=r.right-r.left;
	var divHeight=r.bottom-r.top;
	// set div position.
	var divLeft = Math.floor((parentWinWidth/2) - (divWidth/2)) 
	divLeft += (BrowserIsIE) ? (document.documentElement) ? document.documentElement.scrollLeft : document.body.scrollLeft : window.scrollX;
	if (xNudge != undefined){
		divLeft += xNudge;
	}
	if (divTop == undefined){
		divTop = Math.floor((parentWinHeight/2) - (divHeight/2));
		divTop += (BrowserIsIE) ? (document.documentElement) ? document.documentElement.scrollTop : document.body.scrollTop : window.scrollY;
	}		
	with (divObj.style){		
		visibility = "visible";
		display = "block";
		left = divLeft+"px";
		top = divTop+"px";
	}
}

// returns a list of enclosing tags, up until the one specified (default is body tag).
function getPathToEnclosingTag(element, tagName, pathStr){
	tagName = (tagName==undefined) ? "body" : tagName;
	pathStr = (pathStr==undefined) ? "" : pathStr;
	// use id or name attributes as elTagName, defaulting to actual tag name.
	if (element==undefined) return;	// we never found the enclosing tag identifier.
	var elTagName = element.tagName.toLowerCase();
	elTagName = (element.attributes.src) ? element.attributes.src.value : (element.attributes.id) 
										? element.attributes.id.value : (element.attributes.name) 
										? element.attributes.name.value : elTagName;
	pathStr = (pathStr) ? (elTagName +"."+ pathStr) :elTagName;
	if(elTagName==tagName)return pathStr;
	return getPathToEnclosingTag(element.parentElement, tagName, pathStr);
}

// returns the current screen location of any page element.
function getScreenLoc(element, offset){
	if (element==undefined){
		return offset;
	}
	if (offset == undefined){
		offset = new Array(2);
		offset[0] = 0;
		offset[1] = 0;
	}
	if (element.offsetLeft) offset[0] += element.offsetLeft;
	if (element.offsetTop) offset[1] += element.offsetTop;
	//
	if (element == document.body){
		return offset;
	}
	var parent = (element.offsetParent) ? element.offsetParent : (element.parentElement) ? element.parentElement : (element.parentNode) ? element.parentNode : null;
	// alert(element.id+", offset:"+unpack(offset));
	return getScreenLoc(parent, offset);
}

function getObjectRect(obj){
	var objRect;
	if (BrowserIsIE){
		objRect = obj.getBoundingClientRect();
		objRect.top += document.body.scrollTop;
		objRect.bottom += document.body.scrollTop;
		objRect.left += document.body.scrollLeft;
		objRect.right += document.body.scrollLeft;
	} else {
		objRect = new Object();
		var objTopLeft = getScreenLoc(obj);		
		objRect.left = objTopLeft[0];
		objRect.top = objTopLeft[1];
		objRect.right = objTopLeft[0]+obj.scrollWidth;
		objRect.bottom = objTopLeft[1]+obj.scrollHeight;
	}	
	objRect.width = (objRect.right - objRect.left);
	objRect.height = (objRect.bottom - objRect.top);
	return objRect;
}

//
function getMouseLoc(evt){
	var mLoc = new Array(2);
	if (BrowserIsIE){
		mLoc[0] = (window.event.clientX + document.body.scrollLeft);
		mLoc[1] = (window.event.clientY + document.body.scrollTop);
	} else if (BrowserIsSafari){
		mLoc[0] = (evt.clientX);
		mLoc[1] = (evt.clientY);
	} else {
		mLoc[0] = (evt.clientX + document.body.scrollLeft);
		mLoc[1] = (evt.clientY + document.body.scrollTop);
	}
	return mLoc;
}

// returns the closest container whose id starts with <prefix>, before the specified <delim> character 
// (eg; returns "book_1" if the <startElement> is contained in the document element "book_1", the prefix is "book", and the delim is "_").
function getContainerByPrefix(startElement, prefix, delim){
	if (getLeft(startElement.id, delim) == prefix) return startElement;
	if (startElement.offsetParent!=undefined){
		return getContainerByPrefix(startElement.offsetParent, prefix, delim);
	} else if (startElement.parentElement!=undefined){
		return getContainerByPrefix(startElement.parentElement, prefix, delim);
	} else {
		return;	// failed to find a matching element, having gone all the way up to the BODY element.
	}
}


// find the first directory element in partialURL and build a new absolute URL from it,
// starting from the absolute URL of the current page.
function getAbsoluteURL(partialURL, rootDir){
	// if partialURL is actually an absolute URL already, just return it.
	if (partialURL.indexOf("http")>-1 || partialURL.indexOf("://")>-1) return partialURL;
    var currURL = window.location.href;
    var currURL_array = currURL.split("/");
    var partialURL_array = partialURL.split("/");
    var rootDir = (rootDir) ? rootDir : partialURL_array[0];
    var newAbsURL_array = new Array();
    var newAbsURL = "";
    for (var i=1; i<currURL_array.length; i++){
        if (currURL_array[i]==rootDir){
            newAbsURL_array = currURL_array.slice(0, i);
            break;
        }
    }
    newAbsURL_array = newAbsURL_array.concat(partialURL_array);
    newAbsURL = newAbsURL_array.join("/");
	return newAbsURL;
}

function nav(partialURL){
	absURL = getAbsoluteURL(partialURL);
    window.location.href = absURL;
}

/* String utilities */
// returns the characters in str leading up to the delimiter.
function getLeft(str, delim){
	var delimPos = str.indexOf(delim);
	if (delimPos == -1) return str;
	var leftStr = str.substring(0, delimPos);
	return leftStr;
}
// returns the characters in str following the delimiter.
function getRight(str, delim){
	var delimPos = str.indexOf(delim);
	if (delimPos == -1) return str;
	var rightStr = str.substring(delimPos+1);
	return rightStr;
}
function getRightMost(str, delim){
	var rt = getRight(str, delim);
	if (rt == str){
		return rt;
	} else {
		return getRightMost(rt, delim);
	}
}

// returns contents of a link.
function getLinkText(linkObj){
	if (BrowserIsNN4x){
		return linkObj.text;
	} else {
		return linkObj.innerHTML;
	}
}

function getWinContentSize(){
	var o = { width:0, height:0 };
	if (BrowserIsIE){
		o.width = document.body.clientWidth;
		o.height = document.body.clientHeight;
	} else if (BrowserIsNN4x || BrowserIsNN6x){
		o.width = window.innerWidth;
		o.height = window.innerHeight;
	} else {
		o.width = window.width;
		o.height = window.height;
	}
	return o;
}

function unpack(obj){
	var report = new Array();
	for (var m in obj){
		report.push(m +":"+ obj[m]);
	}
	return report.join();
}

function wait(){
	with (document.body.style){
		cursor = "wait";
	}
}
function endWait(){
	with (document.body.style){
		cursor = "auto";
	}
}

/* reloads a SWF, to send cmds, for ex. */
function reloadObjectTag(obj, addParams){
	var numParamNodes = obj.childNodes.length;
	var newParamNodesHTML = "";
	for (var i=0; i<numParamNodes; i++){
		var ithParamNode = obj.childNodes[i];
		var ithParamAttrs = ithParamNode.attributes;
		if (ithParamAttrs != undefined){
			var paramName = ithParamAttrs.getNamedItem("name").value;
			var paramVal = ithParamNode.getAttribute("value");
			//
			if (paramName == "movie"){
				paramVal = paramVal.split("?")[0]+"?"+addParams;
			}
			if (ithParamNode.nodeName == "PARAM"){
				newParamNodesHTML += '<param name="'+paramName+'" value="'+paramVal+'" />';
			} else if (ithParamNode.nodeName == "EMBED"){
				var embedHTML = "<EMBED ";
				var numAttrs = ithParamNode.attributes.length;
				for (var j=0; j<numAttrs; j++){
					var jthAttr = ithParamNode.attributes[j];
					if (jthAttr.name=="src"){
						embedHTML += (jthAttr.name+"='"+jthAttr.value.split("?")[0]+"?"+addParams+"' ");
					} else {
						embedHTML += (jthAttr.name+"='"+jthAttr.value+"' ");
					}
				}
				embedHTML += "/>";
				newParamNodesHTML += embedHTML;
			}
		}	
	} 
	obj.innerHTML = newParamNodesHTML;
}

/******************************************/
// Style Sheet manipulation. Very cool.
/******************************************/
function getStyleSheetById(id){
	for(var i=0; i<document.styleSheets.length; i++){
		var ithStyleSheet = document.styleSheets[i];
		if (BrowserIsSafari){
			return 0;
			/*
			var styleSheetName = (ithStyleSheet.href) ? ithStyleSheet.href : (ithStyleSheet.name) ? ithStyleSheet.name : "unnamed stylesheet";
			alert("ID:"+id+", "+styleSheetName.split("/").pop());
				for(var j=0; j<ithStyleSheet.rules.length; j++){
					alert("ID:"+id+", "+ithStyleSheet.rules[j].selectorText);
				}
			*/
		} else {
			if (ithStyleSheet.id==id || ithStyleSheet.title==id){
				return ithStyleSheet;
			}
		}
	}
}
function addStyleRule(styleSheet, ruleID, ruleText){
	// Can't figure out how to get imported stylesheets by id/title through Safari,
	// so we'll just cycle through them all until we find the rule we want to modify.
	// cycle backwards, so if a rule is repeated, we're modifying the one that has effect.
	if (BrowserIsSafari){
		var classID = "."+ruleID.split(".").pop(); // have to come up with code for # & compound selectors.
		for(var i=document.styleSheets.length-1; i>=0; i--){
			var ithStyleSheet = document.styleSheets[i];
			for (var j=0; j<ithStyleSheet.rules.length; j++){
				var ithRule = ithStyleSheet.rules[j];
				if (classID==ithRule.selectorText){	
					var ruleProperty = ruleText.split(":")[0].slice(1);	// slice(1) gets rid of leading space.
					var ruleValue= ruleText.split(":")[1].slice(0, -1);  // slice(0, -1) gets rid of trailing semicolon.
					ithRule.style[ruleProperty] = ruleValue;
					break;
				}
			}
		}
	} else if (BrowserIsIE){
		if (styleSheet==undefined) return;
		styleSheet.addRule(ruleID, ruleText);
	} else {
		if (styleSheet==undefined) return;
		return styleSheet.insertRule(ruleID+'{'+ruleText+'}', styleSheet.cssRules.length);
	}
}
function removeStyleRule(styleSheet, ruleID){
	// this looks weird because Safari tells us it is IE.
	if (BrowserIsSafari || !BrowserIsIE){
		// find the rule
		ruleID = ruleID.toLowerCase();
		for (var i=styleSheet.cssRules.length-1; i>=0; i--){
			if (styleSheet.cssRules[i].selectorText!=undefined){
				var selectorText = styleSheet.cssRules[i].selectorText.toLowerCase();
				if (selectorText==ruleID){
					break;
				}
			}
		}
		styleSheet.deleteRule(i);
	} else {
		// find the rule
		ruleID = ruleID.toLowerCase();
		for (var i=styleSheet.rules.length-1; i>=0; i--){
			if (styleSheet.rules[i].selectorText!=undefined){
				var selectorText = styleSheet.rules[i].selectorText.toLowerCase();
				if (selectorText==ruleID){
					break;
				}
			}
		}
		styleSheet.removeRule(i);
	}
}

/* Generic Form validation (just completeness) */
function checkFormCompleteness(formName, elementNamesArray){
	theForm = getObjectRef(formName);
	for (var i=0; i<elementNamesArray.length; i++){
		var ithElementName = elementNamesArray[i];
		var ithElement = theForm[ithElementName];
		if (ithElement==undefined){
			alert(formName+" cannot be validated, as it does not contain the expected element "+ithElementName+".");
		} else if (ithElement.value==""){
			alert("The "+ithElementName+" field must be completed when submitting the form "+formName+".");
			return false;
		} 
	}
	return true;
}


/******************************************/
// STD object to hold any URL-encoded vars.
/******************************************/
function getURLVars(){
	var fullurl = document.location.href;
	var varStr = fullurl.substring(fullurl.indexOf('?')+1, fullurl.length)
	var nvPairs = varStr.split("&");
	var o = new Object();
	for (var i=0; i<nvPairs.length; i++){
		var ithPair = nvPairs[i].split("=");
		var ithName = ithPair[0];
		var ithValue= ithPair[1];
		if (ithName!=undefined && ithValue!=undefined) o[ithName] = ithValue;
	}
	return o;
}

var urlVars = getURLVars();


/******************************************/
// Safe file names.
/******************************************/
function stripInvalidVarChars(theStr){
  var retVal = stripChars(theStr, " ~!@#$%^&*()+|`-=\\{}[]:\";'<>,./?");
  return retVal;
}

function stripChars(theStr, theFilter){
  var retVal = "";
  if (theStr && theFilter)
	retVal = theStr.replace(RegExp("[" + escRegExpChars(theFilter) + "]", "g"), "")
  return retVal;
}

function escRegExpChars(regString) {
	var retVal = regString;
			
	retVal = retVal.replace(/\\/g, "\\\\");
	retVal = retVal.replace(/\//g, "\\/");
	retVal = retVal.replace(/\./g, "\\.");
	retVal = retVal.replace(/\*/g, "\\*");
	retVal = retVal.replace(/\+/g, "\\+");
	retVal = retVal.replace(/\?/g, "\\?");
	retVal = retVal.replace(/\|/g, "\\|");
	retVal = retVal.replace(/\$/g, "\\$");
	retVal = retVal.replace(/\^/g, "\\^");
	retVal = retVal.replace(/\(/g, "\\(");
	retVal = retVal.replace(/\)/g, "\\)");
	retVal = retVal.replace(/\[/g, "\\[");
	retVal = retVal.replace(/\]/g, "\\]");
	retVal = retVal.replace(/\{/g, "\\{");
	retVal = retVal.replace(/\}/g, "\\}");
	retVal = retVal.replace(/\-/g, "\\-");
	
	return retVal;
}