//=======================================
//###################################
// KAJAX - Kayako Ajax JS Lib
//
// Source Copyright 2001-2004 Kayako Web Solutions
// Unauthorized reproduction is not allowed
// License Number: $%LICENSE%$
// $Author: vshoor $ ($Date: 2006/11/14 20:58:58 $)
// $RCSfile: kajax.js,v $ : $Revision: 1.5 $ 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//                   www.kayako.com
//###################################
//=======================================


/**
* ###############################################
* CORE OBJECTS
* ###############################################
*/


/**
* =====================================================
* KAJAX Object
* ***********************************************************
* The parent object that handles all widgets and sub objects
* =====================================================
*/
function KAJAX()
{
	// ======= VARIABLE DECLARATIONS =======
	this.xmlhttp = xmlaction = "";

	// ======= OBJECT DELCARATIONS =======
	this._keyboardHandler = new KAJAX_keyboardHandler();
	this._browserDetect = new KAJAX_browserDetect();
	this._request = AjaxRequest;
	this._interface =new KAJAX_interface();
	this._parser = new KAJAX_parser();

	// Events
	this.eventOnClick = new Array();

	if (this._browserDetect.ie)
	{
		document.onmousedown = this.processMouseDown;
	} else {
		document.addEventListener("mousedown", this.processMouseDown, true);
	}

	window.onload = function () {
		window.$KAJAX._parser.parse();

		bodyElement = document.getElementsByTagName("body");
		bodyElement[0].style.display = 'block';
	}

}

KAJAX.prototype.processMouseDown = function (event) {
	for (var ii=0; ii<window.$KAJAX.eventOnClick.length; ii++)
	{
		var functionNode = window.$KAJAX.eventOnClick[ii];
		functionNode(event);
	}
}


/**
* =====================================================
* Keyboard Handler Object
* ***********************************************************
* This object is mainly used to create shortcut keys
* =====================================================
*/
function KAJAX_keyboardHandler()
{
	this.keyStore = new Array();

	if (window.Event)
	{
		document.captureEvents(Event.KEYDOWN);
	}

	document.onkeydown = function(e) { window.$KAJAX._keyboardHandler.keyHandler(e) };
}

/**
* Use this function to assign a function to be called when a key is pressed
*/
KAJAX_keyboardHandler.prototype.assignKey = function (keyCode, isCtrl, isShift, functionHandler) {
	if (!this.keyStore[keyCode])
	{
		this.keyStore[keyCode] = new Array();
	}

	var keyHashLength = this.keyStore[keyCode].length;
	this.keyStore[keyCode][keyHashLength] = new Array(isCtrl, isShift, functionHandler);
}

/**
* Key Handler - Invoked when any key is pressed
*/
KAJAX_keyboardHandler.prototype.keyHandler = function (e) {
	var isShift = isCtrl = false;

	var coreEvent = null;
	var eventSrc = null;

	if (window.Event)
	{
		if (e.altKey == true) {
			return false;
		} else if (e.shiftKey == true) {
			isShift = true;
		}

		if (e.ctrlKey == true) {
			isCtrl = true;
		}

		keyPress = e.which;

		try {
			if (e.srcElement) {
				eventSrc = e.srcElement;
			} else if (e.target) {
				eventSrc = e.target;
			}
		} catch (e) {
		
		}

		coreEvent = e;
	} else {
		if (window.event.altKey == true)
		{
			return true;
		} else if (window.event.shiftKey == true) {
			isShift = true;
		}

		if (window.event.ctrlKey == true) {
			isCtrl = true;
		}

		keyPress = window.event.keyCode;

		try {
			if (window.event.srcElement) {
				eventSrc = window.event.srcElement;
			} else if (window.event.target) {
				eventSrc = window.event.target;
			}
		} catch (e) {
		
		}

		coreEvent = window.event;
	}

	keyPressChar = String.fromCharCode(keyPress);

//	alert(keyPress);
	// Is there a handler for this key?
	if (!this.keyStore[keyPress])
	{
		return false;
	}


	for (var ii=0; ii<this.keyStore[keyPress].length; ii++)
	{
		var keyInvoker = this.keyStore[keyPress][ii];

		if (keyInvoker[0] == isCtrl && keyInvoker[1] == isShift)
		{
			// Is this supposed to be invoked with Shift? If yes, we itterate through all elements to make sure we are not in any input field. We also do it if the key isnt linked with Ctrl or Shift key
			if ((keyInvoker[1] == true && keyInvoker[0] == false) || (keyInvoker[0] == false && keyInvoker[1] == false))
			{
				for (var eHandler = eventSrc; eHandler != null; eHandler = eHandler.parentNode) {
					if (eHandler.nodeName == "TEXTAREA" || eHandler.nodeName == "SELECT" || eHandler.nodeName == "INPUT" || eHandler.nodeName == "BUTTON") {
						return false;
					}
				}

			// We disable this event if someone pressed Ctrl+Shift together, this helps in preventing the text from appearing in the input field (if user has one in focus i.e.)
			} else if (keyInvoker[1] == true && keyInvoker[0] == true) {
				coreEvent.returnValue = false;
			}

			// Invoke this
			var functionHandler = keyInvoker[2];
			functionHandler();
		}
	}
}


/**
* =====================================================
* Browser Object
* ***********************************************************
* Detects Browser & Client Properties
* =====================================================
*/
function KAJAX_browserDetect()
{
	this.screenHeight = window.screen.availHeight;
	this.screenWidth = window.screen.availWidth;
	this.colorDepth = window.screen.colorDepth;
	this.timeNow = new Date();
	this.referrer = escape(document.referrer);
	this.windows = this.mac = this.linux = "";
	this.ie = this.op = this.moz = this.misc = this.browsercode = this.browsername = this.browserversion = this.operatingsys = "";
	this.dom = this.ienew = this.ie4 = this.ie5 = this.ie6 = this.moz_rv = this.moz_rv_sub = this.ie5mac = this.ie5xwin = this.opnu = this.op4 = this.op5 = this.op6 = this.op7 = this.saf = this.konq = "";
	this.appName = this.appVersion = this.userAgent = "";
	this.appName = navigator.appName;
	this.appVersion = navigator.appVersion;
	this.userAgent = navigator.userAgent.toLowerCase();
	this.title = document.title;
	this.DOMBROWSER = "default";

	this.windows = (this.appVersion.indexOf('Win') != -1);
	this.mac = (this.appVersion.indexOf('Mac') != -1);
	this.linux = (this.appVersion.indexOf('Linux') != -1);

	// DOM Compatible?
	if (!document.layers)
	{
		this.dom = (document.getElementById ) ? document.getElementById : false;
	} else {
		this.dom = false;
	}

	if (document.getElementById)
	{
		this.DOMBROWSER = "default";
	} else if (document.layers) {
		this.DOMBROWSER = "NS4";
	} else if (document.all) {
		this.DOMBROWSER = "IE4";
	}

	this.misc=(this.appVersion.substring(0,1) < 4);
	this.op=(this.userAgent.indexOf('opera') != -1);
	this.moz=(this.userAgent.indexOf('gecko') != -1);
	this.ie=(document.all && !this.op);
	this.saf=((this.userAgent.indexOf('safari') != -1) || (navigator.vendor == "Apple Computer, Inc."));
	this.konq=(this.userAgent.indexOf('konqueror') != -1);

	// Opera
	if (this.op) {
		this.op_pos = this.userAgent.indexOf('opera');
		this.opnu = this.userAgent.substr((this.op_pos+6),4);
		this.op5 = (this.opnu.substring(0,1) == 5);
		this.op6 = (this.opnu.substring(0,1) == 6);
		this.op7 = (this.opnu.substring(0,1) == 7);

	// Mozilla
	} else if (this.moz){
		this.rv_pos = this.userAgent.indexOf('rv');
		this.moz_rv = this.userAgent.substr((this.rv_pos+3),3);
		this.moz_rv_sub = this.userAgent.substr((this.rv_pos+7),1);
		if (this.moz_rv_sub == ' ' || isNaN(this.moz_rv_sub)) {
			this.moz_rv_sub='';
		}
		this.moz_rv = this.moz_rv + this.moz_rv_sub;

	// IE
	} else if (this.ie){
		this.ie_pos = this.userAgent.indexOf('msie');
		this.ienu = this.userAgent.substr((this.ie_pos+5),3);
		this.ie4 = (!this.dom);
		this.ie5 = (this.ienu.substring(0,1) == 5);
		this.ie6 = (this.ienu.substring(0,1) == 6);
	}

	if (this.konq) {
		this.browsercode = "KO";
		this.browserversion = this.appVersion;
		this.browsername = "Knoqueror";
	} else if (this.saf) {
		this.browsercode = "SF";
		this.browserversion = this.appVersion;
		this.browsername = "Safari";
	} else if (this.op) {
		this.browsercode = "OP";
		if (this.op5) {
			this.browserversion = "5";
		} else if (this.op6) {
			this.browserversion = "6";
		} else if (this.op7) {
			this.browserversion = "7";
		} else {
			this.browserversion = this.appVersion;
		}
		this.browsername = "Opera";
	} else if (this.moz) {
		this.browsercode = "MO";
		this.browserversion = this.appVersion;
		this.browsername = "Mozilla";
	} else if (this.ie) {
		this.browsercode = "IE";
		if (this.ie4) {
			this.browserversion = "4";
		} else if (this.ie5) {
			this.browserversion = "5";
		} else if (this.ie6) {
			this.browserversion = "6";
		} else {
			this.browserversion = this.appVersion;
		}
		this.browsername = "Internet Explorer";
	}

	if (this.windows) {
		this.operatingsys = "Windows";
	} else if (this.linux) {
		this.operatingsys = "Linux";
	} else if (this.mac) {
		this.operatingsys = "Mac";
	} else {
		this.operatingsys = "Unkown";
	}

	if (this.ie)
	{
		this.innerWidth = this.screenWidth;
		this.innerHeight = this.screenHeight;
	} else {
		this.innerWidth = window.innerWidth;
		this.innerHeight = window.innerHeight;
	}
}


/**
* =====================================================
* Request Object
* ***********************************************************
* The Main Ajax Handler
* =====================================================
*/

// ===================================================================
// Author: Matt Kruse
// ===================================================================

/**
 * The AjaxRequest class is a wrapper for the XMLHttpRequest objects which 
 * are available in most modern browsers. It simplifies the interfaces for
 * making Ajax requests, adds commonly-used convenience methods, and makes 
 * the process of handling state changes more intuitive.
 * An object may be instantiated and used, or the Class methods may be used 
 * which internally create an AjaxRequest object.
 */
function AjaxRequest() {
	var req = new Object();
	
	// -------------------
	// Instance properties
	// -------------------

	/**
	 * Timeout period (in ms) until an async request will be aborted, and
	 * the onTimeout function will be called
	 */
	req.timeout = null;
	
	/**
	 *	Since some browsers cache GET requests via XMLHttpRequest, an
	 * additional parameter called AjaxRequestUniqueId will be added to
	 * the request URI with a unique numeric value appended so that the requested
	 * URL will not be cached.
	 */
	req.generateUniqueUrl = true;
	
	/**
	 * The url that the request will be made to, which defaults to the current 
	 * url of the window
	 */
	req.url = window.location.href;
	
	/**
	 * The method of the request, either GET (default), POST, or HEAD
	 */
	req.method = "GET";
	
	/**
	 * Whether or not the request will be asynchronous. In general, synchronous 
	 * requests should not be used so this should rarely be changed from true
	 */
	req.async = true;
	
	/**
	 * The username used to access the URL
	 */
	req.username = null;
	
	/**
	 * The password used to access the URL
	 */
	req.password = null;
	
	/**
	 * The parameters is an object holding name/value pairs which will be 
	 * added to the url for a GET request or the request content for a POST request
	 */
	req.parameters = new Object();
	
	/**
	 * The sequential index number of this request, updated internally
	 */
	req.requestIndex = AjaxRequest.numAjaxRequests++;
	
	/**
	 * Indicates whether a response has been received yet from the server
	 */
	req.responseReceived = false;
	
	/**
	 * The name of the group that this request belongs to, for activity 
	 * monitoring purposes
	 */
	req.groupName = null;
	
	/**
	 * The query string to be added to the end of a GET request, in proper 
	 * URIEncoded format
	 */
	req.queryString = "";
	
	/**
	 * After a response has been received, this will hold the text contents of 
	 * the response - even in case of error
	 */
	req.responseText = null;
	
	/**
	 * After a response has been received, this will hold the XML content
	 */
	req.responseXML = null;
	
	/**
	 * After a response has been received, this will hold the status code of 
	 * the response as returned by the server.
	 */
	req.status = null;
	
	/**
	 * After a response has been received, this will hold the text description 
	 * of the response code
	 */
	req.statusText = null;

	/**
	 * An internal flag to indicate whether the request has been aborted
	 */
	req.aborted = false;
	
	/**
	 * The XMLHttpRequest object used internally
	 */
	req.xmlHttpRequest = null;

	// --------------
	// Event handlers
	// --------------
	
	/**
	 * If a timeout period is set, and it is reached before a response is 
	 * received, a function reference assigned to onTimeout will be called
	 */
	req.onTimeout = null; 
	
	/**
	 * A function reference assigned will be called when readyState=1
	 */
	req.onLoading = null;

	/**
	 * A function reference assigned will be called when readyState=2
	 */
	req.onLoaded = null;

	/**
	 * A function reference assigned will be called when readyState=3
	 */
	req.onInteractive = null;

	/**
	 * A function reference assigned will be called when readyState=4
	 */
	req.onComplete = null;

	/**
	 * A function reference assigned will be called after onComplete, if 
	 * the statusCode=200
	 */
	req.onSuccess = null;

	/**
	 * A function reference assigned will be called after onComplete, if 
	 * the statusCode != 200
	 */
	req.onError = null;
	
	/**
	 * If this request has a group name, this function reference will be called 
	 * and passed the group name if this is the first request in the group to 
	 * become active
	 */
	req.onGroupBegin = null;

	/**
	 * If this request has a group name, and this request is the last request 
	 * in the group to complete, this function reference will be called
	 */
	req.onGroupEnd = null;

	// Get the XMLHttpRequest object itself
	req.xmlHttpRequest = AjaxRequest.getXmlHttpRequest();
	if (req.xmlHttpRequest==null) { return null; }
	
	// -------------------------------------------------------
	// Attach the event handlers for the XMLHttpRequest object
	// -------------------------------------------------------
	req.xmlHttpRequest.onreadystatechange = 
	function() {
		if (req==null || req.xmlHttpRequest==null) { return; }
		if (req.xmlHttpRequest.readyState==1) { req.onLoadingInternal(req); }
		if (req.xmlHttpRequest.readyState==2) { req.onLoadedInternal(req); }
		if (req.xmlHttpRequest.readyState==3) { req.onInteractiveInternal(req); }
		if (req.xmlHttpRequest.readyState==4) { req.onCompleteInternal(req); }
	};
	
	// ---------------------------------------------------------------------------
	// Internal event handlers that fire, and in turn fire the user event handlers
	// ---------------------------------------------------------------------------
	// Flags to keep track if each event has been handled, in case of 
	// multiple calls (some browsers may call the onreadystatechange 
	// multiple times for the same state)
	req.onLoadingInternalHandled = false;
	req.onLoadedInternalHandled = false;
	req.onInteractiveInternalHandled = false;
	req.onCompleteInternalHandled = false;
	req.onLoadingInternal = 
		function() {
			if (req.onLoadingInternalHandled) { return; }
			AjaxRequest.numActiveAjaxRequests++;
			if (AjaxRequest.numActiveAjaxRequests==1 && typeof(window['AjaxRequestBegin'])=="function") {
				AjaxRequestBegin();
			}
			if (req.groupName!=null) {
				if (typeof(AjaxRequest.numActiveAjaxGroupRequests[req.groupName])=="undefined") {
					AjaxRequest.numActiveAjaxGroupRequests[req.groupName] = 0;
				}
				AjaxRequest.numActiveAjaxGroupRequests[req.groupName]++;
				if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==1 && typeof(req.onGroupBegin)=="function") {
					req.onGroupBegin(req.groupName);
				}
			}
			if (typeof(req.onLoading)=="function") {
				req.onLoading(req);
			}
			req.onLoadingInternalHandled = true;
		};
	req.onLoadedInternal = 
		function() {
			if (req.onLoadedInternalHandled) { return; }
			if (typeof(req.onLoaded)=="function") {
				req.onLoaded(req);
			}
			req.onLoadedInternalHandled = true;
		};
	req.onInteractiveInternal = 
		function() {
			if (req.onInteractiveInternalHandled) { return; }
			if (typeof(req.onInteractive)=="function") {
				req.onInteractive(req);
			}
			req.onInteractiveInternalHandled = true;
		};
	req.onCompleteInternal = 
		function() {
			if (req.onCompleteInternalHandled || req.aborted) { return; }
			req.onCompleteInternalHandled = true;
			AjaxRequest.numActiveAjaxRequests--;
			if (AjaxRequest.numActiveAjaxRequests==0 && typeof(window['AjaxRequestEnd'])=="function") {
				AjaxRequestEnd(req.groupName);
			}
			if (req.groupName!=null) {
				AjaxRequest.numActiveAjaxGroupRequests[req.groupName]--;
				if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==0 && typeof(req.onGroupEnd)=="function") {
					req.onGroupEnd(req.groupName);
				}
			}
			req.responseReceived = true;
			req.status = req.xmlHttpRequest.status;
			req.statusText = req.xmlHttpRequest.statusText;
			req.responseText = req.xmlHttpRequest.responseText;
			req.responseXML = req.xmlHttpRequest.responseXML;
			if (typeof(req.onComplete)=="function") {
				req.onComplete(req);
			}
			if (req.xmlHttpRequest.status==200 && typeof(req.onSuccess)=="function") {
				req.onSuccess(req);
			}
			else if (typeof(req.onError)=="function") {
				req.onError(req);
			}

			// Clean up so IE doesn't leak memory
			delete req.xmlHttpRequest['onreadystatechange'];
			req.xmlHttpRequest = null;
		};
	req.onTimeoutInternal = 
		function() {
			if (req!=null && req.xmlHttpRequest!=null && !req.onCompleteInternalHandled) {
				req.aborted = true;
				req.xmlHttpRequest.abort();
				AjaxRequest.numActiveAjaxRequests--;
				if (AjaxRequest.numActiveAjaxRequests==0 && typeof(window['AjaxRequestEnd'])=="function") {
					AjaxRequestEnd(req.groupName);
				}
				if (req.groupName!=null) {
					AjaxRequest.numActiveAjaxGroupRequests[req.groupName]--;
					if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==0 && typeof(req.onGroupEnd)=="function") {
						req.onGroupEnd(req.groupName);
					}
				}
				if (typeof(req.onTimeout)=="function") {
					req.onTimeout(req);
				}
			// Opera won't fire onreadystatechange after abort, but other browsers do. 
			// So we can't rely on the onreadystate function getting called. Clean up here!
			delete req.xmlHttpRequest['onreadystatechange'];
			req.xmlHttpRequest = null;
			}
		};

	// ----------------
	// Instance methods
	// ----------------
	/**
	 * The process method is called to actually make the request. It builds the
	 * querystring for GET requests (the content for POST requests), sets the
	 * appropriate headers if necessary, and calls the 
	 * XMLHttpRequest.send() method
	*/
	req.process = 
		function() {
			if (req.xmlHttpRequest!=null) {
				// Some logic to get the real request URL
				if (req.generateUniqueUrl && req.method=="GET") {
					req.parameters["AjaxRequestUniqueId"] = new Date().getTime() + "" + req.requestIndex;
				}
				var content = null; // For POST requests, to hold query string
				for (var i in req.parameters) {
					if (req.queryString.length>0) { req.queryString += "&"; }
					req.queryString += encodeURIComponent(i) + "=" + encodeURIComponent(req.parameters[i]);
				}
				if (req.method=="GET") {
					if (req.queryString.length>0) {
						req.url += ((req.url.indexOf("?")>-1)?"&":"?") + req.queryString;
					}
				}
				req.xmlHttpRequest.open(req.method,req.url,req.async,req.username,req.password);
				if (req.method=="POST") {
					if (typeof(req.xmlHttpRequest.setRequestHeader)!="undefined") {
						req.xmlHttpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
					}
					content = req.queryString;
				}
				if (req.timeout>0) {
					setTimeout(req.onTimeoutInternal,req.timeout);
				}
				req.xmlHttpRequest.send(content);
			}
		};

	/**
	 * An internal function to handle an Object argument, which may contain
	 * either AjaxRequest field values or parameter name/values
	 */
	req.handleArguments = 
		function(args) {
			for (var i in args) {
				// If the AjaxRequest object doesn't have a property which was passed, treat it as a url parameter
				if (typeof(req[i])=="undefined") {
					req.parameters[i] = args[i];
				}
				else {
					req[i] = args[i];
				}
			}
		};

	/**
	 * Returns the results of XMLHttpRequest.getAllResponseHeaders().
	 * Only available after a response has been returned
	 */
	req.getAllResponseHeaders =
		function() {
			if (req.xmlHttpRequest!=null) {
				if (req.responseReceived) {
					return req.xmlHttpRequest.getAllResponseHeaders();
				}
				alert("Cannot getAllResponseHeaders because a response has not yet been received");
			}
		};

	/**
	 * Returns the the value of a response header as returned by 
	 * XMLHttpRequest,getResponseHeader().
	 * Only available after a response has been returned
	 */
	req.getResponseHeader =
		function(headerName) {
			if (req.xmlHttpRequest!=null) {
				if (req.responseReceived) {
					return req.xmlHttpRequest.getResponseHeader(headerName);
				}
				alert("Cannot getResponseHeader because a response has not yet been received");
			}
		};

	return req;
}

// ---------------------------------------
// Static methods of the AjaxRequest class
// ---------------------------------------

/**
 * Returns an XMLHttpRequest object, either as a core object or an ActiveX 
 * implementation. If an object cannot be instantiated, it will return null;
 */
AjaxRequest.getXmlHttpRequest = function() {
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {
		// Based on http://jibbering.com/2002/4/httprequest.html
		/*@cc_on @*/
		/*@if (@_jscript_version >= 5)
		try {
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				return new ActiveXObject("Microsoft.XMLHTTP");
			} catch (E) {
				return null;
			}
		}
		@end @*/
	}
	else {
		return null;
	}
};

/**
 * See if any request is active in the background
 */
AjaxRequest.isActive = function() {
	return (AjaxRequest.numActiveAjaxRequests>0);
};

/**
 * Make a GET request. Pass an object containing parameters and arguments as 
 * the second argument.
 * These areguments may be either AjaxRequest properties to set on the request 
 * object or name/values to set in the request querystring.
 */
AjaxRequest.get = function(args) {
	AjaxRequest.doRequest("GET",args);
};

/**
 * Make a POST request. Pass an object containing parameters and arguments as 
 * the second argument.
 * These areguments may be either AjaxRequest properties to set on the request 
 * object or name/values to set in the request querystring.
 */
AjaxRequest.post = function(args) {
	AjaxRequest.doRequest("POST",args);
};

/**
 * The internal method used by the .get() and .post() methods
 */
AjaxRequest.doRequest = function(method,args) {
	if (typeof(args)!="undefined" && args!=null) {
		var myRequest = new AjaxRequest();
		myRequest.method = method;
		myRequest.handleArguments(args);
		myRequest.process();
	}
}	;

/**
 * Submit a form. The requested URL will be the form's ACTION, and the request 
 * method will be the form's METHOD.
 * Returns true if the submittal was handled successfully, else false so it 
 * can easily be used with an onSubmit event for a form, and fallback to 
 * submitting the form normally.
 */
AjaxRequest.submit = function(theform, args) {
	var myRequest = new AjaxRequest();
	if (myRequest==null) { return false; }
	var serializedForm = AjaxRequest.serializeForm(theform);
	myRequest.method = theform.method.toUpperCase();
	myRequest.url = theform.action;
	myRequest.handleArguments(args);
	myRequest.queryString = serializedForm;
	myRequest.process();
	return true;
};

/**
 * Serialize a form into a format which can be sent as a GET string or a POST 
 * content.It correctly ignores disabled fields, maintains order of the fields 
 * as in the elements[] array. The 'file' input type is not supported, as 
 * its content is not available to javascript. This method is used internally
 * by the submit class method.
 */
AjaxRequest.serializeForm = function(theform) {
	var els = theform.elements;
	var len = els.length;
	var queryString = "";
	this.addField = 
		function(name,value) { 
			if (queryString.length>0) { 
				queryString += "&";
			}
			queryString += encodeURIComponent(name) + "=" + encodeURIComponent(value);
		};
	for (var i=0; i<len; i++) {
		var el = els[i];
		if (!el.disabled) {
			switch(el.type) {
				case 'text': case 'password': case 'hidden': case 'textarea': 
					this.addField(el.name,el.value);
					break;
				case 'select-one':
					if (el.selectedIndex>=0) {
						this.addField(el.name,el.options[el.selectedIndex].value);
					}
					break;
				case 'select-multiple':
					for (var j=0; j<el.options.length; j++) {
						if (el.options[j].selected) {
							this.addField(el.name,el.options[j].value);
						}
					}
					break;
				case 'checkbox': case 'radio':
					if (el.checked) {
						this.addField(el.name,el.value);
					}
					break;
			}
		}
	}
	return queryString;
};

// -----------------------
// Static Class variables
// -----------------------

/**
 * The number of total AjaxRequest objects currently active and running
 */
AjaxRequest.numActiveAjaxRequests = 0;

/**
 * An object holding the number of active requests for each group
 */
AjaxRequest.numActiveAjaxGroupRequests = new Object();

/**
 * The total number of AjaxRequest objects instantiated
 */
AjaxRequest.numAjaxRequests = 0;


/**
* ###############################################
* GUI WIDGETS & OBJECTS
* ###############################################
*/

/**
* =====================================================
* KAJAX Parser Object
* ***********************************************************
* The Core UI Parser - Parses the KXML in the document
* =====================================================
*/
function KAJAX_parser()
{
	this.tags = new Array('ui:box', 'ui:loading', 'ui:fastforward', 'ui:tree', 'ui:keyboard', 'ui:popup', 'ui:accordion');
	this.tagnames = new Array('tabpanel', 'window');

	// Tab Panel
	this.tabStore = new Array();
	this.tabContentStore = new Array();

	// FastForward
	this.fastForwardProperties = new Array();
	this.fastForwardNodes = new Array();
	this.fastForwardNodePointer = new Array();

	// Tree
	this.treeNodes = new Array();
	this.treeProperties = new Array();
	this.treeNodePointer = new Array();
	this.treeParentNodes = new Array();

	// Menu
	this.menuNodes = new Array();
	this.menuProperties = new Array();
	this.menuNodePointer = new Array();
	this.menuParentNodes = new Array();
	this.activeMenuList = new Array();

	// Accordion
	this.accordionSections = new Array();
	this.accordionPointer = new Array();
	this.accordionItemPointer = new Array();
	this.accordionProperties = new Array();

	// Windows
	this.windowZIndex = 0;
	this.windowNodes = new Array();
	this.windowNodePointer = new Array();

	// Tooltips
	this.toolTipStore = new Array();
	this.toolTipProperties = new Array();

	// Keyboard Handler
	this.keyMap = new Array();
	this.keyStore = new Array();
	this.keyMap["0"] = '48';
	this.keyMap['1'] = '49';
	this.keyMap["2"] = '50';
	this.keyMap["3"] = '51';
	this.keyMap["4"] = '52';
	this.keyMap["5"] = '53';
	this.keyMap["6"] = '54';
	this.keyMap["7"] = '55';
	this.keyMap["8"] = '56';
	this.keyMap["9"] = '57';
	this.keyMap["A"] = '65';
	this.keyMap["B"] = '66';
	this.keyMap["C"] = '67';
	this.keyMap["D"] = '68';
	this.keyMap["E"] = '69';
	this.keyMap["F"] = '70';
	this.keyMap["G"] = '71';
	this.keyMap["H"] = '72';
	this.keyMap["I"] = '73';
	this.keyMap["J"] = '74';
	this.keyMap["K"] = '75';
	this.keyMap["L"] = '76';
	this.keyMap["M"] = '77';
	this.keyMap["N"] = '78';
	this.keyMap["O"] = '79';
	this.keyMap["P"] = '80';
	this.keyMap["Q"] = '81';
	this.keyMap["R"] = '82';
	this.keyMap["S"] = '83';
	this.keyMap["T"] = '84';
	this.keyMap["U"] = '85';
	this.keyMap["V"] = '86';
	this.keyMap["W"] = '87';
	this.keyMap["X"] = '88';
	this.keyMap["Y"] = '89';
	this.keyMap["Z"] = '90';
}

/**
* Parses the DOM Tree
*/
KAJAX_parser.prototype.parse = function (x) {
	for (var ii=0; ii<this.tags.length; ii++)
	{
		var currentTag = this.getBrowserTag(this.tags[ii]);

		var tagElements = document.getElementsByTagName(currentTag);

		if (typeof tagElements != 'function' && typeof tagElements != 'object')
		{
			continue;
		}

		var elementStore = new Array();
		for (var jj=0; jj<tagElements.length; jj++)
		{
			elementStore[jj] = tagElements.item(jj);
		}

		// We should have the elements by now, parse them.
		for (var kk=0; kk<elementStore.length; kk++)
		{
			var processElement = elementStore[kk];

			var elementType = 'render_'+currentTag.substring(currentTag.indexOf(':')+1);

			eval("this."+elementType)(processElement);
		}
	}

	for (var ii=0; ii<this.tagnames.length; ii++)
	{
		var currentTagName = this.tagnames[ii];

/*		var tagElements = document.getElementsByName(currentTagName);

		if (typeof tagElements != 'function' && typeof tagElements != 'object')
		{
			continue;
		}

		var elementStore = new Array();
		for (var jj=0; jj<tagElements.length; jj++)
		{
			var processElement = tagElements[jj];

			var elementType = 'render_'+currentTagName;
			eval("this."+elementType)(processElement);

//			elementStore[jj] = tagElements.item(jj);
		}

		// We should have the elements by now, parse them.
		for (var kk=0; kk<elementStore.length; kk++)
		{
			var processElement = elementStore[kk];

			var elementType = 'render_'+currentTagName;
			eval("this."+elementType)(processElement);
		}*/

		var tagElements = new Array();
		while (tagElements = document.getElementsByName(currentTagName)) {
			if (typeof tagElements != 'function' && typeof tagElements != 'object')
			{
				continue;
			}

			if (!tagElements.length)
			{
				break;
			}

			for (var jj=0; jj<tagElements.length; jj++)
			{
				var processElement = tagElements[jj];

				var elementType = 'render_'+currentTagName;
				eval("this."+elementType)(processElement);
			}
		}
	}

	if (enTinyMCE)
	{
		var contentsElement = window.$KAJAX._interface.getObject("contentshtml");
		tinyMCE.execCommand('mceAddControl',true,'contentshtml');
	}
}

/**
* Returns the tag based on browser type, Mozilla requires a tag prefixed with namespace whereas IE and Opera require a plain tag.
*/
KAJAX_parser.prototype.getBrowserTag = function (tagName) {
	if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op)
	{
		return tagName;
	} else {
		return tagName.substring(tagName.indexOf(':')+1);
	}
}

/**
* Returns the tag based on browser type, Mozilla/OP requires a tag prefixed with namespace whereas IE requires a plain tag.
*/
KAJAX_parser.prototype.isValidTag = function (tagName, finalName) {
	tagName = tagName.toLowerCase();

	if (((window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) && tagName == finalName) || (tagName.indexOf(':') && tagName == finalName))
	{
		return true;
	} else {
		if (tagName == finalName.substring(finalName.indexOf(':')+1))
		{
			return true;
		}
	}

	return false;
}






/**
* ###############################################
* BEGIN BOX CONTROL
* ###############################################
*/

/**
* Renders a box
*/
KAJAX_parser.prototype.render_box = function (element) {
	var bodyElement = document.getElementsByTagName("body");
	var newElement = document.createElement("fieldset");
	newElement.className = 'kajaxfieldset';

	var legend = element.getAttribute("legend");
	if (legend)
	{
		var newLegend = document.createElement("legend");
		newLegend.innerHTML = legend;

		newElement.appendChild(newLegend);
	}

	var newContents = document.createElement("div");
	newContents.innerHTML = element.innerHTML;
	newElement.appendChild(newContents);

	bodyElement[0].replaceChild(newElement, element);
}


/**
* ###############################################
* END BOX CONTROL
* ###############################################
*/












/**
* ###############################################
* BEGIN TOOLTIP CONTROL
* ###############################################
*/

/**
* Renders a tooltip box
*/
KAJAX_parser.prototype.displayToolTipXML = function (event, tipName, loadingText, xmlURL, tipWidth, tipHeight) {


	if (window.$KAJAX._browserDetect.ie)
	{
		var cordY = event.y;
		var cordX = event.x;
	} else {
		var cordY = event.pageY;
		var cordX = event.pageX;
	}

	WidgetToolTip.displayToolTipXY(cordX, cordY, tipName, loadingText, xmlURL, tipWidth, tipHeight);
}

/**
* Widget Class for Tool Tip Control
*/
function WidgetToolTip()
{
	window.$KAJAX.eventOnClick[window.$KAJAX.eventOnClick.length] = function (event) {
		WidgetToolTip.destroyAllToolTips(event);
	}
}

WidgetToolTip.prototype.displayToolTipXY = function (cordX, cordY, tipName, loadingText, xmlURL, tipWidth, tipHeight) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	var tipObject = window.$KAJAX._interface.getObject("tip_"+tipName);
	if (tipObject)
	{
		// There is already another object for this
		tipObject.style.left = cordX+'px';
		tipObject.style.top = cordY+'px';
		tipObject.style.display = 'block';
/*		tipObject.innerHTML = '<img src="'+ imagePath +'loadingcircle.gif" align="absmiddle" border="0" /> '+loadingText;

		if (!window.$KAJAX._parser.toolTipProperties[tipName]["requestactive"])
		{
			AjaxRequest.get(
				{
					'url':xmlURL,
					'onSuccess':function(req){ WidgetToolTip.loadToolTipData(tipName, req.responseText); }
				}
			);
		}*/

		return true;
	}

	var subDiv = document.createElement("div");
	subDiv.className = 'kajaxtooltip';
	subDiv.innerHTML = '<img src="'+ imagePath +'loadingcircle.gif" align="absmiddle" border="0" /> '+loadingText;
	subDiv.id = 'tip_'+tipName;
	window.$KAJAX._parser.toolTipProperties[tipName] = new Array();

	var subWidth = tipWidth;
	var subHeight = tipHeight;
	if (!subWidth)
	{
		subWidth = 250;
	}
	if (!subHeight)
	{
		subHeight = 50;
	}

	subDiv.style.width = subWidth+'px';
//	subDiv.style.height = subHeight+'px';

	subDiv.style.left = cordX+'px';
	subDiv.style.top = cordY+'px';

	subDiv.style.textAlign = 'left';
	subDiv.style.padding = '5px';

	AjaxRequest.get(
		{
			'url':xmlURL,
			'onSuccess':function(req){ WidgetToolTip.loadToolTipData(tipName, req.responseText); }
		}
	);

	var tipIndex = window.$KAJAX._parser.toolTipStore.length;
	window.$KAJAX._parser.toolTipStore[tipIndex] = tipName;

	bodyElement[0].appendChild(subDiv);
}

WidgetToolTip.prototype.loadToolTipData = function (tipName, responseData) {
	var tipObject = window.$KAJAX._interface.getObject("tip_"+tipName);
	if (!tipObject)
	{
		return false;
	}
	window.$KAJAX._parser.toolTipProperties[tipName]["requestactive"] = true;

	tipObject.innerHTML = responseData;
}

WidgetToolTip.prototype.destroyAllToolTips = function () {
	if (!window.$KAJAX._parser.toolTipStore.length)
	{
		return false;
	}

	var bodyElement = document.getElementsByTagName("body");

	for (var ii=0; ii<window.$KAJAX._parser.toolTipStore.length; ii++)
	{
		var currentToolTip = window.$KAJAX._parser.toolTipStore[ii];
		var tipObject = window.$KAJAX._interface.getObject("tip_"+currentToolTip);
		if (tipObject)
		{
			tipObject.style.display = 'none';
//			bodyElement[0].removeChild(tipObject);
		}
	}

	window.$KAJAX._parser.destroyPending = false;

//	window.$KAJAX._parser.toolTipStore = new Array();
}

WidgetToolTip.prototype.destroyAllToolTipsDelay = function () {
	if (!window.$KAJAX._parser.toolTipStore.length || window.$KAJAX._parser.destroyPending)
	{
		return false;
	}

	window.$KAJAX._parser.destroyPending = true;
	setTimeout(function() { WidgetToolTip.destroyAllToolTips(); }, 500);
}










/**
* ###############################################
* BEGIN LOADING CONTROL
* ###############################################
*/

/**
* Renders a loading box
*/
KAJAX_parser.prototype.render_loading = function (element) {
	var bodyElement = document.getElementsByTagName("body");
	var newElement = document.createElement("div");
	newElement.className = 'kajaxloadingbg';
	newElement.id = 'loadingtest';
	var innerContent = 'Loading...';
	if (element.innerHTML != '')
	{
		innerContent = element.innerHTML;
	}

	var subDiv = document.createElement("div");
	subDiv.className = 'kajaxloading';
	subDiv.innerHTML = innerContent;

	var subWidth = element.getAttribute("width");
	var subHeight = element.getAttribute("height");
	if (!subWidth)
	{
		subWidth = 150;
	}

	subDiv.style.width = subWidth+'px';
	var centerWidth = window.$KAJAX._browserDetect.innerWidth/2;
	centerWidth = centerWidth-(subWidth/2);

	if (!subHeight)
	{
		subHeight = 16;
	}
	subDiv.style.height = subHeight+'px';
	var centerHeight = ((window.$KAJAX._browserDetect.innerHeight/2)-((subHeight/2)+100));

	subDiv.style.left = centerWidth+'px';
	subDiv.style.top = centerHeight+'px';

	subDiv.style.textAlign = 'center';
	subDiv.style.padding = '10px';

	newElement.appendChild(subDiv);

	newElement.style.top = 0;
	newElement.style.left = 0;
	newElement.style.width = window.$KAJAX._browserDetect.screenWidth+'px';
	newElement.style.height = window.$KAJAX._browserDetect.screenHeight+'px';

	var backgroundImage = element.getAttribute("background");
	if (backgroundImage)
	{
		newElement.style.backgroundImage = "url("+ backgroundImage +")";
	}

	bodyElement[0].replaceChild(newElement, element);
	bodyElement[0].style.overflow = 'hidden';

	var loadingTimeout = parseInt(element.getAttribute("timeout"));
	if (loadingTimeout)
	{
		setTimeout(function () { window.$KAJAX._parser.destroyLoading(newElement)}, 2000);
	}
}

/**
* Create a new loading box
*/
KAJAX_parser.prototype.createLoadingBox = function (loadingName, loadingText, subWidth, subHeight, backgroundImage, loadingTimeout) {
	var bodyElement = document.getElementsByTagName("body");

	var newElement = document.createElement("div");
	newElement.className = 'kajaxloadingbg';
	newElement.id = loadingName;
	var innerContent = loadingText;

	var subDiv = document.createElement("div");
	subDiv.className = 'kajaxloading';
	subDiv.innerHTML = innerContent;

	if (!subWidth)
	{
		subWidth = 150;
	}

	subDiv.style.width = subWidth+'px';
	var centerWidth = window.$KAJAX._browserDetect.innerWidth/2;
	centerWidth = centerWidth-(subWidth/2);

	if (!subHeight)
	{
		subHeight = 16;
	}
	subDiv.style.height = subHeight+'px';
	var centerHeight = ((window.$KAJAX._browserDetect.innerHeight/2)-((subHeight/2)+100));

	subDiv.style.left = centerWidth+'px';
	subDiv.style.top = centerHeight+'px';

	subDiv.style.textAlign = 'center';
	subDiv.style.padding = '10px';

	newElement.appendChild(subDiv);

	newElement.style.top = 0;
	newElement.style.left = 0;
	newElement.style.width = window.$KAJAX._browserDetect.screenWidth+'px';
	newElement.style.height = window.$KAJAX._browserDetect.screenHeight+'px';

	if (backgroundImage)
	{
		newElement.style.backgroundImage = "url("+ backgroundImage +")";
	}

	bodyElement[0].appendChild(newElement);
	bodyElement[0].style.overflow = 'hidden';

	if (loadingTimeout)
	{
		setTimeout(function () { window.$KAJAX._parser.destroyLoading(newElement)}, (loadingTimeout*1000));
	}
}

KAJAX_parser.prototype.destroyLoading = function (element) {
	var bodyElement = document.getElementsByTagName("body");
	if (!bodyElement)
	{
		return false;
	}

	window.document.body.removeChild(element);
}

/**
* ###############################################
* END LOADING CONTROL
* ###############################################
*/


















/**
* ###############################################
* BEGIN TAB CONTROL
* ###############################################
*/

/**
* Renders a Tab Panel
*/
KAJAX_parser.prototype.render_tabpanel = function (element) {
	if (!element.getAttribute("panelid"))
	{
		return false;
	}

	var bodyElement = document.getElementsByTagName("body");
	var ulElement = document.createElement("ul");
	var parentDivElement = document.createElement("div");
	parentDivElement.className = 'kajaxtabparent';
	var tabContents;
	var tabPanelStoreId = randomString();
	var panelID = element.getAttribute("panelid");

	TabWidget.tabNodes[panelID] = new Array();
	var tabPanelId = "tabpanel_"+element.getAttribute("panelid");
	ulElement.id = tabPanelId;
	window.$KAJAX._parser.tabStore[tabPanelStoreId] = new Array();

	var noStore = false;
	if (element.getAttribute("nostore") == "true" || element.getAttribute("nostore") == "1")
	{
		noStore = true;
	}

	if (!noStore)
	{
		var divElement = document.createElement("div");
	}
	if (element.getAttribute("tabstyle") == "bottom")
	{
		ulElement.className = 'kajaxtabbottom';
	} else {
		if (!noStore)
		{
			divElement.className = "kajaxtabcontent";
		}
		ulElement.className = 'kajaxtab';
	}

	if (!noStore)
	{
		divElement.id = "tabstore_"+element.getAttribute("panelid");
	}

	var brElement = document.createElement("br");

	if (element.getAttribute("tabstyle") == "bottom")
	{
		if (!noStore)
		{
			parentDivElement.appendChild(divElement);
		}
		parentDivElement.appendChild(ulElement);
		parentDivElement.appendChild(brElement);
	} else {
		if (!noStore)
		{
			parentDivElement.appendChild(ulElement);
		}

		parentDivElement.appendChild(divElement);
		parentDivElement.appendChild(brElement);
	}

	var parentNode = element.parentNode;
	element.parentNode.replaceChild(parentDivElement, element);

	if (element.hasChildNodes())
	{
		var childNodes = element.childNodes;

		for (var ii=0; ii<childNodes.length; ii++)
		{
			if (childNodes[ii].tagName == "DIV" && childNodes[ii].getAttribute("title") && childNodes[ii].getAttribute("name") == "tab")
			{
				var isSelected = false;
				var isDisabled = false;
				var canClose = false;
				if (childNodes[ii].getAttribute("selected") == "true" || childNodes[ii].getAttribute("selected") == "1")
				{
					isSelected = true;
				}

				if (childNodes[ii].getAttribute("disabled") == "true" || childNodes[ii].getAttribute("disabled") == "1")
				{
					isDisabled = true;
				}

				if (childNodes[ii].getAttribute("close") == "true" || childNodes[ii].getAttribute("close") == "1")
				{
					canClose = true;
				}

				TabWidget.createTab(element.getAttribute("panelid"), isSelected, isDisabled, childNodes[ii].getAttribute("title"), childNodes[ii].innerHTML, childNodes[ii].getAttribute("linkxml"), canClose, childNodes[ii].getAttribute("loadlink"), childNodes[ii].getAttribute("tabicon"), element.getAttribute("tabstyle"), childNodes[ii].getAttribute("storeclass"));
			}
		}
	}
}

/**
* Tab Widget Class
*/
function TabWidget()
{
	this.tabNodes = new Array();
	this.tabPointer = new Array();
}

TabWidget.prototype.destroyTab = function (nodeID) {
	var nodePointer = this.tabPointer["tab_"+nodeID];
	var tabElement = window.$KAJAX._interface.getObject("tab_"+nodeID);
	if (!tabElement || !nodePointer)
	{
//		alert("false!");
		return false;
	}
	var delNodeIndex;
	// We need to select some other node before destroying this one...
	if (nodePointer.isselected)
	{
		// We itterate through the tabs first in ascending order
		var selectNext = false;
		var selectNode;
		for (var ii=0; ii<this.tabNodes[nodePointer.panelid].length; ii++)
		{
			var currentNode = this.tabNodes[nodePointer.panelid][ii];
			if (selectNext)
			{
				var nodeElement = window.$KAJAX._interface.getObject("tab_"+currentNode.nodeid);
				if (nodeElement) // Make sure its a valid element before trying to switch over
				{
					this.switchTab(currentNode.panelid, "tab_"+currentNode.nodeid);
					selectNext = false;
//					alert("[1] delete: "+currentNode.title+"--"+nodePointer.title);
					break;
				} else {
//					alert("[1]boggie: "+currentNode.title+"--"+nodePointer.title);
				}
			} else if (currentNode.nodeid == nodePointer.nodeid) { // We have a match
				selectNext = true;
				delNodeIndex = ii;
//				alert("[1] got a match: "+currentNode.title+"--"+nodePointer.title);
			}
		}

		// Do we need to loop backwards?
		if (selectNext)
		{
			selectNext = false;
//			alert("looping backwards");

			for (var ii=this.tabNodes[nodePointer.panelid].length-1; ii>=0; ii--)
			{
				var currentNode = this.tabNodes[nodePointer.panelid][ii];
				if (selectNext)
				{
					var nodeElement = window.$KAJAX._interface.getObject("tab_"+currentNode.nodeid);
					if (nodeElement) // Make sure its a valid element before trying to switch over
					{
//					alert("delete: "+currentNode.title+"--"+nodePointer.title);
						this.switchTab(currentNode.panelid, "tab_"+currentNode.nodeid);
						selectNext = false;
						break;
					} else {
//					alert("boggie: "+currentNode.title+"--"+nodePointer.title);
						
					}
				} else if (currentNode.nodeid == nodePointer.nodeid) { // We have a match
//					alert("got a match: "+currentNode.title+"--"+nodePointer.title);
					selectNext = true;
					delNodeIndex = ii;
				}
			}
		}
	} else {
		for (var ii=0; ii<this.tabNodes[nodePointer.panelid].length; ii++)
		{
			var currentNode = this.tabNodes[nodePointer.panelid][ii];
			if (currentNode.nodeid == nodePointer.nodeid) { // We have a match
				delNodeIndex = ii;
			}
		}
	}

	if (delNodeIndex)
	{
		this.tabNodes[nodePointer.panelid][delNodeIndex].contents = '';
		this.tabNodes[nodePointer.panelid].splice(delNodeIndex, 1);
	}
	tabElement.parentNode.removeChild(tabElement);
}

TabWidget.prototype.createTab = function(tabPanelId, tabIsSelected, tabIsDisabled, tabTitle, strContents, linkXML, canClose, loadlink, tabIcon, tabStyle, storeClass) {
	var parentElement = window.$KAJAX._interface.getObject("tabpanel_"+tabPanelId);
	var storeElement = window.$KAJAX._interface.getObject("tabstore_"+tabPanelId);
	if (!parentElement)
	{
		return false;
	}


	var randomData = randomString();
	var tabID = 'tab_'+randomData;
	var tabNodeIndex = this.tabNodes[tabPanelId].length;
	this.tabNodes[tabPanelId][tabNodeIndex] = new TabNode(tabPanelId, randomData, tabTitle, strContents, linkXML, canClose, tabIcon, tabStyle);
	var currentTabNode = this.tabNodes[tabPanelId][tabNodeIndex];

	var tabElement = document.createElement("li");
	var isSelected = false;
	var isEnabled = true;
	if (tabIsSelected)
	{
		isSelected = true;
	} else if (tabIsDisabled) {
		isEnabled = false;
	}

	var tabContents;

	this.tabPointer[tabID] = currentTabNode;

	var linkElement = document.createElement("a");
	linkElement.innerHTML = currentTabNode.getTitle(false);
	linkElement.href = "#";
	linkElement.id = tabID;

	currentTabNode.elementId = linkElement.id;

	var subStoreElement = document.createElement("div");
	subStoreElement.id = "tabsubstore_"+randomData;
	currentTabNode.substoreid = "tabsubstore_"+randomData;
	subStoreElement.innerHTML = strContents;
	subStoreElement.style.display = 'none';
	if (storeClass)
	{
		subStoreElement.className = storeClass;
	}

	if (storeElement)
	{
		storeElement.appendChild(subStoreElement);
	}

	if (!isEnabled)
	{
		linkElement.className = "disabledtab";

		if (isSelected && storeElement)
		{
			subStoreElement.style.display = 'block';
		}

	} else if (isSelected) {
		if (tabStyle == "bottom")
		{
			linkElement.className = "bottomcurrenttab";
		} else {
			linkElement.className = "currenttab";
		}

		if (storeElement)
		{
			subStoreElement.style.display = 'block';
		}
	} else if (tabStyle == "bottom") {
		linkElement.className = "bottomtab";
	}

	if (isEnabled)
	{
		linkElement.onclick = function () {
			this.blur();
			TabWidget.switchTab(tabPanelId, this.id);
		}
	} else {
		linkElement.onclick = function () {
			this.blur();
		}
	}

	tabElement.appendChild(linkElement);
	parentElement.appendChild(tabElement);

	if (tabIsSelected)
	{
		this.switchTab(tabPanelId, tabID);
	}

	if (loadlink == true && linkXML)
	{
		currentTabNode.loadURL(true);
	}
}

TabWidget.prototype.switchTab = function (tabPanelId, elementId) {
	var parentElement = window.$KAJAX._interface.getObject("tabpanel_"+tabPanelId);
	var storeElement = window.$KAJAX._interface.getObject("tabstore_"+tabPanelId);
	if (!parentElement)
	{
		return false;
	}

	var selectedTabID;
	var currentTabNode = this.tabPointer[elementId];
	if (!currentTabNode || !this.tabNodes[tabPanelId].length)
	{
		return false;
	}

	// Get the content
	var divObject = window.$KAJAX._interface.getObject("tabstore_"+tabPanelId);
	if (divObject)
	{
		var currentSelectedNode;
		for (var ii=0; ii<this.tabNodes[tabPanelId].length; ii++)
		{
			var currentNode = this.tabNodes[tabPanelId][ii];
			if (currentNode.isselected)
			{
				currentSelectedNode = this.tabNodes[tabPanelId][ii];
				break;
			}
		}

		if (currentSelectedNode)
		{
			currentSelectedNode.contents = divObject.innerHTML;
		}
	}

	var selectedNode;
	for (var ii=0; ii<this.tabNodes[tabPanelId].length; ii++)
	{
		var currentNode = this.tabNodes[tabPanelId][ii];

		var tabObject = window.$KAJAX._interface.getObject("tab_"+currentNode.nodeid);
		if (tabObject && "tab_"+currentNode.nodeid == elementId)
		{
			if (currentNode.tabstyle == "bottom")
			{
				tabObject.className = 'bottomcurrenttab';
			} else {
				tabObject.className = 'currenttab';
			}
			currentNode.isselected = true;
			selectedNode = currentNode;
		} else if (tabObject) {
			if (currentNode.tabstyle == "bottom")
			{
				tabObject.className = 'bottomtab';
			} else {
				tabObject.className = '';
			}
			var subStoreElement = window.$KAJAX._interface.getObject(currentNode.substoreid);
			if (subStoreElement)
			{
				subStoreElement.style.display = 'none';
			}
			currentNode.isselected = false;
		}
	}

	if (selectedNode && selectedNode.linkxml && !selectedNode.contentLoaded)
	{
		selectedNode.loadURL();
	} else if (selectedNode && divObject) {
		var subStoreElement = window.$KAJAX._interface.getObject(currentTabNode.substoreid);
		if (subStoreElement)
		{
			subStoreElement.style.display = 'block';
		}
	}
}

/**
* Tab Node Class
*/
function TabNode(panelID, nodeID, tabTitle, strContents, linkXML, canClose, tabIcon, tabStyle)
{
	this.panelid = panelID;
	this.nodeid = nodeID;
	this.title = tabTitle;
	this.contents = strContents;
	this.linkxml = linkXML;
	this.canclose = canClose;
	this.contentLoaded = false;
	this.isselected = false;
	this.icon = tabIcon;
	this.tabstyle = tabStyle;
}

TabNode.prototype.getTitle = function (loadingCircle) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	if (this.canclose)
	{
		var nodeTitle = '<span style="padding-right: 22px;">';
	} else {
		var nodeTitle = '<span>';
	}

	if (loadingCircle && imagePath)
	{
		nodeTitle += '<img src="'+imagePath+'loadingcircle.gif" align="absmiddle" border="0" /> ';
	} else if (this.icon) {
		nodeTitle += '<img src="'+imagePath+this.icon+'" align="absmiddle" border="0" /> ';
	} else {
//		nodeTitle += '<img src="'+imagePath+'space.gif" width="1" height="15" align="absmiddle" border="0" /> ';
	}

	nodeTitle += this.title;

	if (this.canclose)
	{
		nodeTitle += '<div id="close" onclick="TabWidget.destroyTab(\''+ this.nodeid +'\');"></div>';
	}

	nodeTitle += '</span>';

	return nodeTitle;
}

/**
* Load the URL
*/
TabNode.prototype.loadURL = function (noUpdate) {
	tabElement = window.$KAJAX._interface.getObject("tab_"+this.nodeid);
	if (!tabElement)
	{
		return false;
	}

	tabElement.innerHTML = this.getTitle(true);

	var nodeID = 'tab_' + this.nodeid;

	AjaxRequest.get(
		{
			'url':this.linkxml,
			'onSuccess':function(req){ TabWidget.tabPointer[nodeID].processLoadedData(req.responseText, noUpdate); }
		}
	);
}

/**
* Processes the loaded data
*/
TabNode.prototype.processLoadedData = function (responseText, noUpdate) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");
	var tabElement = window.$KAJAX._interface.getObject("tab_"+this.nodeid);
	var storeElement = window.$KAJAX._interface.getObject("tabstore_"+this.panelid);
	if (!tabElement)
	{
		return false;
	}

	tabElement.innerHTML = this.getTitle(false);

	this.contentLoaded = true;
	this.contents = responseText;

	if (!noUpdate && storeElement)
	{
		storeElement.innerHTML = responseText;
	}
}

TabWidget = new TabWidget();


/**
* ###############################################
* END TAB CONTROL
* ###############################################
*/











/**
* ###############################################
* BEGIN FASTFORWARD FUNCTIONS
* ###############################################
*/


/**
* Renders a FastForward Panel
*/
KAJAX_parser.prototype.render_fastforward = function (element) {
	var bodyElement = document.getElementsByTagName("body");
	var newElement = document.createElement("div");
	newElement.className = 'kajaxfastforwardmaindiv';

	var scroller = document.createElement("div");
	scroller.className = 'kajaxfastforwardscroller';

	// Attributes
	var attribWidth = parseInt(element.getAttribute("width"));
	var attribHeight = parseInt(element.getAttribute("height"));
	var attribName = element.getAttribute("name");
	var attribBaseURL = element.getAttribute("baseurl");
	var attribLoadXML = element.getAttribute("loadxml");
	var attribSearchXML = element.getAttribute("searchxml");
	var attribBackTitle = element.getAttribute("backtitle");
	var attribTitle = element.getAttribute("title");
	var attribType = element.getAttribute("type");
	var attribImagePath = element.getAttribute("imagepath");

	// Rendering should be done first
	if (!attribName || attribName == "")
	{
		return false;
	}
	scroller.id = "fastforwards_"+attribName;
	newElement.id = "fastforward_"+attribName;

	window.$KAJAX._parser.fastForwardProperties[attribName] = new Array();
	window.$KAJAX._parser.fastForwardProperties[attribName]["baseurl"] = attribBaseURL;
	window.$KAJAX._parser.fastForwardProperties[attribName]["loadxml"] = attribLoadXML;
	window.$KAJAX._parser.fastForwardProperties[attribName]["searchxml"] = attribSearchXML;
	window.$KAJAX._parser.fastForwardProperties[attribName]["width"] = attribWidth;
	window.$KAJAX._parser.fastForwardProperties[attribName]["height"] = attribHeight;
	window.$KAJAX._parser.fastForwardProperties[attribName]["backtitle"] = attribBackTitle;
	window.$KAJAX._parser.fastForwardProperties[attribName]["type"] = attribType;
	window.$KAJAX._parser.fastForwardProperties[attribName]["title"] = attribTitle;
	window.$KAJAX._parser.fastForwardProperties[attribName]["imagepath"] = attribImagePath;
	window.$KAJAX._parser.fastForwardProperties[attribName]["animultiplier"] = 3;
	window.$KAJAX._parser.fastForwardProperties[attribName]["isthreadrunning"] = false;
	window.$KAJAX._parser.fastForwardProperties[attribName]["itemcount"] = 0;
	window.$KAJAX._parser.fastForwardProperties[attribName]["cachedvalue"] = "";
	window.$KAJAX._parser.fastForwardProperties[attribName]["currentsearchxml"] = attribBaseURL+attribSearchXML;

	var nodeIndex = window.$KAJAX._parser.fastForwardNodes.length;
	window.$KAJAX._parser.fastForwardNodes[nodeIndex] = new FastForwardNode(attribName, attribTitle, false, false, attribLoadXML, attribSearchXML, false);
	window.$KAJAX._parser.fastForwardNodes[nodeIndex].nodePointer = '0';
	window.$KAJAX._parser.fastForwardProperties[attribName]["parentnode"] = window.$KAJAX._parser.fastForwardNodes[nodeIndex];

	if (attribWidth)
	{
		newElement.style.width = attribWidth+"px";
	}

	if (attribHeight)
	{
		newElement.style.height = attribHeight+"px";
	}
	scroller.style.width = newElement.style.width;
	scroller.style.height = newElement.style.height;

	var panelWidthStr = new String(newElement.style.width);
	panelWidthStr.replace("px", "");
	var panelWidth = parseInt(panelWidthStr);
	window.$KAJAX._parser.fastForwardProperties[attribName]["panelwidth"] = panelWidth;

	if (attribBaseURL)
	{
		var loadXMLURL = attribBaseURL+attribLoadXML;
		var searchXMLURL = attribBaseURL+attribSearchXML;
	} else {
		var loadXMLURL = attribLoadXML;
		var searchXMLURL = attribSearchXML;
	}
	window.$KAJAX._parser.fastForwardProperties[attribName]["loadxmlurl"] = loadXMLURL;
	window.$KAJAX._parser.fastForwardProperties[attribName]["searchxmlurl"] = searchXMLURL;

	scroller.style.overflow = 'hidden';
	var newContents = document.createElement("div");
	newContents.id = "fastforward_new_"+attribName;
	newContents.className = 'fftemp';


	scroller.style.width=newElement.style.width;
	scroller.style.height=(attribHeight-26)+'px';
	scroller.style.overflow = 'auto';


	scroller.appendChild(newContents);


	newContents.style.width = '100%';
//	newContents.style.top = '20px';
	newContents.style.left = '0px';
//	newContents.style.height = (attribHeight-26)+'px';
//	newContents.style.overflow = 'auto';

//	scroller.style.width = newElement.style.width;
//	newContents.style.top = '20px';
//	scroller.style.height = (attribHeight-26)+'px';
//	scroller.style.overflow = 'auto';

	if (!window.$KAJAX._parser.fastForwardProperties[attribName]["title"])
	{
		var titleName = "FastForward";
	} else {
		var titleName = window.$KAJAX._parser.fastForwardProperties[attribName]["title"];
	}
	WidgetFastForward.addFastForwardTitleButton(attribName, titleName, newElement);

//	alert(newElement.innerHTML);
	newElement.appendChild(scroller);

	if (attribType == "popup")
	{
		newElement.className = 'kajaxfastforwardmaindivfloat';
	}

	bodyElement[0].replaceChild(newElement, element);

	if (attribType != "popup")
	{
		// Once the element has been rendered we fetch the XML
		AjaxRequest.get(
			{
				'url':loadXMLURL,
				'onSuccess':function(req){ WidgetFastForward.processFastForwardNodes(attribName, req.responseXML, window.$KAJAX._parser.fastForwardNodes[nodeIndex], false); }
			}
		);
	}
}

/**
* Loads the fast forward panel set as popup
*/
KAJAX_parser.prototype.loadFastForwardPanel = function (event, panelName) {
	var panelProperties = window.$KAJAX._parser.fastForwardProperties[panelName];
	if (!panelProperties)
	{
		return false;
	}

	var panelObject = window.$KAJAX._interface.getObject("fastforward_"+panelName);
	if (!panelObject)
	{
		return false;
	}

	if (window.$KAJAX._browserDetect.ie)
	{
		var cordY = event.y;
		var cordX = event.x;
	} else {
		var cordY = event.pageY;
		var cordX = event.pageX;
	}
	panelObject.style.left = cordX+"px";
	panelObject.style.top = cordY+"px";
	panelObject.style.display = 'block';

	var textObject = window.$KAJAX._interface.getObject("fastforward_newsearch_"+panelName);
	if (textObject)
	{
		textObject.focus();
	}

	panelProperties["visible"] = true;

	if (!panelProperties["parentnode"].n.length)
	{
		// Once the element has been rendered we fetch the XML
		AjaxRequest.get(
			{
				'url':panelProperties["loadxml"],
				'onSuccess':function(req){ WidgetFastForward.processFastForwardNodes(panelName, req.responseXML, panelProperties["parentnode"], false); }
			}
		);
	}
}

/**
* Main FastForward Function Handler
*/
function WidgetFastForward()
{
	window.$KAJAX.eventOnClick[window.$KAJAX.eventOnClick.length] = function (event) {
		WidgetFastForward.hideAllFastForward(event);
	}
}

WidgetFastForward.prototype.hideAllFastForward = function (event) {
	var el;

	if (window.$KAJAX._browserDetect.ie) {
		el = window.event.srcElement;
	} else {
		el = (event.target.tagName ? event.target : event.target.parentNode);
	}

	if (this.getContainerWith(el, "DIV", "kajaxfastforwardmaindivfloat") == null) {
		for (x in window.$KAJAX._parser.fastForwardProperties) {
			if (window.$KAJAX._parser.fastForwardProperties[x]["visible"])
			{
				this.hideFastForward(x);
			}
		}
	}
}

WidgetFastForward.prototype.getContainerWith = function (node, tagName, className) {
	// Starting with the given node, find the nearest containing element
	// with the specified tag name and style class.

	while (node != null) {
		if (node.tagName != null && node.tagName == tagName && this.hasClassName(node, className)) {
			return node;
		}

			node = node.parentNode;
	}

	return node;
}

WidgetFastForward.prototype.hasClassName = function (el, name) {
	var i, list;

	// Return true if the given element currently has the given class name.

	list = el.className.split(" ");
	for (i = 0; i < list.length; i++) {
		if (list[i] == name) {
			return true;
		}
	}

	return false;
}
WidgetFastForward.prototype.processFastForwardNodes = function (panelName, xmlDoc, parentFastForwardNode, isSearchTrigger) {
	var itemRoot = xmlDoc.getElementsByTagName('items').item(0);
	var nodeData = new Array();

	var nodeCount = 0;
	for (var iNode = 0; iNode < itemRoot.childNodes.length; iNode++) {
		var node = itemRoot.childNodes.item(iNode);

		if (node.nodeType != 1)
		{
			continue;
		}

		var nodeLength = parseInt(node.childNodes.length/2);

		var nodeData = new Array();
		for (x=0; x<node.childNodes.length; x++)
		{
			var nodeItem = node.childNodes.item(x);

			if (nodeItem.nodeType != 1)
			{
				continue;
			}

			if (nodeItem.firstChild)
			{
				nodeData[nodeItem.nodeName] = nodeItem.firstChild.data;
			}
		}

		parentFastForwardNode.addItem(new FastForwardNode(panelName, nodeData["title"], nodeData["link"], nodeData["target"], nodeData["subxml"], nodeData["searchxml"]));

		nodeCount++;
	}

	this.renderFastForwardPanel(panelName, parentFastForwardNode, false, isSearchTrigger);
}

WidgetFastForward.prototype.renderFastForwardPanel = function (panelName, parentNode, isBackButton, isSearchTrigger) {
	// We change the naming of old div from new to old and create an empty container
	var panelObject = window.$KAJAX._interface.getObject("fastforwards_"+panelName);
	if (!panelObject)
	{
		return false;
	}
	var panelProperties = window.$KAJAX._parser.fastForwardProperties[panelName];

	if (parentNode.parentNode || isBackButton)
	{
		var oldPanelObject = window.$KAJAX._interface.getObject("fastforward_new_"+panelName);
		if (!oldPanelObject)
		{
			return false;
		}

		// Rename it to old
		oldPanelObject.id = "fastforward_old_"+panelName;

		// Now create a new container, all our new items will be added to this
		var newContents = document.createElement("div");
		newContents.id = "fastforward_new_"+panelName;
		newContents.className = 'fftemp';
		// Position the new box to top right
//		newContents.style.top = '0px';

/*		newContents.style.width = panelProperties["width"];
		newContents.style.left = '0px';
		newContents.style.height = (panelProperties["height"]-26)+'px';
		newContents.style.overflow = 'auto';*/

		if (isBackButton)
		{
			newContents.style.left = (0-window.$KAJAX._parser.fastForwardProperties[panelName]["panelwidth"])+"px";
		} else if (!parentNode.parentNode) {
		} else {
			newContents.style.left = panelObject.style.width;
		}
		panelObject.appendChild(newContents);
	} else {
		var newContents = window.$KAJAX._interface.getObject("fastforward_new_"+panelName);
		if (!newContents)
		{
			return false;
		}
	}

	// Do we need a back button?
	if (parentNode.parentNode)
	{
		if (!window.$KAJAX._parser.fastForwardProperties[panelName]["backtitle"])
		{
			var backTitleName = "Back";
		} else {
			var backTitleName = window.$KAJAX._parser.fastForwardProperties[panelName]["backtitle"];
		}

		this.addFastForwardBackButton(panelName, backTitleName, newContents, parentNode);
	} else {
	}

	// Search button?
	if (parentNode.searchXML)
	{
		this.addFastForwardSearchItem(panelName, newContents, parentNode);
	}

	for (var ii=0; ii<parentNode.n.length; ii++)
	{
		var currentFastForwardNode = parentNode.n[ii];

		var lastItem = this.addFastForwardItem(panelName, currentFastForwardNode.nodeTitle, newContents, currentFastForwardNode);
	}


	var panelObject2 = window.$KAJAX._interface.getObject("fastforward_"+panelName);
//	document.testform.debug.value = panelObject2.innerHTML;
//	alert(panelObject2.innerHTML);
	// By this time all items should be added to new box. So we will have to start our animation and nuke the old box.
	if (isSearchTrigger)
	{
		WidgetFastForward.loadFastForwardObject(panelName);
	} else if (parentNode.parentNode) {
		panelObject.style.overflow='hidden';
		window.$KAJAX._parser.fastForwardProperties[panelName]["anicount"] = 0;
		window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"] = window.setInterval(function () {WidgetFastForward.moveFastForwardObject(panelName, isBackButton)}, 5);
	} else if (isBackButton) {
		panelObject.style.overflow='hidden';
		window.$KAJAX._parser.fastForwardProperties[panelName]["anicount"] = 0;
		window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"] = window.setInterval(function () {WidgetFastForward.moveFastForwardObject(panelName, true)}, 5);
	} else {
		newContents.style.width='100%';
	}
}

WidgetFastForward.prototype.addFastForwardBackButton = function (panelName, itemTitle, panelObject, currentFastForwardNode) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	var newElement = document.createElement("div");
	newElement.className = 'kajaxfastforwarditemtitle';
	newElement.onmouseover = function () {
		this.className = 'kajaxfastforwarditemtitle';
	}

	newElement.onmouseout = function () {
		this.className = 'kajaxfastforwarditemtitle';
	}

	var spanElement1 = document.createElement("div");
	spanElement1.innerHTML = "<img align='absmiddle' src='"+ imagePath+"fastforwardbackarrow.gif" +"' />";
	spanElement1.className = 'kajaxfastforwardbacktitlearrow';

	var spanElement2 = document.createElement("div");
	spanElement2.className = 'kajaxfastforwardbacktitle';
	spanElement2.innerHTML = itemTitle;

	var spanElement3 = document.createElement("div");
	spanElement3.className = 'kajaxfastforwardbacktitleclose';
	spanElement3.innerHTML = "<a href='javascript:WidgetFastForward.hideFastForward(\""+ panelName +"\");'><img border='0' align='absmiddle' src='"+ imagePath+"fastforwardclose.gif" +"' /></a>";

	newElement.appendChild(spanElement1);
	newElement.appendChild(spanElement2);
//	newElement.appendChild(spanElement3);

	spanElement2.onclick = function ()
	{
		this.blur();
		AjaxRequest.get(
			{
				'url':currentFastForwardNode.parentNode.xmlURL,
				'onSuccess':function(req) { WidgetFastForward.renderFastForwardPanel(panelName, currentFastForwardNode.parentNode, true); }
			}
		);
	}


	panelObject.appendChild(newElement);
}

WidgetFastForward.prototype.addFastForwardTitleButton = function (panelName, itemTitle, panelObject) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");
	var panelProperties = window.$KAJAX._parser.fastForwardProperties[panelName];

	var newElement = document.createElement("div");
	newElement.className = 'kajaxfastforwarditemtitle';
	newElement.onmouseover = function () {
		this.className = 'kajaxfastforwarditemtitle';
	}

	newElement.onmouseout = function () {
		this.className = 'kajaxfastforwarditemtitle';
	}

	newElement.innerHTML = "<span style='float:left; margin-right: 4px; margin-left: 4px; float:left; CURSOR: pointer; CURSOR: hand;'><img align='absmiddle' src='"+ imagePath+"fastforwardicon.gif" +"' /> "+itemTitle+"</span><span style='float: right; padding-right: 4px;'><a href='javascript:WidgetFastForward.hideFastForward(\""+ panelName +"\");'><img border='0' align='absmiddle' src='"+ imagePath+"fastforwardclose.gif" +"' /></a></span>";

	panelObject.appendChild(newElement);
}

WidgetFastForward.prototype.hideFastForward = function (panelName) {
	var panelProperties = window.$KAJAX._parser.fastForwardProperties[panelName];
	var panelObject = window.$KAJAX._interface.getObject("fastforward_"+panelName);
	if (!panelObject)
	{
		return false;
	}

	panelProperties["visible"] = false;
	panelObject.style.display = 'none';
}

WidgetFastForward.prototype.handleTitleClick = function (event) {
	if (window.$KAJAX._browserDetect.ie) {
		target = window.event.srcElement;
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		target = event.target;
	}

}


WidgetFastForward.prototype.addFastForwardSearchItem = function (panelName, panelObject, currentFastForwardNode) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	var newElement = document.createElement("div");
	newElement.className = 'kajaxfastforwardsearchcontainer';
	newElement.onmouseover = function () {
		this.className = 'kajaxfastforwardsearchcontainer';
	}

	newElement.onmouseout = function () {
		this.className = 'kajaxfastforwardsearchcontainer';
	}

	var textObject = window.$KAJAX._interface.getObject("fastforward_newsearch_"+panelName);
	if (textObject)
	{
		newElement.appendChild(textObject);
	} else {
		newElement.innerHTML = "<input type='textbox' name='fastforward_newsearch_"+ panelName +"' id='fastforward_newsearch_"+ panelName +"' class='fastforwardsearch' autocomplete='off' style='width: "+ (window.$KAJAX._parser.fastForwardProperties[panelName]["panelwidth"]-30) +"px; BACKGROUND: #FFFFFF URL("+ imagePath +"fastforwardsearch.gif) no-repeat; BACKGROUND-POSITION: 2px 1px;' onFocus='javascript:WidgetFastForward.fastForwardStartAutoSearch(\""+ panelName +"\", this, \""+ currentFastForwardNode.nodePointer +"\");' />";
	}

	panelObject.appendChild(newElement);
}

WidgetFastForward.prototype.fastForwardStartAutoSearch = function (panelName, textElement, nodePointer) {
	if (window.$KAJAX._parser.fastForwardProperties[panelName]["isthreadrunning"] == false)
	{
		setTimeout(function () { WidgetFastForward.fastForwardLookupThread(panelName, nodePointer); }, 2000);
	}
}

/**
* Actual handler thread
*/
WidgetFastForward.prototype.fastForwardLookupThread = function (panelName, nodePointer) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	var currentFastForwardNode = window.$KAJAX._parser.fastForwardNodePointer["ffi_"+panelName+"_"+nodePointer];
	if (!currentFastForwardNode)
	{
		return false;
	}

	window.$KAJAX._parser.fastForwardProperties[panelName]["isthreadrunning"] = true;

	var textObject = window.$KAJAX._interface.getObject("fastforward_newsearch_"+panelName);
	if (!textObject)
	{
		return false;
	}
	var currentValue = textObject.value;

	if (currentValue == "" && window.$KAJAX._parser.fastForwardProperties[panelName]["cachedvalue"] != "")
	{
	} else if (currentValue != window.$KAJAX._parser.fastForwardProperties[panelName]["cachedvalue"] && currentValue != "") {
		textObject.style.background = "#FFFFFF URL("+ imagePath +"loadingcircle.gif) no-repeat";
		textObject.style.backgroundPosition ="2px 1px";
		var searchURL = window.$KAJAX._parser.fastForwardProperties[panelName]["baseurl"]+currentFastForwardNode.searchXML;

		AjaxRequest.get(
			{
				'url': searchURL,
				'onSuccess':function(req) { WidgetFastForward.fastForwardProcessSearchXML(panelName, req.responseXML, currentFastForwardNode, currentValue); }
			}
		);

	}

	window.$KAJAX._parser.fastForwardProperties[panelName]["cachedvalue"] = currentValue;

	setTimeout(function () { WidgetFastForward.fastForwardLookupThread(panelName, nodePointer); }, 2000);
}

/**
* Actual Search Handler
*/
WidgetFastForward.prototype.fastForwardProcessSearchXML = function (panelName, xmlDoc, currentFastForwardNode, textValue) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	var textObject = window.$KAJAX._interface.getObject("fastforward_newsearch_"+panelName);
	if (!textObject)
	{
		return false;
	}
	textObject.style.background = "#FFFFFF URL("+ imagePath +"fastforwardsearch.gif) no-repeat";
	textObject.style.backgroundPosition ="2px 1px";

	var newNode = new FastForwardNode(panelName, "Search: "+textValue, currentFastForwardNode.nodeLink, currentFastForwardNode.nodeTarget, currentFastForwardNode.xmlURL, currentFastForwardNode.searchXML)
	currentFastForwardNode.addItem(newNode);

	WidgetFastForward.processFastForwardNodes(panelName, xmlDoc, newNode, true);
}

WidgetFastForward.prototype.addFastForwardItem = function (panelName, itemTitle, panelObject, currentFastForwardNode) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	var newElement = document.createElement("div");
	newElement.className = 'kajaxfastforwarditemdiv';
	newElement.onmouseover = function () {
		this.className = 'kajaxfastforwarditemhover';
	}

	newElement.onmouseout = function () {
		this.className = 'kajaxfastforwarditemdiv';
	}

	newElement.id = "ffi_"+panelName+"_"+currentFastForwardNode.nodePointer;
	window.$KAJAX._parser.fastForwardNodePointer[newElement.id] = currentFastForwardNode;

	var baseURL = window.$KAJAX._parser.fastForwardProperties[panelName]["baseurl"];

	if (currentFastForwardNode.nodeLink)
	{
		newElement.onclick = function () { this.blur(); window.location.href = currentFastForwardNode.nodeLink; }
		newElement.innerHTML = "<span style='float:left'>"+itemTitle+"</span> ";
	} else if (currentFastForwardNode.xmlURL) {
		newElement.innerHTML = "<span style='float:left'>"+itemTitle+"</span><span style='float:right;'><img align='absmiddle' src='"+ imagePath+"fastforwardarrow.gif" +"' /></span> ";
		var loadXMLURL = baseURL+currentFastForwardNode.xmlURL;

		if (currentFastForwardNode.n.length)
		{
			newElement.onclick = function ()
			{
				WidgetFastForward.renderFastForwardPanel(panelName, currentFastForwardNode, false);
			}
		} else {
			newElement.onclick = function ()
			{
				this.blur();
				AjaxRequest.get(
					{
						'url':loadXMLURL,
						'onSuccess':function(req) { WidgetFastForward.processFastForwardNodes(panelName, req.responseXML, currentFastForwardNode, false); }
					}
				);
			}
		}
	}

	panelObject.appendChild(newElement);

	return newElement;
}

WidgetFastForward.prototype.moveFastForwardObject = function (panelName, isBack) {
//		var logObject = window.$KAJAX._interface.getObject("log");
//		logObject.innerHTML += "exec<br>";
	var panelObject = window.$KAJAX._interface.getObject("fastforwards_"+panelName);
	if (!panelObject)
	{
		clearInterval(window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"]);
		return false;
	}

	var oldPanelObject = window.$KAJAX._interface.getObject("fastforward_old_"+panelName);
	if (!oldPanelObject)
	{
		clearInterval(window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"]);
		return false;
	}

	var newPanelObject = window.$KAJAX._interface.getObject("fastforward_new_"+panelName);
	if (!newPanelObject)
	{
		clearInterval(window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"]);
		return false;
	}

	var panelProperties = window.$KAJAX._parser.fastForwardProperties[panelName];
	var oldPanelLeftStr = new String(oldPanelObject.style.left);
	var newPanelLeftStr = new String(newPanelObject.style.left);
	oldPanelLeftStr.replace("px", "");
	newPanelLeftStr.replace("px", "");
	var oldPanelLeft = parseInt(oldPanelLeftStr);
	var newPanelLeft = parseInt(newPanelLeftStr);
	var panelWidth = window.$KAJAX._parser.fastForwardProperties[panelName]["panelwidth"];
	var aniMultiplier = window.$KAJAX._parser.fastForwardProperties[panelName]["animultiplier"]*window.$KAJAX._parser.fastForwardProperties[panelName]["anicount"];
	// Left to Right Animation
	if (isBack)
	{
		var oldPanelLeftNew = oldPanelLeft+5+aniMultiplier;
		var newPanelLeftNew = newPanelLeft+5+aniMultiplier;

		if (oldPanelLeftNew >= panelWidth && window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"])
		{
			oldPanelObject.style.left = panelWidth+"px";
			newPanelObject.style.left = "0px";
			panelObject.removeChild(oldPanelObject);
			clearInterval(window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"]);

			var textObject = window.$KAJAX._interface.getObject("fastforward_newsearch_"+panelName);
			if (textObject)
			{
				textObject.focus();
			}
	panelObject.style.width=panelProperties["width"]+"px";
	panelObject.style.height=(panelProperties["height"]-26)+'px';
	panelObject.style.overflow = 'auto';
	newPanelObject.style.width = '100%';

		} else {
			oldPanelObject.style.left = oldPanelLeftNew+"px";
			newPanelObject.style.left = newPanelLeftNew+"px";
		}
	// Right to Left Animation
	} else {
		var oldPanelLeftNew = oldPanelLeft-5-aniMultiplier;
		var newPanelLeftNew = newPanelLeft-5-aniMultiplier;
//		var logObject = window.$KAJAX._interface.getObject("log");
//		logObject.innerHTML = logObject.innerHTML+oldPanelLeftNew+" - "+newPanelLeftNew+" = " + aniMultiplier +"<br>";

		if (oldPanelLeftNew <= (0-panelWidth) && window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"])
		{
			oldPanelObject.style.left = (0-panelWidth)+"px";
			newPanelObject.style.left = "0px";
			panelObject.removeChild(oldPanelObject);
			clearInterval(window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"]);

			var textObject = window.$KAJAX._interface.getObject("fastforward_newsearch_"+panelName);
			if (textObject)
			{
				textObject.focus();
			}
	panelObject.style.width=panelProperties["width"]+"px";
	panelObject.style.height=(panelProperties["height"]-26)+'px';
	panelObject.style.overflow = 'auto';
	newPanelObject.style.width = '100%';

		} else {
			oldPanelObject.style.left = oldPanelLeftNew+"px";
			newPanelObject.style.left = newPanelLeftNew+"px";
		}
	}

	window.$KAJAX._parser.fastForwardProperties[panelName]["anicount"]++;
}

WidgetFastForward.prototype.loadFastForwardObject = function (panelName) {
	var panelObject = window.$KAJAX._interface.getObject("fastforwards_"+panelName);
	if (!panelObject)
	{
		return false;
	}

	var oldPanelObject = window.$KAJAX._interface.getObject("fastforward_old_"+panelName);
	if (!oldPanelObject)
	{
		return false;
	}

	var newPanelObject = window.$KAJAX._interface.getObject("fastforward_new_"+panelName);
	if (!newPanelObject)
	{
		return false;
	}

	var panelWidth = window.$KAJAX._parser.fastForwardProperties[panelName]["panelwidth"];

	oldPanelObject.style.left = panelWidth+"px";
	newPanelObject.style.left = "0px";
	panelObject.removeChild(oldPanelObject);
	clearInterval(window.$KAJAX._parser.fastForwardProperties[panelName]["intervalid"]);

	var textObject = window.$KAJAX._interface.getObject("fastforward_newsearch_"+panelName);
	if (textObject)
	{
		textObject.focus();
	}
}




/**
* FastForward Node Class
*/
function FastForwardNode(panelName, nodeTitle, nodeLink, nodeTarget, xmlURL, searchXML)
{
	this.n = new Array();
	this.panelName = panelName;
	this.xmlURL = xmlURL;
	this.searchXML = searchXML;
	this.nodeTitle = nodeTitle;
	this.nodeLink = nodeLink;
	this.nodeTarget = nodeTarget;
}

FastForwardNode.prototype.addItem = function (newItem) {
	var nodeIndex = this.n.length;
	this.n[nodeIndex] = newItem;

	this.n[nodeIndex].nodePointer = this.nodePointer + '_'+nodeIndex;

	this.n[nodeIndex].parentNode = this;

	return this.n[nodeIndex];
}













/**
* ###############################################
* END FASTFORWARD FUNCTIONS
* ###############################################
*/



















/**
* ###############################################
* BEGIN TREE CONTROL FUNCTIONS
* ###############################################
*/


/**
* Renders a tree control from a given parentElement
*/
KAJAX_parser.prototype.render_tree = function (parentElement, replaceCustom) {
	var bodyElement = document.getElementsByTagName("body");
	var newParentDiv = document.createElement("div");

	var attribImagePath = parentElement.getAttribute("imagepath");
	var attribTreeName = parentElement.getAttribute("name");
	var attribOnRender = parentElement.getAttribute("onrender");
	var attribOnRenderHide = parentElement.getAttribute("onrenderhide");
	var attribCssClass = parentElement.getAttribute("class");
	newParentDiv.id = 'tree_'+attribTreeName;
	if (attribImagePath)
	{
		window.$KAJAX._parser.treePreloadImages(attribImagePath);
	}

	if (!attribTreeName || !attribImagePath)
	{
		return false;
	}

	window.$KAJAX._parser.treeProperties[attribTreeName] = new Array();
	window.$KAJAX._parser.treeProperties[attribTreeName]["imagepath"] = attribImagePath;
	window.$KAJAX._parser.treeProperties[attribTreeName]["onrender"] = attribOnRender;
	window.$KAJAX._parser.treeProperties[attribTreeName]["cssclass"] = attribCssClass;
	window.$KAJAX._parser.treeParentNodes[attribTreeName] = new TreeNode("", "", "", "", true, false, attribCssClass, "", "", "");

	newParentDiv.className = attribCssClass;
	window.$KAJAX._parser.processTreeNodes(attribTreeName, parentElement, window.$KAJAX._parser.treeNodes, newParentDiv, 0, '', '', window.$KAJAX._parser.treeParentNodes[attribTreeName]);

	if (replaceCustom)
	{
		var replaceElement = window.$KAJAX._interface.getObject(replaceCustom);
		if (!replaceElement)
		{
			return false;
		}

		replaceElement.innerHTML = newParentDiv.innerHTML;
	} else {
		parentElement.parentNode.replaceChild(newParentDiv, parentElement);
	}

	if (attribOnRender)
	{
		var renderObject = window.$KAJAX._interface.getObject(attribOnRender);
		if (renderObject)
		{
			renderObject.style.display = 'block';
		}
	}

	if (attribOnRenderHide)
	{
		var renderObjectHide = window.$KAJAX._interface.getObject(attribOnRenderHide);
		if (renderObjectHide)
		{
			renderObjectHide.style.display = 'none';
		}
	}
}


/**
* Preload images hack for Mozilla
*/
KAJAX_parser.prototype.treePreloadImages = function (imagePath)
{
	var plustop = new Image;
	plustop.src = this.iconpath + 'plustop.gif';
	var plusbottom = new Image;
	plusbottom.src = this.iconpath + 'plusbottom.gif';
	var plus = new Image;
	plus.src = this.iconpath + 'plus.gif';
	
	var minustop = new Image;
	minustop.src = this.iconpath + 'minustop.gif';
	var minusbottom = new Image;
	minusbottom.src = this.iconpath + 'minusbottom.gif';
	var minus = new Image;
	minus.src = this.iconpath + 'minus.gif';

	var branchtop = new Image;
	branchtop.src = this.iconpath + 'branchtop.gif';
	var branchbottom = new Image;
	branchbottom.src = this.iconpath + 'branchbottom.gif';
	var branch = new Image;
	branch.src = this.iconpath + 'branch.gif';

	var linebottom = new Image;
	linebottom.src = this.iconpath + 'linebottom.gif';
	var line = new Image;
	line.src = this.iconpath + 'line.gif';
}

/**
* Processes the node items
*/
KAJAX_parser.prototype.processTreeNodes = function (treeName, parentElement, currentNode, newParentDiv, branchLevel, prependImage, strBranchTree, parentTreeNode) {
	var nodeCount = 0;
	var totalNodeCount = 0;
	for (var iiNode = 0; iiNode < parentElement.childNodes.length; iiNode++) {
		var childtestnode = parentElement.childNodes.item(iiNode);
		if (childtestnode.nodeType != 1)
		{
			continue;
		}
		totalNodeCount++;
	}

	for (var iNode = 0; iNode < parentElement.childNodes.length; iNode++) {
		var node = parentElement.childNodes.item(iNode);

		if (node.nodeType != 1)
		{
			continue;
		}
		var attribNodeTitle = node.getAttribute("title");
		var attribHasChilds = false;
		var attribLinkTarget = node.getAttribute("target");
		var attribCssClass = node.getAttribute("class");
		var attribOnCollapse = node.getAttribute("oncollapse");
		var attribOnExpand = node.getAttribute("onexpand");
		var attribOnToggle = node.getAttribute("ontoggle");
		var attribLink = node.getAttribute("link");
		var attribLinkXML = node.getAttribute("linkxml");
		var attribIcon = node.getAttribute("icon");
		var attribExpandedIcon = node.getAttribute("expandedicon");

		if (strBranchTree != "")
		{
			var strCurrentNodeName = strBranchTree+'_'+nodeCount;
		} else {
			var strCurrentNodeName = nodeCount;
		}

		var nodeAttributeExpanded = node.getAttribute("expanded");
		if (!nodeAttributeExpanded)
		{
			var attribExpanded = true;
		} else if (nodeAttributeExpanded == "true") {
			var attribExpanded = true;
		} else {
			var attribExpanded = false;
		}


		if (attribNodeTitle)
		{
			attribHasChilds = true;
		} else {
			attribNodeTitle = node.firstChild.nodeValue;
		}

		// Parent Nodes are always expanded
		if (!node.getAttribute("expanded") && branchLevel == 0)
		{
			attribExpanded = true;
		}


		var treeNodeLength = currentNode.length;
		currentNode[treeNodeLength] = new TreeNode(attribNodeTitle, attribIcon, attribLink, attribLinkXML, attribExpanded, false, attribCssClass, attribLinkTarget, attribExpandedIcon, strCurrentNodeName);

		window.$KAJAX._parser.treeNodePointer['node_'+strCurrentNodeName] = currentNode[treeNodeLength];
		parentTreeNode.n[parentTreeNode.n.length] = currentNode[treeNodeLength];

		var parentExpanded = true;
		if (parentTreeNode.expanded == false)
		{
			parentExpanded = false;
			currentNode[treeNodeLength].expanded = false;
			attribExpanded = false;
		}
		currentNode[treeNodeLength].nodeTitle = attribNodeTitle;

		var nodeDivElement = document.createElement("div");

		nodeDivElement.id = 'node_'+strCurrentNodeName;

		if (parentExpanded == false)
		{
			nodeDivElement.style.display = "none";
		} else {
			nodeDivElement.style.display = "block";
		}

		if (attribCssClass)
		{
			nodeDivElement.className = attribCssClass;
		}

		var gifModifier = '';
		if (nodeCount == 0 && branchLevel == 0)
		{
			gifModifier = "top";
		} else if ((nodeCount+1) == totalNodeCount) {
			gifModifier = "bottom";
		}

		var gifName = '';
		if (attribHasChilds && attribExpanded == true)
		{
			gifName = 'minus';
		} else if (attribHasChilds && attribExpanded == false || attribLinkXML) {
			gifName = 'plus';
		} else {
			gifName = 'branch';
		}
		
		if (attribExpanded == true)
		{
			currentNode[treeNodeLength].replaceNodeImage = window.$KAJAX._parser.treeProperties[treeName]["imagepath"]+'minus'+gifModifier+'.gif';;
		} else if (attribExpanded == false) {
			currentNode[treeNodeLength].replaceNodeImage = window.$KAJAX._parser.treeProperties[treeName]["imagepath"]+'plus'+gifModifier+'.gif';;
		}

		if (attribLinkXML)
		{
			attribLink = 'javascript:window.$KAJAX._parser.treeLoadXML(\''+ treeName +'\', \''+ strCurrentNodeName +'\', \''+ attribLinkXML +'\');';
		}

		var branchOnClick = '';
		if (attribHasChilds && attribExpanded == false)
		{
			branchOnClick = ' onClick="javascript:window.$KAJAX._parser.treeNodeSwitcher(\''+ treeName +'\', \''+ strCurrentNodeName +'\', \'expand\');" style="cursor: hand; cursor: pointer;"';
		} else if (attribHasChilds && attribExpanded == true) {
			branchOnClick = ' onClick="javascript:window.$KAJAX._parser.treeNodeSwitcher(\''+ treeName +'\', \''+ strCurrentNodeName +'\', \'contract\');" style="cursor: hand; cursor: pointer;"';
		} else if (attribLinkXML) {
			branchOnClick = ' onClick="'+ attribLink +'" style="cursor: hand; cursor: pointer;"';
		}
		

		var branchImage = '<img src="'+ window.$KAJAX._parser.treeProperties[treeName]["imagepath"]+gifName+gifModifier +'.gif" align="absmiddle" id="tbimg_'+ strCurrentNodeName +'"'+ branchOnClick +'>';

		var iconImage = '';
		if (attribIcon)
		{
			var iconImage = '<img src="'+ window.$KAJAX._parser.treeProperties[treeName]["imagepath"]+attribIcon+'" align="absmiddle" id="timg_'+ strCurrentNodeName +'">';
		}

		var expandedIconImage = '';
		if (attribExpandedIcon)
		{
			var expandedIconImage = '<img src="'+ window.$KAJAX._parser.treeProperties[treeName]["imagepath"]+attribExpandedIcon+'" align="absmiddle" id="timg_'+ strCurrentNodeName +'">';
		}

		if (attribExpanded && expandedIconImage)
		{
			iconImage = expandedIconImage;
		}

		var prependData = '';
		if (prependImage)
		{
			prependData = prependImage;
		}

		var finalNodeTitle = attribNodeTitle;

		if (attribLink && !attribLinkTarget)
		{
			finalNodeTitle = '<a class="tree" href="'+ attribLink +'">'+ attribNodeTitle +'</a>';
		} else if (attribLink && attribLinkTarget) {
			finalNodeTitle = '<a class="tree" href="'+ attribLink +'" target="'+ attribLinkTarget +'">'+ attribNodeTitle +'</a>';
		} else {
//			finalNodeTitle = '<span class="smalltext">'+ finalNodeTitle +'</span>';
		}

		nodeDivElement.innerHTML = '<nobr>'+prependData+branchImage+iconImage+finalNodeTitle+'</nobr>';

		nodeDivElement.style.display = 'block';

		newParentDiv.appendChild(nodeDivElement);
		var newPrependImage = '<img src="'+ window.$KAJAX._parser.treeProperties[treeName]["imagepath"]+'line.gif" align="top">';

		currentNode[treeNodeLength].prependImage = prependData+newPrependImage;
		currentNode[treeNodeLength].branchLevel = (branchLevel+1);

		if (attribHasChilds)
		{
			// Has Child Elements
			var childNodeCount = window.$KAJAX._parser.processTreeNodes(treeName, node, currentNode, newParentDiv, (branchLevel+1), prependData+newPrependImage, strCurrentNodeName, currentNode[treeNodeLength]);
//			nodeCount += childNodeCount;
		}

		nodeCount++;
	}

	return nodeCount;
}

/**
* Loads the tree data using AJAX
*/
KAJAX_parser.prototype.treeLoadXML = function (treeName, nodeName, linkURL)
{
	AjaxRequest.get(
		{
			'url': linkURL,
			'onSuccess':function(req) { window.$KAJAX._parser.treeProcessLoadedXML(treeName, nodeName, linkURL, req); }
		}
	);
}

KAJAX_parser.prototype.treeProcessLoadedXML = function (treeName, nodeName, linkURL, responseAJAX)
{
	var currentTag = 'ui:tree';
	if (window.$KAJAX._browserDetect.moz)
	{
		currentTag = 'tree';
	}

	var xmlDoc = responseAJAX.responseXML;
	var itemRoot = xmlDoc.getElementsByTagName(currentTag).item(0);
	var newParentDiv = document.createElement("div");

	// Get the current node
	var currentNode = window.$KAJAX._parser.treeNodePointer["node_"+nodeName];
	if (!currentNode)
	{
		return false;
	}

	var currentNodeObject = window.$KAJAX._interface.getObject("node_"+nodeName);
	if (!currentNodeObject)
	{
		return false;
	}

	var currentNodeImgObject = window.$KAJAX._interface.getObject("tbimg_"+nodeName);
	if (currentNodeImgObject)
	{
		currentNodeImgObject.src = currentNode.replaceNodeImage;
		currentNodeImgObject.style.cursor = 'hand';
		currentNodeImgObject.style.cursor = 'pointer';

		if (currentNode.expanded)
		{
			currentNodeImgObject.onclick = function () { javascript:window.$KAJAX._parser.treeNodeSwitcher(treeName, nodeName, 'expand'); }
		} else {
			currentNodeImgObject.onclick = function () { javascript:window.$KAJAX._parser.treeNodeSwitcher(treeName, nodeName, 'contract'); }
		}
	}

	var currentNodeParentDiv = window.$KAJAX._interface.getObject("tree_"+treeName);
	if (!currentNodeParentDiv)
	{
		return false;
	}

	var childNodeCount = window.$KAJAX._parser.processTreeNodes(treeName, itemRoot, window.$KAJAX._parser.treeNodes, newParentDiv, currentNode.branchLevel, currentNode.prependImage, nodeName, currentNode);

	for (var iNode = newParentDiv.childNodes.length-1; iNode >= 0; iNode--) {
		var node = newParentDiv.childNodes.item(iNode);
		currentNodeParentDiv.insertBefore(node, currentNodeObject.nextSibling);
	}
}

/**
* New C# style string formatter
*/
	KAJAX_parser.prototype.stringFormat = function (strInput)
	{
		var idx = 0;
	
		for (var i=1; i<arguments.length; i++) {
			while ((idx = strInput.indexOf('{' + (i - 1) + '}', idx)) != -1) {
				strInput = strInput.substring(0, idx) + arguments[i] + strInput.substr(idx + 3);
			}
		}
		
		return strInput;
	}

/**
* Swaps the plus/minus branch images
*/
KAJAX_parser.prototype.treeSwapImage = function (nodeName)
{
	var imgSrc = document.images['tbimg_' + nodeName].src;

	var re = /^(.*)(plus|minus)(bottom|top|single)?.gif$/
	if (matches = imgSrc.match(re)) {
			document.images['tbimg_' + nodeName].src = window.$KAJAX._parser.stringFormat('{0}{1}{2}{3}', matches[1], matches[2] == 'plus' ? 'minus' : 'plus', matches[3] ? matches[3] : '','.gif');
	}
}

/**
* Expands the current node
*/
KAJAX_parser.prototype.treeNodeSwitcher = function (treeName, nodeName) {
	var currentNode = window.$KAJAX._parser.treeNodePointer["node_"+nodeName];
	if (!currentNode)
	{
		return false;
	}

	var currentNodeObject = window.$KAJAX._interface.getObject("node_"+nodeName);
	if (!currentNodeObject)
	{
		return false;
	}

	var currentNodeImgObject = window.$KAJAX._interface.getObject("timg_"+nodeName);

	window.$KAJAX._parser.treeSwapImage(nodeName);

	if (!currentNode.n.length)
	{
		return false;
	}

	var actionType = '';
	if (currentNode.expanded)
	{
		currentNode.expanded = false;
		actionType = 'contract';

		if (currentNodeImgObject)
		{
			currentNodeImgObject.src = window.$KAJAX._parser.treeProperties[treeName]["imagepath"]+currentNode.icon;
		}
	} else {
		currentNode.expanded = true;
		actionType = 'expand';

		if (currentNodeImgObject && currentNode.expandedIcon)
		{
			currentNodeImgObject.src = window.$KAJAX._parser.treeProperties[treeName]["imagepath"]+currentNode.expandedIcon;
		}
	}


	for (var ii=0; ii<currentNode.n.length; ii++)
	{
		var currentChildNode = currentNode.n[ii];
		var currentChildObject = window.$KAJAX._interface.getObject("node_"+currentChildNode.nodeID);
		if (!currentChildObject)
		{
			continue;
		}


		if (actionType == 'expand')
		{
			currentChildObject.style.display = 'block';
			if (currentChildNode.n.length)
			{
				window.$KAJAX._parser.treeRestoreNodeDisplayChilds(treeName, currentChildNode.nodeID);
			}
		} else if (actionType == 'contract') {
			currentChildObject.style.display = 'none';
			if (currentChildNode.n.length)
			{
				window.$KAJAX._parser.treeHideNodeDisplayChilds(treeName, currentChildNode.nodeID);
			}
		}

	}
}

KAJAX_parser.prototype.treeRestoreNodeDisplayChilds = function (treeName, nodeName, nodeVisible) {
	if (nodeVisible == null || nodeVisible == 'undefined')
	{
		nodeVisible = true;
	}
	var currentNode = window.$KAJAX._parser.treeNodePointer["node_"+nodeName];
	if (!currentNode)
	{
		return false;
	}

	var currentNodeObject = window.$KAJAX._interface.getObject("node_"+nodeName);
	if (!currentNodeObject)
	{
		return false;
	}

	if (!currentNode.n.length)
	{
		return false;
	}

	for (var ii=0; ii<currentNode.n.length; ii++)
	{
		var currentChildNode = currentNode.n[ii];
		var currentChildObject = window.$KAJAX._interface.getObject("node_"+currentChildNode.nodeID);
		if (!currentChildObject)
		{
			continue;
		}

		if (currentChildNode.nodeTitle == "DItem #3.2.1" || currentChildNode.nodeTitle == "AJAXItem #3.2")
		{
//			alert(nodeVisible);
		}

		if (currentChildNode.n.length)
		{
			if (currentNode.expanded && nodeVisible)
			{
				currentChildObject.style.display = 'block';
			} else {
				nodeVisible = false;
				currentChildObject.style.display = 'none';
			}
		} else {
			if (currentNode.expanded && nodeVisible)
			{
				currentChildObject.style.display = 'block';
			} else {
				currentChildObject.style.display = 'none';
			}
		}

//		currentChildObject.innerHTML = currentChildObject.innerHTML+nodeVisible;

		if (currentChildNode.n.length)
		{
			window.$KAJAX._parser.treeRestoreNodeDisplayChilds(treeName, currentChildNode.nodeID, nodeVisible);
		}
	}
}

KAJAX_parser.prototype.treeHideNodeDisplayChilds = function (treeName, nodeName) {

	var currentNode = window.$KAJAX._parser.treeNodePointer["node_"+nodeName];
	if (!currentNode)
	{
		return false;
	}

	var currentNodeObject = window.$KAJAX._interface.getObject("node_"+nodeName);
	if (!currentNodeObject)
	{
		return false;
	}

	if (!currentNode.n.length)
	{
		return false;
	}

	for (var ii=0; ii<currentNode.n.length; ii++)
	{
		var currentChildNode = currentNode.n[ii];
		var currentChildObject = window.$KAJAX._interface.getObject("node_"+currentChildNode.nodeID);
		if (!currentChildObject)
		{
			continue;
		}

		currentChildObject.style.display = 'none';

		if (currentChildNode.n.length)
		{
			window.$KAJAX._parser.treeHideNodeDisplayChilds(treeName, currentChildNode.nodeID);
		}
	}
}

/**
* TreeNode Class
*/
function TreeNode(title, icon, link, linkxml, expanded, isDynamic, cssClass, linkTarget, expandedIcon, strCurrentNodeName)
{
	this.title = title;
	this.icon = icon;
	this.expandedIcon = expandedIcon;
	this.link = link;
	this.linkxml = linkxml;
	this.expanded = expanded;
	this.isDynamic = isDynamic;
	this.cssClass = cssClass;
	this.linkTarget = linkTarget;
	this.n = new Array();
	this.events = new Array();
	this.handlers = null;
	this.oncollapse = null;
	this.onexpand = null;
	this.ontoggle = null;
	this.prependImage = '';
	this.branchLevel = 0;
	this.nodeID = strCurrentNodeName;
}

/**
* Adds a node to an already existing node
*/
TreeNode.prototype.addItem = function (newNode)
{
	newIndex = this.n.length;
	this.n[newIndex] = newNode;

	return this.n[newIndex];
}

/**
* Sets an event for this particular node
*/
TreeNode.prototype.setEvent = function (eventName, eventHandler)
{
	switch (eventName.toLowerCase()) {
		case 'onexpand':
			this.onexpand = eventHandler;
			break;

		case 'oncollapse':
			this.oncollapse = eventHandler;
			break;

		case 'ontoggle':
			this.ontoggle = eventHandler;
			break;

		default:
			this.events[eventName] = eventHandler;
	}
}


/**
* ###############################################
* END TREE CONTROL FUNCTIONS
* ###############################################
*/














/**
* ###############################################
* BEGIN WINDOW CONTROL FUNCTIONS
* ###############################################
*/

/**
* Renders a window control
*/
KAJAX_parser.prototype.render_window = function (parentElement) {
	var windowName = parentElement.getAttribute("windowname");
	if (!windowName || windowName == "")
	{
		return false;
	}
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	// Render Window Area
	var windowElement = document.createElement("div");
	windowElement.className = 'kajaxwindow';
	windowElement.id = windowName+"_win";
	var windowTitle = parentElement.getAttribute("title");
	var attribIsModal = parentElement.getAttribute("modal");
	var attribIsVisible = parentElement.getAttribute("visible");
	var clientHeight = parentElement.getAttribute("height");
	if (!clientHeight)
	{
		clientHeight = "400"; // Default Height
	}

	var clientWidth = parentElement.getAttribute("width");
	if (!clientWidth)
	{
		clientWidth = "400"; // Default Height
	}
	var centerWidth = window.$KAJAX._browserDetect.innerWidth/2;
	centerWidth = centerWidth-(clientWidth/2);

	var centerHeight = ((window.$KAJAX._browserDetect.innerHeight/2)-((clientHeight/2)+100));

	var clientLeft = parentElement.getAttribute("left");
	var clientTop = parentElement.getAttribute("top");
	if (!clientLeft)
	{
		clientLeft = centerWidth;
	}

	if (!clientTop)
	{
		clientTop = centerHeight;
	}

	clientLeft = Math.ceil(clientLeft);
	clientTop = Math.ceil(clientTop);

	var isModal = false;
	var isVisible = true;
	if ((attribIsModal && attribIsModal == "true") || (attribIsModal && attribIsModal == "1"))
	{
		isModal = true;
	}

	if ((attribIsVisible && attribIsVisible == "true") || (attribIsVisible && attribIsVisible == "1"))
	{
		isVisible = true;
	}

	var windowNodeLength = window.$KAJAX._parser.windowNodes.length;
	window.$KAJAX._parser.windowNodes[windowNodeLength] = new WindowNode(windowName, windowTitle, isVisible, isModal, clientLeft, clientTop, clientWidth, clientHeight);
	window.$KAJAX._parser.windowNodePointer[windowName] = window.$KAJAX._parser.windowNodes[windowNodeLength];
	var currentWindowNode = window.$KAJAX._parser.windowNodes[windowNodeLength];

	// Render Client Area
	var clientArea = document.createElement("div");
	clientArea.className = 'kajaxclientarea';

	windowElement.style.width = clientWidth+"px";
	clientArea.style.height = clientHeight+"px";

	windowElement.style.left = clientLeft+"px";
	windowElement.style.top = clientTop+"px";

	// Render Title Bar
	var titlebarElement = document.createElement("div");
	titlebarElement.className = 'kjxwindowtitleright';
	titlebarElement.id = windowName+"_tbar";

	currentWindowNode.windowElement = windowElement;
	currentWindowNode.titlebarElement = titlebarElement;

	var titlebarTextElement = document.createElement("div");
	titlebarTextElement.className = 'kjxwindowtitleleft';
	titlebarTextElement.id = windowName+"_tbartxt";
	if (windowTitle)
	{
		var titleSubElement = document.createElement("div");
		titleSubElement.className = 'kjxwindowtitlemain';
		titleSubElement.innerHTML = windowTitle;
		var titleCloseElement = document.createElement("div");
		titleCloseElement.className = 'kjxwindowtitleclose';

		titlebarTextElement.appendChild(titleSubElement);
		titlebarTextElement.appendChild(titleCloseElement);
		titlebarElement.appendChild(titlebarTextElement);
		windowElement.appendChild(titlebarElement);
		currentWindowNode.titlebarElement = titleSubElement;
	}

	clientArea.innerHTML = parentElement.innerHTML;

	windowElement.appendChild(clientArea);

	// Window Events
//	windowElement.onmouseover = function (event) { window.$KAJAX._parser.windowResizeCursorSet(event, windowName) }
//	windowElement.onmousemove = function (event) { window.$KAJAX._parser.windowResizeCursorSet(event, windowName) }
//	windowElement.onmouseout = function (event) { window.$KAJAX._parser.windowResizeCursorRestore(event, windowName) }
//	windowElement.onmousedown = function (event) { window.$KAJAX._parser.windowResizeCursorDragStart(event, windowName) }

	// Title Bar Events
	titleSubElement.onmousedown = function (event) { window.$KAJAX._parser.windowMoveDragStart(event, windowName) }
	titleSubElement.onmouseup = function (event) { window.$KAJAX._parser.windowMoveDragStop(event, windowName) }

	// Client Area Events
	clientArea.onclick = function (event) { window.$KAJAX._parser.windowClientAreaClick(event, windowName) }


	if (isModal)
	{
		var modalBackground = document.createElement("div");
		modalBackground.style.top = 0;
		modalBackground.style.left = 0;
		modalBackground.style.width = window.$KAJAX._browserDetect.screenWidth+'px';
		modalBackground.style.height = window.$KAJAX._browserDetect.screenHeight+'px';
		modalBackground.style.backgroundImage = "url("+ imagePath+"checkbg.gif" +")";
		modalBackground.className = 'kajaxmodalbg';

		modalBackground.appendChild(windowElement);

		if (!isVisible)
		{
			modalBackground.style.display = "none";
		} else {
			modalBackground.style.display = "";
			bodyElement[0].style.overflow = 'hidden';
			bodyElement[0].className = 'kjxnooverflow';

			if (window.$KAJAX._browserDetect.ie)
			{
				var root = document.all[1]; // IE >= 4
				root.style.overflow = 'hidden';
			}
		}

		parentElement.parentNode.replaceChild(modalBackground, parentElement);
	} else {
		if (!isVisible)
		{
			windowElement.style.display = "none";
		}

		parentElement.parentNode.replaceChild(windowElement, parentElement);
	}
}

/**
* Displays an existing window
*/
KAJAX_parser.prototype.showWindow = function (windowName) {
}

/**
* Hides an existing window
*/
KAJAX_parser.prototype.hideWindow = function (windowName) {
}

/**
* Destroys the window
*/
KAJAX_parser.prototype.destroyWindow = function (windowName) {
}

/**
* Minimize an existing window
*/
KAJAX_parser.prototype.minimizeWindow = function (windowName) {
}

/**
* Restore a window
*/
KAJAX_parser.prototype.restoreWindow = function (windowName) {
}

/**
* Makes an existing window active
*/
KAJAX_parser.prototype.makeActiveWindow = function (windowName) {
	var activeWindowNode = window.$KAJAX._parser.windowNodePointer[windowName];
	if (!activeWindowNode)
	{
		return false;
	}
//	activeWindowNode.titlebarElement.className = 'kajaxtitlebar';
	activeWindowNode.windowElement.style.zIndex = ++window.$KAJAX._parser.windowZIndex;

	for (var ii=0; ii<window.$KAJAX._parser.windowNodes.length; ii++)
	{
		var currentNode = window.$KAJAX._parser.windowNodes[ii];

		if (currentNode.name != activeWindowNode.name)
		{
//			currentNode.titlebarElement.className = 'kajaxtitlebarinactive';
		}
	}

}

/**
* EVENT: Clicked on Client Area, Make the window active
*/
KAJAX_parser.prototype.windowClientAreaClick = function (event, windowName) {
	window.$KAJAX._parser.makeActiveWindow(windowName);
}

/**
* EVENT: Drag Start
*/
KAJAX_parser.prototype.windowMoveDragStart = function (event, windowName) {
	var target;
	var currentWindowNode = window.$KAJAX._parser.windowNodePointer[windowName];
	if (!currentWindowNode)
	{
		return false;
	}

	// Make sure the event is on the window frame.

	if (window.$KAJAX._browserDetect.ie) {
		target = window.event.srcElement;
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		target = event.target;
	}

	if (target != currentWindowNode.titlebarElement && target.parentNode != currentWindowNode.titlebarElement) {
		return;
	}

	window.$KAJAX._parser.makeActiveWindow(windowName);

	if (window.$KAJAX._browserDetect.ie) {
		x = window.event.x;
		y = window.event.y;
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		x = event.pageX;
		y = event.pageY;
	}

	currentWindowNode.xOffset = currentWindowNode.windowElement.offsetLeft - x;
	currentWindowNode.yOffset = currentWindowNode.windowElement.offsetTop - y;

	// Set document to capture mousemove and mouseup events.

	if (window.$KAJAX._browserDetect.ie) {
		document.onmousemove = function (e) { window.$KAJAX._parser.windowMoveDragGo(e, windowName) };
		document.onmouseup = function (e) { window.$KAJAX._parser.windowMoveDragStop(e, windowName) };
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		document.addEventListener("mousemove", function (e) { window.$KAJAX._parser.windowMoveDragGo(e, windowName) }, true);
		document.addEventListener("mouseup", function (e) { window.$KAJAX._parser.windowMoveDragStop(e, windowName) }, true);
		event.preventDefault();
	}

	currentWindowNode.inMoveDrag = true;
}

/**
* EVENT: Drag Stop
*/
KAJAX_parser.prototype.windowMoveDragStop = function (event, windowName) {
	var currentWindowNode = window.$KAJAX._parser.windowNodePointer[windowName];
	if (!currentWindowNode)
	{
		return false;
	}

	currentWindowNode.inMoveDrag = false;

	// Remove mousemove and mouseup event captures on document.
	if (window.$KAJAX._browserDetect.ie) {
		document.onmousemove = null;
		document.onmouseup   = null;
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		document.removeEventListener("mousemove", function (e) { window.$KAJAX._parser.windowMoveDragGo(e, windowName) }, true);
		document.removeEventListener("mouseup", function (e) { window.$KAJAX._parser.windowMoveDragStop(e, windowName) }, true);
	}
}

/**
* EVENT: Drag Go
*/
KAJAX_parser.prototype.windowMoveDragGo = function (event, windowName) {
	var x, y;

	var currentWindowNode = window.$KAJAX._parser.windowNodePointer[windowName];
	if (!currentWindowNode || !currentWindowNode.inMoveDrag)
	{
		return false;
	}

	// Get cursor position.
	if (window.$KAJAX._browserDetect.ie) {
		x = window.event.x;
		y = window.event.y;
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		x = event.pageX;
		y = event.pageY;
		event.preventDefault();
	}

	// Move window frame based on offset from cursor.
	currentWindowNode.windowElement.style.left = (x + currentWindowNode.xOffset) + "px";
	currentWindowNode.windowElement.style.top  = (y + currentWindowNode.yOffset) + "px";
}

/**
* EVENT: Cursor Set
*/
KAJAX_parser.prototype.windowResizeCursorSet = function (event, windowName) {
	var currentWindowNode = window.$KAJAX._parser.windowNodePointer[windowName];
	if (!currentWindowNode || currentWindowNode.inResizeDrag)
	{
		return false;
	}

	var target;
	var xOff, yOff;

  // If not on window frame, restore cursor and exit.

	if (window.$KAJAX._browserDetect.ie) {
		target = window.event.srcElement;
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		target = event.target;
	}

	if (target != currentWindowNode.windowElement) {
		return;
	}

	// Find resize direction.
	if (window.$KAJAX._browserDetect.ie) {
		xOff = window.event.offsetX;
		yOff = window.event.offsetY;
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		xOff = event.layerX;
		yOff = event.layerY;
	}

	currentWindowNode.resizeDirection = ""
	if (yOff <= currentWindowNode.resizeCornerSize) {
		currentWindowNode.resizeDirection += "n";
	} else if (yOff >= currentWindowNode.windowElement.offsetHeight - currentWindowNode.resizeCornerSize) {
		currentWindowNode.resizeDirection += "s";
	}
	
	if (xOff <= currentWindowNode.resizeCornerSize) {
		currentWindowNode.resizeDirection += "w";
	} else if (xOff >= currentWindowNode.windowElement.offsetWidth - currentWindowNode.resizeCornerSize) {
		currentWindowNode.resizeDirection += "e";
	}

	// If not on window edge, restore cursor and exit.
	  if (currentWindowNode.resizeDirection == "") {
		currentWindowNode.windowElement.onmouseout(event);
		return;
	}

	// Change cursor.
	if (window.$KAJAX._browserDetect.ie) {
		document.body.style.cursor = currentWindowNode.resizeDirection + "-resize";
	} else if (window.$KAJAX._browserDetect.moz || window.$KAJAX._browserDetect.op) {
		currentWindowNode.windowElement.style.cursor = currentWindowNode.resizeDirection + "-resize";
	}
}

/**
* EVENT: Cursor Restore
*/
KAJAX_parser.prototype.windowResizeCursorRestore = function (event, windowName) {

}

/**
* EVENT: Cursor Set
*/
KAJAX_parser.prototype.windowResizeCursorDragStart = function (event, windowName) {

}

/**
* Window Widget Class
*/
function WindowWidget()
{
	
}


/**
* WindowNode Class
*/
function WindowNode(windowName, title, isVisible, isModal, left, top, width, height)
{
	this.title = title;
	this.name = windowName;
	this.isVisible = isVisible;
	this.isModal = isModal;
	this.left = left;
	this.top = top;
	this.width = width;
	this.height = height;
	this.zindex = 0;
	this.resizeCornerSize = 16;
	this.minimizedTextWidth = 100;
	this.windowElement = null;
	this.titlebarElement = null;
	this.xOffset = 0;
	this.yOffset = 0;
	this.inMoveDrag = false;
	this.inResizeDrag = false;
}

WindowWidget = new WindowWidget();



/**
* ###############################################
* END WINDOW CONTROL FUNCTIONS
* ###############################################
*/















/**
* ###############################################
* BEGIN KEYBOARD CONTROL FUNCTIONS
* ###############################################
*/

/**
* Handles the keyboard subsystem
09=Tab
11=Home
13=Enter
32=Space Bar
33= !
34= "
35= #
36= $
37= %
38= &amp;
39= '
40= (
41= )
42= *
43= +
44= ,
45= -
46= 
47= /
48= 0
49= 1
50= 2
51= 3
52= 4
53= 5
54= 6
55= 7
56= 8
57= 9
58= :
59= ;
60= &lt;
61= =
62= &gt;
63= ?
64= @
65= A
66= B
67= C
68= D
69= E
70= F
71= G
72= H
73= I
74= J
75=K
76=L
77=M
78=N
79=O
80=P
81=Q
82=R
83=S
84=T
85=U
86=V
87=W
88=X
89=Y
90=Z
91=[
92=\
93=]
94=^
95=-
96=`
97=a
98=b
99=c
100=d
101=e
102=f
103=g
104=h
105=i
106=j
107=k
108=l
109=m
110=n
111=o
112=p
113=q
114=r
115=s
116=t
117=u
118=v
119=w
120=x
121=y
122=z
123={
124=|
125=}
126=~
*/
KAJAX_parser.prototype.render_keyboard = function (parentElement) {
	var bodyElement = document.getElementsByTagName("body");

	var attribKey = parentElement.getAttribute("key");
	var attribKeyCode = parentElement.getAttribute("keycode");
	var attribCtrl = parentElement.getAttribute("ctrl");
	var attribShift = parentElement.getAttribute("shift");

	var isCtrl = false;
	if ((attribCtrl && attribCtrl== "true") || (attribCtrl && attribCtrl== "1"))
	{
		isCtrl = true;
	}

	var isShift = false;
	if ((attribShift && attribShift == "true") || (attribShift && attribShift == "1"))
	{
		isShift = true;
	}

	if (attribKey)
	{
		attribKey = attribKey.toUpperCase();
	}

	if (attribKeyCode && parseInt(attribKeyCode))
	{
		var keyCode = parseInt(attribKeyCode);
	} else if (attribKey && window.$KAJAX._parser.keyMap[attribKey]) {
		var keyCode = parseInt(window.$KAJAX._parser.keyMap[attribKey]);
	} else {
		return false;
	}

	var keyStoreLength = window.$KAJAX._parser.keyStore.length;
	window.$KAJAX._parser.keyStore[keyStoreLength] = new KeyNode(keyStoreLength, isShift, isCtrl, keyCode, parentElement.innerHTML);

	window.$KAJAX._keyboardHandler.assignKey(keyCode, isCtrl, isShift, function () { eval(window.$KAJAX._parser.keyStore[keyStoreLength].jsCode) });

	bodyElement[0].removeChild(parentElement);
}

/**
* KeyNode Class
*/
function KeyNode(nodeID, isShift, isCtrl, keyCode, jsCode)
{
	this.nodeID = nodeID;
	this.isShift = isShift;
	this.isCtrl = isCtrl;
	this.keyCode = keyCode;
	this.jsCode = jsCode;
}















/**
* ###############################################
* BEGIN POPUP CONTROL
* ###############################################
*/

/**
* Processes the popup elements, rendering happens on the fly.
*/
KAJAX_parser.prototype.render_popup = function (tagElement) {
	var bodyElement = document.getElementsByTagName("body");

	var menuName = tagElement.getAttribute("name");
	if (!menuName || menuName == "")
	{
		return false;
	}

	var menuWidth = tagElement.getAttribute("width");
	if (!menuWidth)
	{
		menuWidth = '150';
	}

	window.$KAJAX._parser.menuNodes[menuName] = new Array();
	window.$KAJAX._parser.menuProperties[menuName] = new Array();
	window.$KAJAX._parser.menuProperties[menuName]['width'] = menuWidth;

	var menuParentNodeLength = window.$KAJAX._parser.menuParentNodes.length;
	window.$KAJAX._parser.menuParentNodes[menuName] = new MenuNode(menuName, '', '', '0', false, '', '', false, '', '', menuWidth, 0);

	WidgetMenu.processMenuNodes(menuName, tagElement, 0, '', window.$KAJAX._parser.menuParentNodes[menuName]);

	window.$KAJAX.eventOnClick[window.$KAJAX.eventOnClick.length] = function (event) {
		window.$KAJAX._parser.destroyAllActiveMenus(event);
	}

	tagElement.parentNode.removeChild(tagElement);
}

/**
* Destroys all active menus
*/
KAJAX_parser.prototype.destroyAllActiveMenus = function (event) {
	var el;

	if (window.$KAJAX._browserDetect.ie) {
		el = window.event.srcElement;
	} else {
		el = (event.target.tagName ? event.target : event.target.parentNode);
	}

	if (WidgetMenu.getContainerWith(el, "DIV", "kajaxmenu") == null) {
		var activeMenuCount = window.$KAJAX._parser.activeMenuList.length;
		if (!activeMenuCount)
		{
			return false;
		}

		for (var ii=0; ii<activeMenuCount; ii++)
		{
			var parentNode = window.$KAJAX._parser.menuParentNodes[window.$KAJAX._parser.activeMenuList[ii]];
			if (parentNode)
			{
				WidgetMenu.closeSubMenus(window.$KAJAX._parser.activeMenuList[ii], parentNode);
			}
		}
	}
}

/**
* Displays popup right below linkObject location
*/
KAJAX_parser.prototype.displayPopup = function (event, menuName) {
	if (window.$KAJAX._browserDetect.ie)
	{
		var cordY = event.y;
		var cordX = event.x;
	} else {
		var cordY = event.pageY;
		var cordX = event.pageX;
	}

	window.$KAJAX._parser.displayPopupXY(cordX, cordY, menuName);
}

/**
* Displays popup at specific X Y coordinates
*/
KAJAX_parser.prototype.displayPopupXY = function (cordx, cordy, popupName) {
	// Invalid Menu
	if (!window.$KAJAX._parser.menuParentNodes[menuName] || !window.$KAJAX._parser.menuParentNodes[menuName].n.length)
	{
		return false;
	}

	var parentNodeContainer = window.$KAJAX._parser.menuParentNodes[menuName];

	WidgetMenu.renderPopupMenu(menuName, parentNodeContainer, cordX, cordY);
}

/**
* Fetch the given XML and then display popup at X,Y location
*/
KAJAX_parser.prototype.displayPopupXMLXY = function (linkXML, cordx, cordy) {
	AjaxRequest.get(
		{
			'url':linkXML,
			'onSuccess':function(req){ WidgetMenu.renderXMLMenu(cordx, cordy, req.responseXML); }
		}
	);
}

/**
* Displays popup right below linkObject location
*/
KAJAX_parser.prototype.displayPopupXML = function (event, linkXML) {
	if (window.$KAJAX._browserDetect.ie)
	{
		var cordY = event.y;
		var cordX = event.x;
	} else {
		var cordY = event.pageY;
		var cordX = event.pageX;
	}

	window.$KAJAX._parser.displayPopupXMLXY(linkXML, cordX, cordY);
}

/**
* A Menu Node Class
*/
function MenuNode(title, icon, hoverIcon, nodeID, isSeperator, link, linkxml, expanded, cssClass, linkTarget, width)
{
	this.title = title;
	this.icon = icon;
	this.hoverIcon = hoverIcon;
	this.link = link;
	this.linkxml = linkxml;
	this.expanded = expanded;
	this.cssClass = cssClass;
	this.linkTarget = linkTarget;
	this.n = new Array();
	this.events = new Array();
	this.branchLevel = 0;
	this.nodeID = nodeID;
	this.isSeperator = isSeperator;
	this.width = width;
	this.isChildMenuVisible = false;
	this.isvisible = false;
	this.branchLevel = 0;
	this.ajaxRequestActive = false;
}

/**
* Adds a node to an already existing node
*/
MenuNode.prototype.addItem = function (newNode)
{
	newIndex = this.n.length;
	this.n[newIndex] = newNode;

	return this.n[newIndex];
}


/**
* WidgetMenu Class
*/
function WidgetMenu()
{

}

/**
* Processes a parent element and converts them into menu nodes
*/
WidgetMenu.prototype.processMenuNodes = function (menuName, parentElement, branchLevel, strBranchTree, parentNode)
{
	var nodeCount = 0;
	// We always just go through the element and create relevant MenuNodes

	for (var iNode = 0; iNode < parentElement.childNodes.length; iNode++) {
		var currentNode = parentElement.childNodes.item(iNode);

		if (currentNode.nodeType != 1)
		{
			continue;
		}

		if (strBranchTree == "")
		{
			var strCurrentNodeName = nodeCount;
		} else {
			var strCurrentNodeName = strBranchTree+'_'+nodeCount;
		}

		var menuNodeIndex = window.$KAJAX._parser.menuNodes[menuName].length;
		// Seperator
		if (window.$KAJAX._parser.isValidTag(currentNode.tagName, 'ui:menuseperator'))
		{
			window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex] = new MenuNode('', '', '', strCurrentNodeName, true, '', '', false, currentNode.getAttribute("class"), '', 0, branchLevel);
			window.$KAJAX._parser.menuNodePointer['n_'+menuName+'_'+strCurrentNodeName] = window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex];
			window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex].parentNode = parentNode;
			parentNode.addItem(window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex]);
		} else if (window.$KAJAX._parser.isValidTag(currentNode.tagName, 'ui:menuitem')) {
			if (currentNode.getAttribute("title"))
			{
				var nodeTitle = currentNode.getAttribute("title");
			} else {
				var nodeTitle = currentNode.firstChild.nodeValue;
			}

			window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex] = new MenuNode(nodeTitle, currentNode.getAttribute("icon"), currentNode.getAttribute("hovericon"), strCurrentNodeName, false, currentNode.getAttribute("link"), currentNode.getAttribute("linkxml"), false, currentNode.getAttribute("class"), currentNode.getAttribute("target"), currentNode.getAttribute("width"), branchLevel);

			window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex].parentNode = parentNode;
			window.$KAJAX._parser.menuNodePointer['n_'+menuName+'_'+strCurrentNodeName] = window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex];
			parentNode.addItem(window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex]);

			// We have child items.. process again
			if (currentNode.childNodes.length)
			{
				this.processMenuNodes(menuName, currentNode, (branchLevel+1), strBranchTree+'_'+branchLevel, window.$KAJAX._parser.menuNodes[menuName][menuNodeIndex]);
			}
		}

		nodeCount++;
	}
}

/**
* Renders Popup at X,Y Coordinates
*/
WidgetMenu.prototype.renderPopupMenu = function (menuName, parentNodeContainer, cordx, cordy)
{
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	var menuParentElement = document.createElement("div");
	menuParentElement.id = 'km_'+menuName+'_'+parentNodeContainer.nodeID;
	menuParentElement.className = 'kajaxmenu';

	if (parentNodeContainer.width)
	{
		menuParentElement.style.width = parentNodeContainer.width+'px';
	} else {
		menuParentElement.style.width = window.$KAJAX._parser.menuProperties[menuName]['width']+'px';
	}

	window.$KAJAX._parser.activeMenuList[window.$KAJAX._parser.activeMenuList.length] = menuName;

	parentNodeContainer.isvisible = true;

	for (var ii=0; ii<parentNodeContainer.n.length; ii++)
	{
		var currentNode = parentNodeContainer.n[ii];
		var hasChilds = false;
		if (currentNode.n.length)
		{
			hasChilds = true;
		}

		// Seperator
		if (currentNode.isSeperator)
		{
			var menuSeperator = document.createElement("div");
			menuSeperator.className = 'kajaxmenuItemSep';
			menuParentElement.appendChild(menuSeperator);
		// Normal Menu Item
		} else {
			var menuItem = document.createElement("div");
			menuItem.id = 'n_'+menuName+'_'+currentNode.nodeID;

			var prefixData = suffixData = "";

			if (currentNode.icon)
			{
				prefixData += '<td bgcolor="#fcfaf5" width="16"><img src="'+ imagePath + currentNode.icon + '" align="absmiddle" border="0" id="i_'+menuName+'_'+ currentNode.nodeID +'" /></td>';
			} else {
				prefixData += '<td bgcolor="#fcfaf5" width="16"><img src="'+ imagePath + "space.gif" + '" width="16" height="16" align="absmiddle" border="0" id="i_'+menuName+'_'+ currentNode.nodeID +'" /></td>';
			}

			prefixData += '<td bgcolor="#efe8da" width="1"><img src="'+ imagePath + "space.gif" + '" width="1" height="1" border="0" /></td>'

			if (currentNode.n.length || currentNode.linkxml)
			{
				suffixData += '<td width="16" align="right"><img src="'+ imagePath + "menuarrow.gif" + '" align="absmiddle" border="0" id="si_'+menuName+'_'+ currentNode.nodeID +'" /></td>';
			} else {
				suffixData += '<td width="16" align="right"><img src="'+ imagePath + "space.gif" + '" width="16" height="16" align="absmiddle" border="0" id="si_'+menuName+'_'+ currentNode.nodeID +'" /></td>';
			}

			menuItem.innerHTML = '<table width="100%" cellpadding="0" cellspacing="0" border="0" class="kajaxmenuText"><tr>'+prefixData+'<td width="100%"><div style="padding: 3px;">&nbsp;'+currentNode.title+'</div></td>'+suffixData+'</tr></table>';

			menuItem.className = 'kajaxmenuItem';

			menuItem.onmouseover = function () {
				var menuNodeHover = window.$KAJAX._parser.menuNodePointer[this.id];
				if (menuNodeHover)
				{
					if (parentNodeContainer.activeItem && parentNodeContainer.activeItem.nodeID != menuNodeHover.parentNode.nodeID)
					{
						WidgetMenu.closeSubMenus(menuName, parentNodeContainer.activeItem);
					}

					if (this.className != 'kajaxmenuItemHighlight') { this.className = 'kajaxmenuItemHighlight'; }
					parentNodeContainer.activeItem = menuNodeHover;

					if (menuNodeHover.hoverIcon)
					{
						var iconObject = window.$KAJAX._interface.getObject("i_"+menuName+'_'+menuNodeHover.nodeID);
						if (iconObject)
						{
							iconObject.src = imagePath + menuNodeHover.hoverIcon;
						}
					}

					menuNodeObject = window.$KAJAX._interface.getObject(this.id);
					// Is this supposed to be an AJAX object?
					if (menuNodeHover.linkxml && !menuNodeHover.n.length && !menuNodeHover.ajaxRequestActive)
					{
						menuNodeHover.ajaxRequestActive = true;
						var statusIconObject = window.$KAJAX._interface.getObject("si_"+menuName+'_'+menuNodeHover.nodeID);
						if (statusIconObject)
						{
							statusIconObject.src = imagePath + "loadingcircle.gif";
						}
						AjaxRequest.get(
							{
								'url':menuNodeHover.linkxml,
								'onSuccess':function(req){ WidgetMenu.renderXMLChildMenus(menuName, menuNodeObject, menuNodeHover, req.responseXML); }
							}
						);
					} else {
						// We have sub menus?
						if (menuNodeHover.n.length)
						{
							WidgetMenu.renderChildMenus(menuName, menuNodeObject, menuNodeHover);
						}
					}
				}
			}
			menuItem.onmouseout = function () {
				var menuNodeHover = window.$KAJAX._parser.menuNodePointer[this.id];

				if (this.className != 'kajaxmenuItem' && !menuNodeHover.isChildMenuVisible) {
					this.className = 'kajaxmenuItem';
					if (menuNodeHover)
					{
						if (menuNodeHover.icon)
						{
							var iconObject = window.$KAJAX._interface.getObject("i_"+menuName+'_'+menuNodeHover.nodeID);
							if (iconObject)
							{
								iconObject.src = imagePath + menuNodeHover.icon;
							}
						}
					}
				}

			}
			menuParentElement.appendChild(menuItem);
		}
	}

	menuParentElement.style.left = cordx+"px";
	menuParentElement.style.top = cordy+"px";

	bodyElement[0].appendChild(menuParentElement);
}

WidgetMenu.prototype.renderXMLMenu = function (cordx, cordy, xmlDoc) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	// We first process the xmlDoc and add the relevant pointers.
	var currentTag = 'ui:popup';
	if (window.$KAJAX._browserDetect.moz)
	{
		currentTag = 'popup';
	}

	var tagElement = xmlDoc.getElementsByTagName(currentTag).item(0);
	if (!tagElement || !tagElement.childNodes.length)
	{
		return false;
	}

	var menuName = tagElement.getAttribute("name");
	if (!menuName || menuName == "")
	{
		return false;
	}

	var menuWidth = tagElement.getAttribute("width");
	if (!menuWidth)
	{
		menuWidth = '150';
	}

	window.$KAJAX._parser.menuNodes[menuName] = new Array();
	window.$KAJAX._parser.menuProperties[menuName] = new Array();
	window.$KAJAX._parser.menuProperties[menuName]['width'] = menuWidth;

	var menuParentNodeLength = window.$KAJAX._parser.menuParentNodes.length;
	window.$KAJAX._parser.menuParentNodes[menuName] = new MenuNode(menuName, '', '', '0', false, '', '', false, '', '', menuWidth, 0);

	WidgetMenu.processMenuNodes(menuName, tagElement, 0, '', window.$KAJAX._parser.menuParentNodes[menuName]);

	window.$KAJAX.eventOnClick[window.$KAJAX.eventOnClick.length] = function (event) {
		window.$KAJAX._parser.destroyAllActiveMenus(event);
	}

	// By this time we should have the menu data processed and in the required arrays.
	var parentNodeContainer = window.$KAJAX._parser.menuParentNodes[menuName];

	WidgetMenu.renderPopupMenu(menuName, parentNodeContainer, cordx, cordy);
}

WidgetMenu.prototype.renderXMLChildMenus = function (menuName, parentElement, parentNode, xmlDoc) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	// We first process the xmlDoc and add the relevant pointers.
	var currentTag = 'ui:popup';
	if (window.$KAJAX._browserDetect.moz)
	{
		currentTag = 'popup';
	}

	var itemRoot = xmlDoc.getElementsByTagName(currentTag).item(0);
	if (!itemRoot || !itemRoot.childNodes.length)
	{
		return false;
	}

	parentNode.ajaxRequestActive = false;

	// Reset Status Icon
	var statusIconObject = window.$KAJAX._interface.getObject("si_"+menuName+'_'+parentNode.nodeID);
	if (statusIconObject)
	{
		statusIconObject.src = imagePath + "menuarrow.gif";
	}

	// Process XML Nodes
	this.processMenuNodes(menuName, itemRoot, (parentNode.branchLevel+1), parentNode.nodeID, parentNode);

	// Render the newly fetched menus
	this.renderChildMenus(menuName, parentElement, parentNode);
}

WidgetMenu.prototype.renderChildMenus = function (menuName, parentElement, parentNode) {
	if (!parentElement || !parentNode)
	{
		return false;
	}

	x = this.getPageOffsetLeft(parentElement) + parentElement.offsetWidth;
	y = this.getPageOffsetTop(parentElement);



	// We find the X Y coordinates for our child menu.
	var maxX, maxY;

	if (window.$KAJAX._browserDetect.ie) {
		maxX = (document.documentElement.scrollLeft != 0 ? document.documentElement.scrollLeft : document.body.scrollLeft) + (document.documentElement.clientWidth  != 0 ? document.documentElement.clientWidth : document.body.clientWidth);
		maxY = (document.documentElement.scrollTop != 0 ? document.documentElement.scrollTop : document.body.scrollTop) + (document.documentElement.clientHeight != 0 ? document.documentElement.clientHeight : document.body.clientHeight);
	} else if (window.$KAJAX._browserDetect.op) {
		maxX = document.documentElement.scrollLeft + window.innerWidth;
		maxY = document.documentElement.scrollTop  + window.innerHeight;
	} else if (window.$KAJAX._browserDetect.moz) {
		maxX = window.scrollX + window.innerWidth;
		maxY = window.scrollY + window.innerHeight;
	}

	maxX -= parentElement.offsetWidth;
	maxY -= parentElement.offsetHeight;

	var menuObject = this.getContainerWith(parentElement, 'DIV', 'kajaxmenu');

	var currentNodeWidth = parentNode.width;
	if (!currentNodeWidth)
	{
		currentNodeWidth = window.$KAJAX._parser.menuProperties[menuName]['width'];
	}

	if (x > maxX && menuObject) {
		x = Math.max(0, x - parentElement.offsetWidth - currentNodeWidth + (menuObject.offsetWidth - parentElement.offsetWidth));
	}

	y = Math.max(0, Math.min(y, maxY));

	parentNode.isChildMenuVisible = true;
	this.renderPopupMenu(menuName, parentNode, x, y);
}

WidgetMenu.prototype.closeSubMenus = function (menuName, parentNode) {
	if (!parentNode)
	{
		return false;
	}

	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");
	var childNodeCount = parentNode.n.length;

	if (!childNodeCount)
	{
		return false;
	}

	var parentMenuObject;
	if (parentNode.isvisible)
	{
		for (var ii=0; ii<childNodeCount; ii++)
		{
			var currentNode = parentNode.n[ii];
			var menuNodeObject = window.$KAJAX._interface.getObject('n_'+menuName+'_'+currentNode.nodeID);
			if (menuNodeObject)
			{
				parentMenuObject = menuNodeObject.parentNode;
				menuNodeObject.parentNode.removeChild(menuNodeObject);
			}

			if (currentNode.n.length)
			{
				this.closeSubMenus(menuName, currentNode);
			}
		}

		if (parentMenuObject)
		{
			parentMenuObject.parentNode.removeChild(parentMenuObject);
		}

		parentNode.isvisible = false;
		var parentNodeObject = window.$KAJAX._interface.getObject('n_'+menuName+'_'+parentNode.nodeID);
		if (parentNodeObject)
		{
			parentNodeObject.className = 'kajaxmenuItem';
			if (parentNode.icon)
			{
				var iconObject = window.$KAJAX._interface.getObject("i_"+menuName+'_'+parentNode.nodeID);
				if (iconObject)
				{
					iconObject.src = imagePath + parentNode.icon;
				}
			}
		}
	}
}

WidgetMenu.prototype.getContainerWith = function (node, tagName, className) {
	// Starting with the given node, find the nearest containing element
	// with the specified tag name and style class.

	while (node != null) {
		if (node.tagName != null && node.tagName == tagName && this.hasClassName(node, className)) {
			return node;
		}

			node = node.parentNode;
	}

	return node;
}

WidgetMenu.prototype.hasClassName = function (el, name) {
	var i, list;

	// Return true if the given element currently has the given class name.

	list = el.className.split(" ");
	for (i = 0; i < list.length; i++) {
		if (list[i] == name) {
			return true;
		}
	}

	return false;
}

WidgetMenu.prototype.getPageOffsetLeft = function (el) {
	var x;

	// Return the x coordinate of an element relative to the page.

	x = el.offsetLeft;
	if (el.offsetParent != null) {
		x += this.getPageOffsetLeft(el.offsetParent);
	}

	return x;
}

WidgetMenu.prototype.getPageOffsetTop = function (el) {
	var y;

	// Return the x coordinate of an element relative to the page.

	y = el.offsetTop;


	if (el.offsetParent != null) {
//		alert(el.offsetParent.innerHTML);
		y += this.getPageOffsetTop(el.offsetParent);
	}

	return y;
}

WidgetMenu = new WidgetMenu;


/**
* ###############################################
* END POPUP CONTROL
* ###############################################
*/











/**
* ###############################################
* BEGIN ACCORDION CONTROL
* ###############################################
*/


/**
* Renders an Accordion Control
*/
KAJAX_parser.prototype.render_accordion = function (tagElement) {
	var bodyElement = document.getElementsByTagName("body");
	var imagePath = bodyElement[0].getAttribute("kajaximagepath");

	var attribName = tagElement.getAttribute("name");
	if (!attribName)
	{
		return false;
	}
	var attribWidth = tagElement.getAttribute("width");
	if (!attribWidth)
	{
		attribWidth = "200";
	}

	// No Sub Items?
	if (!tagElement.childNodes.length)
	{
		return false;
	}

	window.$KAJAX._parser.accordionSections[attribName] = new Array();
	window.$KAJAX._parser.accordionProperties[attribName] = new Array();

	var accordionElement = document.createElement("div");
	accordionElement.className = "kajaxaccordion";
	accordionElement.id = "ka_"+attribName;
	accordionElement.style.width = attribWidth+"px";

	var sectionCount = 0;
	for (var ii=0; ii<tagElement.childNodes.length; ii++)
	{
		var currentSectionNode = tagElement.childNodes[ii];

		if (currentSectionNode.nodeType != 1)
		{
			continue;
		}

		var attribTitle = currentSectionNode.getAttribute("title");
		var attribIcon = currentSectionNode.getAttribute("icon");
		var attribHoverIcon = currentSectionNode.getAttribute("hovericon");
		var attribItemIcon = currentSectionNode.getAttribute("itemicon");
		var attribItemHoverIcon = currentSectionNode.getAttribute("itemhovericon");
		var attribLink = currentSectionNode.getAttribute("link");
		var attribLinkXML = currentSectionNode.getAttribute("linkxml");
		var attribTarget = currentSectionNode.getAttribute("target");
		var attribCssClass = currentSectionNode.getAttribute("class");
		var attribExpanded = currentSectionNode.getAttribute("expanded");

		var isExpanded = false;
		if (attribExpanded == "1" || attribExpanded == "true")
		{
			isExpanded = true;
		}

		var sectionIndex = window.$KAJAX._parser.accordionSections[attribName].length;
		window.$KAJAX._parser.accordionSections[attribName][sectionIndex] = new AccordionSection(attribName, sectionCount, attribTitle, attribIcon, attribHoverIcon, attribItemIcon, attribItemHoverIcon, attribCssClass, attribLink, attribLinkXML, attribTarget, isExpanded);
		var currentSection = window.$KAJAX._parser.accordionSections[attribName][sectionIndex];

		var sectionElement = document.createElement("div");
		if (attribCssClass)
		{
			sectionElement.className = attribCssClass;
		} else {
			sectionElement.className = 'kajaxaccordionSection';
		}
		sectionElement.id = 'as_'+attribName+'_'+sectionCount;
		window.$KAJAX._parser.accordionPointer['as_'+attribName+'_'+sectionCount] = currentSection;

		var sectionElementContainer = document.createElement("div");
		sectionElementContainer.id = 'asc_'+attribName+'_'+sectionCount;

		if (isExpanded)
		{
			sectionElementContainer.style.display = 'block';
		} else {
			sectionElementContainer.style.display = 'none';
		}

		var prefixData = suffixData = '';
		if (attribIcon)
		{
			prefixData = '<td width="16" align="right"><img src="'+ imagePath + attribIcon +'" width="16" height="16" id="ais_' +attribName+'_'+sectionCount+ '" border="0" align="absmiddle" /></td>';
		}

		suffixData = '<td width="16" align="right"><img src="'+ imagePath + 'space.gif' +'" width="16" height="16" id="ass_' +attribName+'_'+sectionCount+ '" border="0" align="absmiddle" /></td>';

		sectionElement.innerHTML = '<table cellpadding="0" cellspacing="0" border="0"><tr>'+ prefixData +'<td class="kajaxaccordionText">&nbsp;'+ attribTitle +'</td>'+suffixData+'</tr></table>';

		sectionElement.onmouseover = function () {
			var sectionNode = window.$KAJAX._parser.accordionPointer[this.id];
			if (this.className != 'kajaxaccordionSectionHighlight')
			{
				this.className = 'kajaxaccordionSectionHighlight';

				if (sectionNode && sectionNode.hoverIcon)
				{
					var sectionNodeIcon = window.$KAJAX._interface.getObject('ais_'+sectionNode.accordionName+'_'+sectionNode.sectionID);
					if (sectionNodeIcon)
					{
						sectionNodeIcon.src = imagePath+sectionNode.hoverIcon;
					}
				}
			}
		}

		sectionElement.onmouseout = function () {
			var sectionNode = window.$KAJAX._parser.accordionPointer[this.id];
			if (this.className != 'kajaxaccordionSection')
			{
				this.className = 'kajaxaccordionSection';

				if (sectionNode && sectionNode.icon)
				{
					var sectionNodeIcon = window.$KAJAX._interface.getObject('ais_'+sectionNode.accordionName+'_'+sectionNode.sectionID);
					if (sectionNodeIcon)
					{
						sectionNodeIcon.src = imagePath+sectionNode.icon;
					}
				}
			}
		}

		sectionElement.onmousedown = function () {
			var sectionPointer = window.$KAJAX._parser.accordionPointer[this.id];
			if (sectionPointer)
			{
				sectionPointer.expandSection();
			}
		}

		// Now that we have the sections, we process the items under the given section, Do we have any sub items?
		var sectionItemCount = 0;
		if (currentSectionNode.childNodes.length)
		{
			for (var kk=0; kk<currentSectionNode.childNodes.length; kk++)
			{
				var currentItemNode = currentSectionNode.childNodes[kk];
				if (currentItemNode.nodeType != 1)
				{
					continue;
				}

				var nodeTitle = currentItemNode.firstChild.nodeValue;
				var attribLink = currentItemNode.getAttribute("link");
				var attribTarget = currentItemNode.getAttribute("target");
				var attribIcon = currentItemNode.getAttribute("icon");
				var attribHoverIcon = currentItemNode.getAttribute("hovericon");
				var attribCssClass = currentItemNode.getAttribute("class");

				if (!attribIcon)
				{
					attribIcon = attribItemIcon;
				}
				if (!attribHoverIcon)
				{
					attribHoverIcon = attribItemHoverIcon;
				}

				var currentSectionItem = currentSection.addItem(new AccordionItems(currentSection, sectionItemCount, nodeTitle, attribIcon, attribHoverIcon, attribCssClass, attribLink, attribTarget));
				var sectionItemElement = document.createElement("div");
				sectionItemElement.id = 'ai'+attribName+'_'+sectionCount+'_'+sectionItemCount;
				window.$KAJAX._parser.accordionItemPointer[sectionItemElement.id] = currentSectionItem;

				if (attribCssClass)
				{
					sectionItemElement.className = attribCssClass;
				} else {
					sectionItemElement.className = 'kajaxaccordionItem';
				}

				var itemPrefixData = '<td width="22" align="right"><img src="'+ imagePath + "space.gif" +'" width="22" height="16" id="aic_' +attribName+'_'+sectionCount+'_'+sectionItemCount+ '" border="0" align="absmiddle" /></td>';
				if (attribIcon)
				{
					itemPrefixData += '<td width="16" align="right"><img src="'+ imagePath + attribIcon +'" width="16" height="16" id="aii_' +attribName+'_'+sectionCount+'_'+sectionItemCount+ '" border="0" align="absmiddle" /></td>';
				}

				sectionItemElement.innerHTML = '<table cellpadding="0" cellspacing="0" border="0"><tr>'+ itemPrefixData +'<td class="kajaxaccordionText">&nbsp;'+ nodeTitle +'</td></tr></table>';

				sectionItemElement.onmouseover = function () {
					var sectionItemNode = window.$KAJAX._parser.accordionItemPointer[this.id];

					if (this.className != 'kajaxaccordionItemHighlight')
					{
						this.className = 'kajaxaccordionItemHighlight';

						if (sectionItemNode && sectionItemNode.hoverIcon)
						{
							var sectionNodeIcon = window.$KAJAX._interface.getObject('aii_'+sectionItemNode.parentSection.accordionName+'_'+sectionItemNode.parentSection.sectionID+'_'+sectionItemNode.itemID);
							if (sectionNodeIcon)
							{
								sectionNodeIcon.src = imagePath+sectionItemNode.hoverIcon;
							}
						}
					}
				}

				sectionItemElement.onmouseout = function () {
					var sectionItemNode = window.$KAJAX._parser.accordionItemPointer[this.id];
					if (this.className != 'kajaxaccordionItem')
					{
						this.className = 'kajaxaccordionItem';

						if (sectionItemNode && sectionItemNode.icon)
						{
							var sectionNodeIcon = window.$KAJAX._interface.getObject('aii_'+sectionItemNode.parentSection.accordionName+'_'+sectionItemNode.parentSection.sectionID+'_'+sectionItemNode.itemID);
							if (sectionNodeIcon)
							{
								sectionNodeIcon.src = imagePath+sectionItemNode.icon;
							}
						}
					}
				}

				sectionElementContainer.appendChild(sectionItemElement);

				sectionItemCount++;
			}
		}

		accordionElement.appendChild(sectionElement);
		accordionElement.appendChild(sectionElementContainer);

		sectionCount++;
	}

	bodyElement[0].replaceChild(accordionElement, tagElement);
}

/**
* Accordion Section Class
*/
function AccordionSection(accordionName, sectionID, title, icon, hoverIcon, itemIcon, itemHoverIcon, cssClass, link, linkXML, target, isExpanded)
{
	this.accordionName = accordionName;
	this.sectionID = sectionID;
	this.title = title;
	this.icon = icon;
	this.hoverIcon = hoverIcon;
	this.itemIcon = itemIcon;
	this.itemHoverIcon = itemHoverIcon;
	this.cssClass = cssClass;
	this.link = link;
	this.linkXML = linkXML;
	this.target = target;
	this.n = new Array();
	this.isExpanded = isExpanded;
}

/**
* Adds a New Item Node
*/
AccordionSection.prototype.addItem = function (newNode) {
	newIndex = this.n.length;
	this.n[newIndex] = newNode;

	return this.n[newIndex];
}

/**
* Resets the section status for all sections and expands the current section
*/
AccordionSection.prototype.expandSection = function () {
	if (!window.$KAJAX._parser.accordionSections[this.accordionName] || !window.$KAJAX._parser.accordionSections[this.accordionName].length)
	{
		return false;
	}

	for (var ii=0; ii<window.$KAJAX._parser.accordionSections[this.accordionName].length; ii++)
	{
		var currentSection = window.$KAJAX._parser.accordionSections[this.accordionName][ii];
		var sectionObject = window.$KAJAX._interface.getObject('asc_'+currentSection.accordionName+'_'+currentSection.sectionID);
		if (currentSection.accordionName == this.accordionName && currentSection.sectionID == this.sectionID && sectionObject)
		{
			// Current Object, Is it already expanded?
			if (sectionObject.style.display == 'block')
			{
				sectionObject.style.display = 'none'; // Contract It
				currentSection.isExpanded = false;
			} else {
				sectionObject.style.display = 'block';
				currentSection.isExpanded = true;
			}
		} else {
			if (sectionObject)
			{
				sectionObject.style.display = 'none';
				currentSection.isExpanded = false;
			}
		}
	}
}

/**
* Accordion Items Class
*/
function AccordionItems(parentSection, itemID, title, icon, hoverIcon, cssClass, link, target)
{
	this.parentSection = parentSection;
	this.itemID = itemID;
	this.title = title;
	this.icon = icon;
	this.hoverIcon = hoverIcon;
	this.cssClass = cssClass;
	this.link = link;
	this.target = target;
}









/**
* ###############################################
* END ACCORDION CONTROL
* ###############################################
*/








/**
* =====================================================
* Interface Object 
* ***********************************************************
* Handles fetching, display, moving, scrolling etc of UI objects.
* =====================================================
*/
function KAJAX_interface()
{
	
}

/**
* Gets the object from DOM
*/
KAJAX_interface.prototype.getObject = function (objectid)
{
	if (window.$KAJAX._browserDetect.DOMBROWSER == "default")
	{
		return document.getElementById(objectid);
	} else if (window.$KAJAX._browserDetect.DOMBROWSER == "NS4") {
		return document.layers[objectid];
	} else if (window.$KAJAX._browserDetect.DOMBROWSER == "IE4") {
		return document.all[objectid];
	}
}



/**
* ###############################################
* MISC OBJECTS
* ###############################################
*/



function print_r(input, _indent)
{
    if(typeof(_indent) == 'string') {
        var indent = _indent + '    ';
        var paren_indent = _indent + '  ';
    } else {
        var indent = '    ';
        var paren_indent = '';
    }
    switch(typeof(input)) {
        case 'boolean':
            var output = (input ? 'true' : 'false') + "\n";
            break;
        case 'object':
            if ( input===null ) {
                var output = "null\n";
                break;
            }
            var output = ((input.reverse) ? 'Array' : 'Object') + " (\n";
            for(var i in input) {
                output += indent + "[" + i + "] => " + print_r(input[i], indent);
            }
            output += paren_indent + ")\n";
            break;
        case 'number':
        case 'string':
        default:
            var output = "" + input  + "\n";
    }
    return output;
}

function randomString() {
	var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
	var string_length = 8;
	var randomstring = '';
	for (var i=0; i<string_length; i++) {
		var rnum = Math.floor(Math.random() * chars.length);
		randomstring += chars.substring(rnum,rnum+1);
	}

	return randomstring;
}
/**
* ###############################################
* INIT
* ###############################################
*/

window.$KAJAX = new KAJAX();
WidgetFastForward = new WidgetFastForward();
WidgetToolTip = new WidgetToolTip();