﻿// ----------------------------------------------------------- //
//                        clientBase                           //
// ----------------------------------------------------------- //
function debugLog() { this.clear(); }
debugLog.prototype.clear = function()
{
	this.element = null;
}
debugLog.prototype.log = function(theMsg)
{
	if (this.element)
	{
        newDiv = document.createElement('div');
        this.element.appendChild(newDiv);
       	newDiv.appendChild(document.createTextNode(theMsg));
    }
}



// ----------------------------------------------------------- //
//                       ajaxRequestor                         //
// ----------------------------------------------------------- //
function ajaxRequestor() { this.clearAll(); }

ajaxRequestor.prototype.__defaultError = function(sender)
{
	var tempStr = "ajaxRequestor Error:\n" +
                  "status: " + this.requestor.status + "\n" +
	 	          "headers: " + this.requestor.getAllResponseHeaders();
	alert(tempStr);
}
ajaxRequestor.prototype.__defaultSuccess = function(sender)
{
	alert("ajaxRequestor successfully returned from a request - but there is no handler assigned to receive it");
}
ajaxRequestor.prototype.__decodeString = function(inputStr)
{
	var decoded = unescape(inputStr);
	decoded = decoded.replace(/\%2F/g, "/"); 
	decoded = decoded.replace(/\%3F/g, "?");
	decoded = decoded.replace(/\%3D/g, "=");
	decoded = decoded.replace(/\%26/g, "&");
	decoded = decoded.replace(/\%40/g, "@");
	return decoded;
}
ajaxRequestor.prototype.__encodeString = function(inputStr)
{
	var encoded = escape(inputStr);
	encoded = encoded.replace(/\//g,"%2F");
	encoded = encoded.replace(/\?/g,"%3F");
	encoded = encoded.replace(/=/g,"%3D");
	encoded = encoded.replace(/&/g,"%26");
	encoded = encoded.replace(/@/g,"%40");
	return encoded;
}
ajaxRequestor.prototype.__getParams = function()
{
	if (this.getNames.length == 0) { return ""; }
	var out = (this.url.indexOf('?') == -1) ? '?' : '&';
	for (var i=0; i<this.getNames.length; i++)
	{
		out += this.getNames[i] + '=' + this.getValues[i];
		if (i < (this.getNames.length - 1)) { out += '&'; }
	}
	return out;
}
ajaxRequestor.prototype.__getRequestor = function()
{
	this.requestor = null;
    if (window.XMLHttpRequest) {
    	this.requestor = new XMLHttpRequest();
    } else if (typeof ActiveXObject != "undefined") {
    	this.requestor = new ActiveXObject("Microsoft.XMLHTTP");
    }
}
ajaxRequestor.prototype.__onRTS = function()
{
//debug.log('rs=' + this.requestor.readyState);
//debug.log('status=' + this.requestor.status);
//debug.log('lastResponse=' + this.requestor.responseText);
//debug.log('');
    if (this.requestor.readyState == 4)
	{
//alert(this.requestor.responseText);
		if (this.masterStatus) { this.masterStatus.handleChange(false); }
		if ((this.requestor.status==200) || (this.requestor.status==0))
		{
			this.lastResponse = this.__decodeString(this.requestor.responseText);
//debug.log(this.lastResponse);
			if (!this.lastResponse) 
			{
				top.location = this.onUnrecognized;
				return false;
			}
			if (this.xmlHandler) 
			{
				this.xmlHandler.importXML(this.lastResponse); 
			}
			this.onSuccess(this);
		} else {
//debug.log('ERROR: ' + this.lastResponse);
			this.onError(this);
		}
		this.busy = false;
	}
}
ajaxRequestor.prototype.__postParams = function()
{
	var out = "";
	var varNames = '';
	for (var i=0; i<this.postNames.length; i++)
	{
		if (i > 0) { varNames += '|'; }
		varNames += this.postNames[i];
		if (i > 0) { out += '&'; }
		out += this.postNames[i] + '=' + this.__encodeString(this.postValues[i]);
	}
	if (out) { out += '&' + 'ajax_var_names=' + varNames; }
	return out;
}
ajaxRequestor.prototype.clear = function()
{
	this.methodPost = true;
	this.__transStatus = 0;
	this.__transBusy = false;
    this.lastResponse = new String();
    this.newRequest();
}
ajaxRequestor.prototype.clearAll = function()
{
    this.xmlHandler = null;
    this.masterStatus = null;
    this.onUnrecognized = new String();

    this.onError = this.__defaultError;
    this.onSuccess = this.__defaultSuccess;
    
    this.clear();
}
ajaxRequestor.prototype.execute = function()
{
	if (this.busy) { return false; }
	
	this.__getRequestor();

	if (!this.requestor) {
		alert("You cannot dispatch a request on this machine (no viable XMLHTTPRequestor)");
		return "";
	}
	if (!this.url) {
		alert("You must supply a URL to ajaxRequestor to process a request");
		return "";
	}

	this.busy = true;
	var httpMethod = (this.methodPost) ? 'POST' : 'GET';

	var theURL = this.url;
	theURL += this.__getParams();
	this.lastRequest = theURL;
	
	var loader = this;
	this.requestor.onreadystatechange = function() { loader.__onRTS.call(loader); }
	if (this.masterStatus) { this.masterStatus.handleChange(true); }

    this.requestor.open('POST', theURL, true);
    this.requestor.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");    
    this.requestor.send(this.__postParams());
    
}
ajaxRequestor.prototype.getParam = function(key, value)
{
	var ptr = this.getNames.length;
	for (var i=0; i<this.getNames.length; i++)
	{
		if (this.getNames[i] == key) { ptr = i; }
	}
	this.getNames[ptr] = key;
	this.getValues[ptr] = value;
}
ajaxRequestor.prototype.method = function(doPost)
{
	this.methodPost = (doPost);
}
ajaxRequestor.prototype.newRequest = function()
{
	this.getNames = new Array();
	this.getValues = new Array();
	this.postNames = new Array();
	this.postValues = new Array();
	this.url = '';
}
ajaxRequestor.prototype.postParam = function(key, value)
{
	var ptr = this.postNames.length;
	for (var i=0; i<this.postNames.length; i++)
	{
		if (this.postNames[i] == key) { ptr = i; }
	}
	this.postNames[ptr] = key;
	this.postValues[ptr] = value;
}



// ----------------------------------------------------------- //
//                       transmitState                         //
// ----------------------------------------------------------- //
function transmitState() { this.clear(); }

transmitState.prototype.clear = function()
{
	this.busyCount = 0;
	this.onChange = null;
	this.busy = false;
}
transmitState.prototype.handleChange = function(busy)
{
        if (busy) { this.busyCount++; }
        if (!busy) { this.busyCount--; }
        if (this.busyCount < 0) { this.busyCount = 0; }
        if (this.busyCount)
        {
                if (!this.busy) { if (this.onChange) { this.onChange(true); } }
                this.busy = true;
        } else {
                if (this.busy) { if (this.onChange) { this.onChange(false); } }
                this.busy = false;
        }
}





// ----------------------------------------------------------- //
//                       dirtyElement                          //
// ----------------------------------------------------------- //
function dirtyElement() { this.clear(); }
dirtyElement.prototype.clear = function()
{
	this.dirtyList = new Array();
	this.dirtyIDX = new Array();
	this.onChange = null;
	this.isDirtyAny = false;
}
dirtyElement.prototype.clearDirty = function(theName) 
{ 
	this.dirtyList[theName] = false;
	this.isDirtyAny = false;
	for (var i=0; i<this.dirtyIDX.length; i++)
	{
		var thisName = this.dirtyIDX[i];
		if (this.dirtyList[thisName]) { this.isDirtyAny = true; }
	}
	if ( (!this.isDirtyAny) && (this.onChange) ) { this.onChange(false, theName); }
}
dirtyElement.prototype.clearDirtyAll = function()
{
	for (var i=0; i<this.dirtyIDX.length; i++)
	{
		var thisName = this.dirtyIDX[i];
		this.dirtyList[thisName] = false;
	}
	if (this.onChange) { this.onChange(false); }
	this.isDirtyAny = false;
}
dirtyElement.prototype.dirty = function(theName) 
{
	if ( (!this.isDirty(theName)) && (this.onChange)) { this.onChange(true, theName); }
	this.dirtyList[theName] = true;
	this.isDirtyAny = true; 
}
dirtyElement.prototype.isDirty = function(theName) 
{ 
	return this.dirtyList[theName]; 
}
dirtyElement.prototype.proceed = function(theName, theMsg)
{
	if (this.isDirty(theName)) { return confirm(theMsg); }
	else return true;
}
dirtyElement.prototype.proceedAny = function(theMsg)
{
	if (this.isDirtyAny) 
	{ 
		ok2Go = confirm(theMsg);
		if (ok2Go) { this.clearDirtyAll(); }
		return ok2Go; 
	} else return true;
}
dirtyElement.prototype.watch = function(theName) { 
	this.dirtyList[theName] = false; 
	var ptr = this.dirtyIDX.length;
	this.dirtyIDX[ptr] = theName;	
}



// ----------------------------------------------------------- //
//                       localStorage                          //
// ----------------------------------------------------------- //
function localStorage() { this.clear(); }
localStorage.prototype.clear = function()
{
	this.fileName = new String();
}
localStorage.prototype._getRaw = function()
{
	var rawBuff = document.cookie;
	var cookieRegExp = new RegExp("\\b" + this.fileName + "=([^;]*)");
	theValue = cookieRegExp.exec(rawBuff);
	if (theValue != null) { theValue = theValue[1]; }
	return theValue;
}
localStorage.prototype.dropFile = function()
{
	if (this.fileName)
	{
		var expiredDate = new Date();
		expiredDate.SetMonth(-1);
		var writeBuff = this.fileName + "=";
		writeBuff += "expires=" + expiredDate.toGMTString();
		document.cookie = writeBuff;
	}
}
localStorage.prototype.dropItem = function(theName)
{
	var rawBuff = readUnEscapedCookie(this.fileName);
	if (rawBuff)
	{
		var stripAttributeRegExp = new RegExp("(^|/&)" + theName + "=[^&]*&?");
		rawBuff = rawBuff.replace(stripAttributeRegExp, "$1");
		if (rawBuff.length != 0)
		{
			var newBuff = this.fileName + "=" + rawBuff;
			document.cookie = newBuff
		} else { this.dropFile(); }
	}
}
localStorage.prototype.enabled = function()
{
	var cookiesEnabled = window.navigator.cookieEnabled;
	if (!cookiesEnabled)
	{
		document.cookie = "cookiesEnabled=True";
		cookiesEnabled = new Boolean(document.cookie).valueOf();
	}
	return cookiesEnabled;
}
localStorage.prototype.retrieveItem = function(theName)
{
	var rawBuff = this._getRaw(this.fileName);
	var extractMultiValueCookieRegExp = new RegExp("\\b" + theName + "=([^;&]*)");
	resValue = extractMultiValueCookieRegExp.exec(rawBuff);
	if (resValue != null) { resValue = unescape(resValue[1]); }
	return resValue;
}
localStorage.prototype.storeItem = function(theName, theValue)
{
	var rawBuff = this._getRaw(this.fileName);
	if (rawBuff)
	{
		var stripAttributeRegExp = new RegExp("(^|&)" + theName + "=[^&]*&?");
		rawBuff = rawBuff.replace(stripAttributeRegExp, "$1");
		if (rawBuff.length != 0) { rawBuff += "&"; }
	} else rawBuff = "";
	
	rawBuff += theName + "=" + escape(theValue);
	document.cookie = this.fileName + "=" + rawBuff;
}



// ----------------------------------------------------------- //
//                          xmlNode                            //
// ----------------------------------------------------------- //
function xmlNode(theHandler) 
{ 
	this.tag = new String("unassigned");
	this.data = new String();
	this.updateData = new String();
	this.children = new Array();
	this.attributeKeys = new Array();
	this.attributeValues = new Array();
	this.parent = new Number();
	this.mID = new Number();
	this.handler = theHandler;
}
xmlNode.prototype.addChildPtr = function(thePtr)
{
	var newPtr = this.children.length;
	this.children[newPtr] = thePtr;
}
xmlNode.prototype.attribStr = function()
{
	var out = '';
	for (var i=0; i<this.attributeKeys.length; i++)
	{
		if (this.attributeValues[i])
		{
			out += ' ' + this.attributeKeys[i] + '="' + this.attributeValues[i] + '"';
		}
	}
	return out;
}
xmlNode.prototype.attributeValue = function(attrName)
{
	attrName = attrName.toLowerCase();
	for (var i=0; i<this.attributeKeys.length; i++)
	{
		if (attrName == this.attributeKeys[i])
		{
			return this.attributeValues[i];
		}
	}
	return "";
}
xmlNode.prototype.buildXML = function(outArr, indent)
{
	var ptr = outArr.length;
	var myIndent = '';
	if (!this.handler.forAjaxMS) { myIndent = this.handler.indentTemplate.substr(0, indent * 4); }
	var myTag = myIndent + '<' + this.tag;
	var myAttribs = this.attribStr();
	if (myAttribs) { myTag += ' ' + myAttribs; }
	if ( (this.data.length==0) && (!this.hasChildren()) )
	{
		outArr[ptr] = myTag + '/>';
		return;
	}
	
	// If no children, then I either have data or am empty...
	if (!this.hasChildren()) 
	{
		var myData = this.data;
		myData = myData.replace(/\</g, '[$felt]');
		myData = myData.replace(/\>/g, '[$fegt]');
		outArr[ptr] = myTag + '>' + myData + '</' + this.tag + '>';
		return;
	}
	
	// OK: I have child nodes...
	outArr[ptr] = myTag + '>';
	for (var i=0; i<this.children.length; i++)
	{
		var thisNode = this.handler.__xmlNodeArray[this.children[i]];
		thisNode.buildXML(outArr, indent+1);
	}
	var ptr = outArr.length;
	outArr[ptr] = myIndent + '</' + this.tag + '>';	
}
xmlNode.prototype.childData = function(childIDX)
{
	var tempNode = this.childNode(childIDX);
	return tempNode.data;
}
xmlNode.prototype.childDataNamed = function(tagName)
{
	tagName = tagName.toLowerCase();
	for (var i=0; i<this.children.length; i++)
	{
		var tempNode = this.childNode(i);
		if (tempNode.tag == tagName) { return tempNode.data; }
	}
	return '';
}
xmlNode.prototype.childNode = function(childIDX)
{
	var childPtr = this.children[childIDX];
	return this.handler.__xmlNodeArray[childPtr];
}
xmlNode.prototype.dump = function()
{
	var out = '[' + this.mID + '] ';
	out += 'tag=' + this.tag + ', ';
	out += 'data length is ' + this.data.length + ', ';
	var childCount = this.children.length;
	out += 'children[' + childCount + '](';
	for (var j=0; j<childCount; j++) { out += this.children[j] + ','; }
	out += '), ';
	out += 'parent=' + this.parent + ', ';
	out += 'data=' + this.data;
	return out;
}
xmlNode.prototype.hasChildren = function() { return (this.children.length > 0); }
xmlNode.prototype.importNode = function() 
{
	// Find the end of <this> tag and ditch all of it from the input string...
	endOfTag = this.handler.work.indexOf('>', this.handler.searchPtr);
	workStr = this.handler.work.substring(this.handler.searchPtr + 1, endOfTag); // doesnt grab the '>'
	this.handler.searchPtr = endOfTag + 1;

	// now look for the first space in the tag - it denotes the end of the tag name...
	emptyNode = false;
	if (workStr.indexOf('/') >= 0)
	{
		emptyNode = true;
		workStr = workStr.substr(0, workStr.length - 1);
	}
	space = workStr.indexOf(' ');
	if (space == -1) { space = 65535; } // arbitrary large number
	ptr = workStr.length;
	if (space < ptr) { ptr = space };

	this.tag = workStr.substring(0, ptr);
	this.tag = this.tag.toLowerCase();
	workStr = workStr.substring(ptr, 65535); // artibrarily large number...

	// Now time for the attributes...
    workStr = workStr.replace(/=[\s]*"[\s]*/g, '=\"') + ' '; // Kill all whitespace between = and "
	arr1 = workStr.split(/" /g); // now split on the remaining "(space)
	this.attributeKeys = new Array();
	this.attributeValues = new Array();
	for (i=0; i<arr1.length; i++) 
	{
		if (arr1[i] <= ' ') { continue; }
		arr2 = arr1[i].split(/=\"/g);
		var thisKey = arr2[0];
		var thisValue = arr2[1];
		this.attributeKeys[i] = thisKey.replace(/^\s+|\s+$/, '');
		this.attributeValues[i] = thisValue.replace(/^\s+|\s+$/, '');
	}
	
	// If <I> am an empty tag, then exit now...
	if (emptyNode) { return ""; }

	// If the next character in the work buffer is anything other than a '<' then there
	// is text for me to collect, and the tag must, by XML rules, be all done...
	thisChar = this.handler.work.charAt(this.handler.searchPtr);
	if (thisChar != '<') 
	{
		textEnd = this.handler.work.indexOf('<', this.handler.searchPtr);
		var tempStr = this.handler.work.substring(this.handler.searchPtr, textEnd);
		tempStr = tempStr.replace(/\[\$fegt\]/g, '>');
		tempStr = tempStr.replace(/\[\$felt\]/g, '<');
		this.data = tempStr;
		this.handler.__killNextTag();
		return "";
	}


	// OK: If I am here, then either there are children OR the very next tag is <me> closing
	// and I was empty after all. 
	while ((!this.handler.__nextIsClose()) && (this.handler.work.length > 0)) 
	{
		myPtr = this.children.length;
		ptr = this.handler.__newXMLNode(this.handler);
		this.children[myPtr] = ptr;
		tempObj = this.handler.__xmlNodeArray[ptr];
		tempObj.parent = this.mID;
		tempObj.importNode();
	}


	// I am at <me> closing. Eat me off the master string end exit...
	this.handler.__killNextTag();
}
xmlNode.prototype.updateAttribute = function(key, value)
{
	var key = key.toLowerCase();
	for (var i=0; i<this.attributeKeys.length; i++)
	{
		if (this.attributeKeys[i] == key)
		{
			this.attributeValues[i] = value;
			return true;
		}
	}
	var ptr = this.attributeKeys.length;
	this.attributeKeys[ptr] = key;
	this.attributeValues[ptr] = value;
	return true;
}
xmlNode.prototype.updateChildPtr = function(idx, newPtr)
{
	this.children[idx] = newPtr;
}



// ----------------------------------------------------------- //
//                        xmlHandler                           //
// ----------------------------------------------------------- //
function xmlHandler() { this.clearAll(); }
xmlHandler.prototype.__bubbleSort = function(method, attrName)
{
	var max = this.currentChildCount();
	var tempNode = null;
	for (var i=0; i<max - 1; i++)
	{
		for (var j=(i+1); j<max; j++)
		{
			switch (method)
			{
				case 0 :
					baseVal = this.childTag(i);
					compVal = this.childTag(j);
					break;
				case 1 :
					baseVal = this.childData(i);
					compVal = this.childData(j);
					break;
				case 2 :
					tempNode = this.childNode(i); 
					baseVal = tempNode.attributeValue(attrName);
					tempNode = this.childNode(j); 
					compVal = tempNode.attributeValue(attrName);
					break;
				case 3 :
					baseVal = this.onSortByOther(this, this.childNode(i));
					compVal = this.onSortByOther(this, this.childNode(j));
			}
			baseVal = baseVal.toLowerCase();
			compVal = compVal.toLowerCase();
			if (compVal < baseVal)
			{
				var basePtr = this.childPtr(i);
				var compPtr = this.childPtr(j);
				tempNode = this.__xmlNodeArray[this.currentPtr];
				tempNode.updateChildPtr(i, compPtr);
				tempNode.updateChildPtr(j, basePtr);
			}
		}
	}
	return true;
}
xmlHandler.prototype.__killNextTag = function()
{
	if (this.work.length > 0) 
	{
        this.searchPtr = this.work.indexOf('>', this.searchPtr) + 1;
	}
}
xmlHandler.prototype.__newXMLNode = function(theHandler)
{
	ptr = this.__xmlNodeArray.length;
    this.__xmlNodeArray[ptr] = new xmlNode(this);
    this.__xmlNodeArray[ptr].handler = this;
    this.__xmlNodeArray[ptr].mID = ptr;
	return ptr;
}
xmlHandler.prototype.__nextIsClose = function()
{
	// This function is called by nodes that want to know if the next 
	// item in the tag list is actually <themseleves> closing...
	result = (this.work.substr(this.searchPtr, 2) == '</');
	return result; 
}
xmlHandler.prototype.__xmlNodeArrayDump = function()
{
    var childCount = this.__xmlNodeArray.length;
    var out = '';
    for (var i=0; i<childCount; i++) 
    {
    	if (this.__xmlNodeArray[i]) 
    	{ 
    		out += this.__xmlNodeArray[i].dump() + '<br>\n'; 
    	}
    }
    return out;
}
xmlHandler.prototype.addChild = function(theTag, theValue, stepIn)
{
	var newPtr = this.__newXMLNode(this);
	var newNode = this.__xmlNodeArray[newPtr]; 
	newNode.tag = theTag;
	newNode.data = theValue;
	newNode.parent = this.currentPtr;
	var parentNode = this.__xmlNodeArray[this.currentPtr];
	parentNode.addChildPtr(newPtr);
	if (stepIn) { this.currentPtr = newPtr; }
	return this.currentNode();
}
xmlHandler.prototype.attributeValue = function(attrName)
{
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	return tempNode.attributeValue(attrName);
}
xmlHandler.prototype.bindRadioToTag = function(theElem, theTag)
{
	theTag = theTag.toLowerCase();
	this.bindings[theTag] = theElem;
	this.bindingType[theTag] = 'radio';
}
xmlHandler.prototype.bindTextToTag = function(theElem, theTag)
{
	theTag = theTag.toLowerCase();
	this.bindings[theTag] = theElem;
	this.bindingType[theTag] = 'text';
}
xmlHandler.prototype.boundUpdate = function(theElem, groupName)
{
	var theID = theElem.getAttribute('id');
	var theNode = this.reverseBindings[theID];
	if (theNode) { theNode.updateData = theElem.value; } 
	if (this.masterDirty) { this.masterDirty.dirty(groupName); }
	return true;
}
xmlHandler.prototype.childData = function(idx)
{
	var result = '';
	var tempNode = this.childNode(idx);
	if (tempNode) { return tempNode.data };
}
xmlHandler.prototype.childDataNamed = function(tagName)
{
	var result = '';
	var tempNode = this.childNodeNamed(tagName);
	if (tempNode) { return tempNode.data };
}
xmlHandler.prototype.childNode = function(nodeIDX)
{
        var retNode = null;
        if (!isNaN(nodeIDX))
        {
                var tempNode = this.__xmlNodeArray[this.currentPtr];
                var ptr = tempNode.children[nodeIDX];
		if ((nodeIDX >= 0) && (nodeIDX < tempNode.children.length)) { retNode = this.__xmlNodeArray[ptr]; }
        }
        return retNode;
}
xmlHandler.prototype.childNodeNamed = function(nodeIDX)
{
	var retNode = null;
	if (isNaN(nodeIDX))
	{
		var holdPtr = this.currentPtr;
		if (this.stepInto(nodeIDX)) {
			var ptr = this.currentPtr;
			retNode = this.__xmlNodeArray[ptr];
			// Put me back where I was...
			this.currentPtr = holdPtr;
		}
		// if not, then I am where I started anyway...
	}
	return retNode;
}
xmlHandler.prototype.childPtr = function(nodeIDX) 
{
	var tempNode = this.__xmlNodeArray[this.currentPtr];
    return tempNode.children[nodeIDX];
}
xmlHandler.prototype.childTag = function(idx)
{
	var result = '';
	var tempNode = this.childNode(idx);
	if (tempNode) { return tempNode.tag };
}
xmlHandler.prototype.clear = function() 
{
        this.__xmlNodeArray = new Array();
        this.work = new String(); // This will be used by all nodes during the import
        ptr = this.__newXMLNode(this);
        this.rootPtr = ptr;
        this.currentPtr = ptr;
        tempObj = this.__xmlNodeArray[ptr];
        tempObj.parent = ptr; // SPECIAL CASE - root is it's own parent
        this.originalXML = new String();
        this.forAjaxMS = false;
}
xmlHandler.prototype.clearAll = function()
{
	this.bindings = new Array();
	this.bindingType = new Array();
	this.reverseBindings = new Array();
	this.masterDirty = null;
	this.indentTemplate = "                                                                      ";
	this.onSortbyOther = null;
	this.clear();
}
xmlHandler.prototype.clearBound = function(optionalPath)
{
	if (optionalPath) {
		this.moveToRoot();
		this.stepDeep(optionalPath);
	}
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	var max = tempNode.children.length;
	for (var i=0; i<max; i++) 
	{
		var thisTag = tempNode.childTag(i);
		thisElem = this.bindings[thisTag];
		if (this.bindingType[thisTag] == 'radio') {thisElem[0].checked = true; }
		else if (this.bindingType[thisTag] == 'check') { } // What do we do here?
		else {thisElem.value = ''; }
	}
}
xmlHandler.prototype.currentChildCount = function() { return this.__xmlNodeArray[this.currentPtr].children.length; }
xmlHandler.prototype.currentData = function() { return this.__xmlNodeArray[this.currentPtr].data; }
xmlHandler.prototype.currentNode = function() { return this.__xmlNodeArray[this.currentPtr]; }
xmlHandler.prototype.currentNodeID = function() { return this.currentPtr; }
xmlHandler.prototype.currentTag = function() { return this.__xmlNodeArray[this.currentPtr].tag; }
xmlHandler.prototype.deleteCurrentChildren = function() 
{ 
	while (this.currentChildCount()) 
	{ 
		this.deleteChildNode(0); 
	} 
}
xmlHandler.prototype.deleteChildNode = function(childPtr)
{
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	var childArrPtr = tempNode.children[childPtr];
	tempNode.children.splice(childPtr, 1);
	this.__xmlNodeArray[childArrPtr] = null; // I won't get the pointer back, but the memory will be freed...
}
xmlHandler.prototype.evaluateBindings = function(optionalPath)
{
	if (optionalPath) {
		this.moveToRoot();
		this.stepDeep(optionalPath);
	}
	// Look at the tags for all the current children. 
	// if the tag exists in the hash list this.bindings, then
	// the element associated with that item is updated.
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	var max = tempNode.children.length;
	for (var i=0; i<max; i++) 
	{
		var ptr = tempNode.children[i];
		var thisNode = this.__xmlNodeArray[ptr];
		thisNode.updateData = thisNode.data;
		var thisTag = thisNode.tag;
		if (this.bindings[thisTag])
		{
			thisElem = this.bindings[thisTag];
			if (this.bindingType[thisTag] == 'radio')
			{
				atLeastOne = false;
				for (var i=0; i<thisElem.length; i++)
				{
					this.reverseBindings[thisElem[i].getAttribute('id')] = thisNode;
					if ( (thisElem[i]) && (thisElem[i].value === thisNode.data) )
					{
						atLeastOne = true;
						thisElem[i].checked = true;
					} else { thisElem[i].checked = false; }
				}
				if (!atLeastOne)
				{
					thisElem[0].checked = true;
				}
			} else if (this.bindingType[thisTag] == 'check')
			{
			} else { 
				thisElem.value = thisNode.data;
				this.reverseBindings[thisElem.getAttribute('id')] = thisNode;
			}
		}
	}
}
xmlHandler.prototype.firstNode = function()
{
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	var parentNode = this.__xmlNodeArray[tempNode.parent];
	this.currentPtr = parentNode.children[0];
}
xmlHandler.prototype.importXML = function(inputXML)
{
	this.clear();
	this.searchPtr = 0;
	this.originalXML = inputXML;
	this.work = inputXML;

	// Clean the XML first...
	if (this.work.indexOf('ajaxms="1"') == -1)
	{
	    this.work = this.work.replace(/>[\s]*</g, "><"); // Kill all whitespace between tags
	    this.work = this.work.replace(/<\?.*\?>/g, ""); // Kill all comments
	    this.work = this.work.replace(/<[\s]*/g, "<"); // Kill all whitespace between LT and next character
	}

	tempObj = this.__xmlNodeArray[0];
	tempObj.importNode();
}
xmlHandler.prototype.isFirstNode = function()
{
	// Evalute whether the current node is the <zeroth> in its parent's child list
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	tempNode.flagged = true;
	theParent = tempNode.parent;
	parentNode = this.__xmlNodeArray[theParent];
	for (var i=0; i<parentNode.children.length; i++)
	{
		var childNode = this.__xmlNodeArray[parentNode.children[i]];
		if (childNode.flagged) 
		{
			// Found it!
			childNode.flagged = false;
			return (i == 0);
		}
	}
	// I should never be here...
	tempNode.flagged = false;
	return false;
}
xmlHandler.prototype.isLastNode = function()
{
        // Evalute whether the current node is the <zeroth> in its parent's child list
        var tempNode = this.__xmlNodeArray[this.currentPtr];
        tempNode.flagged = true;
        theParent = tempNode.parent;
        parentNode = this.__xmlNodeArray[theParent];
        for (var i=0; i<parentNode.children.length; i++)
        {
                var childNode = this.__xmlNodeArray[parentNode.children[i]];
                if (childNode.flagged)
                {
                        // Found it!
                        childNode.flagged = false;
                        return (i == parentNode.children.length - 1);
                }
        }
        // I should never be here...
        tempNode.flagged = false;
        return false;
}
xmlHandler.prototype.lastNode = function()
{
        var tempNode = this.__xmlNodeArray[this.currentPtr];
        var parentNode = this.__xmlNodeArray[tempNode.parent];
        this.currentPtr = parentNode.children[parentNode.children.length - 1];
}
xmlHandler.prototype.makeUpdatesPermanent = function()
{
	var thisNode = this.__xmlNodeArray[this.currentPtr];
	for (var i=0; i<thisNode.children.length; i++)
	{
		var childNode = this.childNode(i);
		childNode.data = childNode.updateData;
	}
}
xmlHandler.prototype.moveToRoot = function() { this.currentPtr = this.rootPtr; }
xmlHandler.prototype.nextNode = function()
{
        // Evalute whether the current node is the <zeroth> in its parent's child list
        var tempNode = this.__xmlNodeArray[this.currentPtr];
        tempNode.flagged = true;
        theParent = tempNode.parent;
        parentNode = this.__xmlNodeArray[theParent];
        for (var i=0; i<parentNode.children.length; i++)
        {
		var ptr = parentNode.children[i];
                var childNode = this.__xmlNodeArray[ptr];
                if (childNode.flagged)
                {
                        // Found it!
                        childNode.flagged = false;
			if (i < parentNode.children.length - 1)
			{
				this.currentPtr = parentNode.children[i + 1];
				return "";
			}
                }
        }
        // I should never be here...
        tempNode.flagged = false;
        return false;
}
xmlHandler.prototype.outputAllXML = function(makePretty)
{
	// This will, be default, compress the XML on the way out - if the user
	// wants "pretty" xml then TRUE must be passed in here...
	this.forAjaxMS = !makePretty;
	var holdPtr = this.currentPtr;
	this.moveToRoot();
	return this.outputCurrentXML(makePretty);
	this.currentPtr = holdPtr;
}
xmlHandler.prototype.outputCurrentXML = function(makePretty)
{
	// This will, be default, compress the XML on the way out - if the user
	// wants "pretty" xml then TRUE must be passed in here...
	this.forAjaxMS = !makePretty;
	var output = new Array();
	var theNode = this.__xmlNodeArray[this.currentPtr];
	if (this.forAjaxMS) { theNode.updateAttribute('ajaxms', '1'); }
//	theNode.updateAttribute('ajaxms', (this.forAjaxMS) ? '1' : '0');
	theNode.buildXML(output, 0);
	if (this.forAjaxMS) { return output.join(''); }
	else { return output.join('\n'); }
	output = null;
}
xmlHandler.prototype.prevNode = function()
{
        // Evalute whether the current node is the <zeroth> in its parent's child list
        var tempNode = this.__xmlNodeArray[this.currentPtr];
        tempNode.flagged = true;
        theParent = tempNode.parent;
        parentNode = this.__xmlNodeArray[theParent];
        for (var i=0; i<parentNode.children.length; i++)
        {
                var childNode = this.__xmlNodeArray[parentNode.children[i]];
                if (childNode.flagged)
                {
                        // Found it!
                        childNode.flagged = false;
                        if (i > 0)
                        {
				this.currentPtr = parentNode.children[i - 1];
                                return "";
                        }
                }
        }
        // I should never be here...
        tempNode.flagged = false;
        return false;
}
xmlHandler.prototype.returnToID = function(theID) { this.currentPtr = theID; }
xmlHandler.prototype.sortByTag = function() { this.__bubbleSort(0); }
xmlHandler.prototype.sortByData = function() { this.__bubbleSort(1); }
xmlHandler.prototype.sortByAttribute = function(attrName) { this.__bubbleSort(2, attrName); }
xmlHandler.prototype.sortByOther = function()
{
	if (!this.onSortByOther) { return false; }
	this.__bubbleSort(3);
}
xmlHandler.prototype.stepDeep = function(tagPath)
{
	var holdPtr = this.currentPtr;
	tagPath = tagPath.toLowerCase();
	var tempArr = tagPath.split('|');
	for (var i=0; i<tempArr.length; i++)
	{
		if (!this.stepInto(tempArr[i])) 
		{
			this.currentPtr = holdPtr;
			return false;
		}	
	}
	// If I am here then I succeeded!
	return true;
}
xmlHandler.prototype.stepInto = function(tagName)
{
	var tagName = tagName.toLowerCase();
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	for(var i=0; i<tempNode.children.length; i++) {
		var childID = tempNode.children[i];
		var thisNode = this.__xmlNodeArray[childID];
		if ((thisNode.tag === tagName) && (thisNode.tag.length == tagName.length)) {
			this.currentPtr = childID;
			return true;
		}
	}
	return false;
}
xmlHandler.prototype.stepIntoIDX = function(idx)
{
        var tempNode = this.__xmlNodeArray[this.currentPtr];
        if ((idx >= 0) && (idx < tempNode.children.length)) { this.currentPtr = tempNode.children[idx]; }
}
xmlHandler.prototype.stepOut = function() { this.currentPtr = this.__xmlNodeArray[this.currentPtr].parent; }
xmlHandler.prototype.updateAttribute = function(theName, theValue)
{
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	tempNode.updateAttribute(theName, theValue);
}
xmlHandler.prototype.updateData = function(theData)
{
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	tempNode.data = theData;
}
xmlHandler.prototype.updateTag = function(theName)
{
	var tempNode = this.__xmlNodeArray[this.currentPtr];
	tempNode.tag = theName;
}


// ----------------------------------------------------------- //
//                       Table Manager                         //
// ----------------------------------------------------------- //
// This object is used to manage the creation of tables - not that
// you'd really need it if it wasn't for IE's quirkiness...
function tableManager(cellPadding, cellSpacing, border, width) 
{ 
	this.clear();
	if (cellPadding) { this.cellPadding = cellPadding; }
	if (cellSpacing) { this.cellSpacing = cellSpacing; }
	if (border) { this.border = border; }
	if (width) { this.width = width; }
}
tableManager.prototype.clear = function()
{
	this.cellPadding = 0;
	this.cellSpacing = 0;
	this.border = 0;
	this.width = '100%';
	this.sizingGraphicURL = '/graphics/dot_clear.gif';
	
	this.currentRow = null;
	this.currentCell = null;
	
	this.isIE = ((document.all) && (document.getElementById));
	if (this.isIE) {
		this.mainNode = document.createElement('TBODY');
	} else {
		this.mainNode = document.createElement('TABLE');
	}
}
tableManager.prototype.addTableTo = function(newOwner)
{
	if (this.isIE)
	{
		var tableNode = document.createElement('TABLE');
		this.attribute(tableNode, 'cellpadding', this.cellPadding, 'cellspacing', this.cellSpacing, 'border', this.border, 'width', this.width);
		tableNode.appendChild(this.mainNode);
		newOwner.appendChild(tableNode);
		return tableNode;
	} else {
		this.attribute(this.mainNode, 'cellpadding', this.cellPadding, 'cellspacing', this.cellSpacing, 'border', this.border, 'width', this.width);
		newOwner.appendChild(this.mainNode);
		return this.mainNode;
	}
}
tableManager.prototype.attribute = function(theNode)
{
	for(var i=1; i<arguments.length; i+=2) 
	{ 
		if (this.isIE) { 
			// NN2 attribute the object the old way...
			switch(arguments[i].toLowerCase())
			{
				case 'align' : theNode.align = arguments[i+1]; break;
				case 'bgcolor' : theNode.bgColor = arguments[i+1]; break;
				case 'border' : theNode.border = arguments[i+1]; break;
				case 'cellpadding' : theNode.cellPadding = arguments[i+1]; break;
				case 'cellspacing' : theNode.cellSpacing = arguments[i+1]; break;
				case 'class' : theNode.className = arguments[i+1]; break;
				case 'colspan' : theNode.colSpan = arguments[i+1]; break;
				case 'enctype' : theNode['enctype'] = arguments[i+1]; break;
				case 'height' : theNode.height = arguments[i+1]; break;
				case 'href' : theNode.setAttribute('href', arguments[i+1]); break;
				case 'id' : theNode.id = arguments[i+1]; break;
				case 'method' : theNode['method'] = arguments[i+1]; break;
				case 'onclick' : theNode['onclick'] = new Function(arguments[i+1]); break;
				case 'onblur' : theNode['onblur'] = new Function(arguments[i+1]); break;
				case 'onchange' : theNode['onchange'] = new Function(arguments[i+1]); break;
				case 'onclick' : theNode['onclick'] = new Function(arguments[i+1]); break;
				case 'ondblclick' : theNode['ondblclick'] = new Function(arguments[i+1]); break;
				case 'onfocus' : theNode['onfocus'] = new Function(arguments[i+1]); break;
				case 'onkeypress' : theNode['onkeypress'] = new Function(arguments[i+1]); break;
				case 'onmouseover' : theNode['onmouseover'] = new Function(arguments[i+1]); break;
				case 'onmouseout' : theNode['onmouseout'] = new Function(arguments[i+1]); break;
				case 'nowrap' : theNode.noWrap = 'nowrap'; break;
				case 'size' : theNode.src = arguments[i+1]; break;
				case 'src' : theNode.src = arguments[i+1]; break;
				case 'type' : theNode.setAttribute('type', arguments[i+1]); break;
				case 'valign' : theNode.vAlign = arguments[i+1]; break;
				case 'value' : theNode.value = arguments[i+1]; break;
				case 'visibility' : theNode.visibility = arguments[i+1]; break;
				case 'width' : theNode.width = arguments[i+1]; break;
			}
		} else { theNode.setAttribute(arguments[i], arguments[i+1]); }
	}
	return theNode;
}
tableManager.prototype.newCell = function(rowNode)
{
	if (!rowNode) { rowNode = this.currentRow; }
	if (!rowNode) { rowNode = this.newRow(); }
	this.currentCell = document.createElement('TD');
	rowNode.appendChild(this.currentCell);
	return this.currentCell;
}
tableManager.prototype.newCellContent = function(cellContent, rowNode)
{
	if (!rowNode) { rowNode = this.currentRow; }
	this.newCell();
	this.currentCell.appendChild(cellContent);
	return this.currentCell;
}
tableManager.prototype.newFirstCell = function(content)
{
	this.newRow();
	this.newCell();
	if (content) { this.currentCell.appendChild(content); }
	return this.currentCell;
}
tableManager.prototype.newRow = function() 
{ 
	this.currentRow = document.createElement('TR');
	this.mainNode.appendChild(this.currentRow);
	return this.currentRow; 
}
tableManager.prototype.newTextCell = function(theText, theClass)
{
	return this.textCell(theText, theClass);
}
tableManager.prototype.sizingCell = function(height, width, colSpan) { return this._sizingCell(this.currentRow, height, width, colSpan); }
tableManager.prototype._sizingCell = function(theRow, height, width, colSpan)
{
	if (!theRow) { theRow = this.newRow(); }
	var thisContent = document.createElement('img');
	thisContent.src = this.sizingGraphicURL;
	this.attribute(thisContent, 'height', height, 'width', width);
	this.newCell(theRow).appendChild(thisContent);

	if (colSpan) { this.attribute(this.currentCell, 'colSpan', colSpan); }
	return this.currentCell;
}
tableManager.prototype.sizingRow = function(height, colSpan)
{
	this.newRow();
	this.sizingCell(height, 1, colSpan);
	return this.currentCell;
}
tableManager.prototype.textCell = function(theText, textClass)
{
	this.newCell();
	if (textClass) { this.attribute(this.currentCell, 'class', textClass); }
	this.currentCell.appendChild(document.createTextNode(theText));
	return this.currentCell;
}






// ----------------------------------------------------------- //
//                       Miscellaneous                         //
// ----------------------------------------------------------- //

String.prototype.trim = function()
{
 	return this.replace(/^\s+/g, '').replace(/\s+$/g, '');
}
function addEventStr(theObj, functionStr)
{
	if ((document.all) && (document.getElementById))
	{
   		theObj["onclick"] = new Function(functionStr);
	} else {
		theObj.setAttribute('onClick', functionStr); 
	}
}
function browserWindowHeight()
{
	if ((document.all) && (document.getElementById))
	{
		return document.body.offsetHeight;
	} else {
		return window.innerHeight;
	}
}
function browserWindowWidth()
{
	if ((document.all) && (document.getElementById))
	{
		return document.body.offsetWidth;
	} else {
		return window.innerWidth;
	}
}
function removeAllChildren(theNode)
{ 
	while (theNode.childNodes[0]) { theNode.removeChild(theNode.childNodes[0]); } 
}
function selectSelectValue(theSelect, theValue)
{
	// Very simply - select the option in the list that has a <value> matching what was passed...
	theValue = theValue.toLowerCase();
	var max = theSelect.options.length;
	for (var i=0; i<max; i++)
	{
		if (theValue == theSelect.options[i].value.toLowerCase())
		{
			theSelect.selectedIndex = i;
			return true;
		}
	}
	return false;
}
function highlightRow(theRow, theRowColor, theTextColor)
{
    if (typeof(document.getElementsByTagName) != 'undefined')
        { var theCells = theRow.getElementsByTagName('td'); }
    else if (typeof(theRow.cells) != 'undefined')
        { var theCells = theRow.cells; }
    else { return false; }

    var rowCellsCnt = theCells.length;
    for (var c=0; c<rowCellsCnt; c++)
    {
        theCells[c].style.backgroundColor=theRowColor;
        if (theTextColor) { theCells[c].style.color=theTextColor; }
        theCells[c].style.cursor='pointer';
    }
    return true;
}
function highlightCell(theCell, theColor, theTextColor)
{
    theCell.style.backgroundColor=theColor;
    if (theTextColor) { theCell.style.color=theTextColor; }
    theCell.style.cursor='pointer';
    return true;
}
