/*global window, document, navigator, screen, alert, HTMLElement, HTMLAnchorElement, XMLHttpRequest, ActiveXObject, Option */
var OneNet = OneNet || {};
OneNet.Core = OneNet.Core || {};
OneNet.Core.Common = OneNet.Core.Common || {};
OneNet.Core.Common.Utility = OneNet.Core.Common.Utility || {};

OneNet.Utility = OneNet.Core.Common.Utility;

// *** Function Prototypes

Function.prototype.createDelegate = function(object, method)
{
	/// <summary>Creates a delegate to allow the specified method to run in the context of the specified instance.</summary>
	/// <param name="object" type="Object"></param>
	/// <param name="method" type="Function"></param>
	/// <param name="arguments" type="optional arguments">Optional extra arguments to pass into the method when it is called</param>
	/// <remarks>Necessary to allow "this" in event handlers to point to the specified object rather than the event source element.</remarks>
	/// <remarks>NOTE: IE 5.0 doesn't understand Function.apply if we need to support this browser we will need to define it (perhaps define it in terms of Function.call)</remarks>
	/// <remarks>The delegate function returned will not have the event object as the first parameter. If you need to get at the event details in the delegate function use Function.createDelegateWithDelegate instead.</remarks>
	/// <remarks>
	///	NOTE: There is a bug in IE with this function where if the first known parameter (at the Function.createDelegate call)
	///	or first local parameter (when there are no known parameters) is an event object then it will not be passed to the delegate function.
	///	If an event object needs to be used with createDelegate make sure it isn't the first parameter or if there are no other parameters pass
	///	in a dummy value like null or new Object() or the same event object twice.
	/// </remarks>
	/// <remarks>
	///		Example of Function.createDelegate when no extra parameters.
	///		button.onclick = Function.createDelegate(this, this.sort);
	///		sort: function()
	///		{
	///		}
	///
	///		Example of Function.createDelegate with known parameters
	///		button.onclick = Function.createDelegate(this, this.sort, arg1, arg2, ..., argN);
	///		sort: function(arg1, arg2, ..., argN)
	///		{
	///		}
	///
	///		Example of Function.createDelegate with known parameters and local parameters.
	///		var myFunction = Function.createDelegate(this, this.sort, knownParameter1, knownParameter2, ..., knownParameterN);
	///		myFunction(localParameter1, localParameter2, ..., localParameterN);
	///
	///		sort: function(knownArg1, knownArg2, ..., knownArgN, localArg1, localArg2, ..., localArgN)
	///		{
	///		}
	/// </remarks>
	var functionArguments = arguments;

	return function()
	{
		var callerArguments = [];

		//Now add the arguments to the array. We need to add the arguments known at the time of the createDelegate call and the arguments known when the method is called
		//For example
		//var myFunction = Function.createDelegate(this, blahFunction, 1, 2);
		//myFunction(3, 4);
		//In this example 1 and 2 will be stored in the functionArguments variable
		//and 3 and 4 will be stored in the local arguments variable.
		var i, n;

		//Add arguments passed into the createDelegate method.
		for (i = 2, n = functionArguments.length; i < n; i++)
		{
			callerArguments.push(functionArguments[i]);
		}

		//Add any local arguments that might of been added during the method call (i.e. not the arguments defined at the creation of createDelegate)
		//NOTE: im DOM compliant browsers the first argument will be an event object, we need to skip over this argument.
		for (i = arguments.length > 0 && arguments[0].target ? 1 : 0, n = arguments.length; i < n; i++)
		{
			callerArguments.push(arguments[i]);
		}

		return method.apply(object, callerArguments);
	};
};

Function.prototype.createDelegateWithEvent = function(object, method)
{
	/// <summary>Creates a delegate to allow the specified method to run in the context of the specified instance.</summary>
	/// <param name="object" type="Object"></param>
	/// <param name="method" type="Function"></param>
	/// <param name="arguments" type="optional arguments">Optional extra arguments to pass into the method when it is called</param>
	/// <remarks>Necessary to allow "this" in event handlers to point to the specified object rather than the event source element.</remarks>
	/// <remarks>Use: button.onclick = Function.createDelegate(this, this.method)</remarks>
	/// <remarks>Use: button.onclick = Function.createDelegate(this, this.method, optionalArgument1, optionalArgument2, ... optionalArgumentN)</remarks>
	/// <remarks>NOTE: IE 5.0 doesn't understand Function.apply if we need to support this browser we will need to define it (perhaps define it in terms of Function.call)</remarks>
	/// <remarks>
	///		The delegate function returned will have the event object as the first parameter (or an empty object in browsers that do not pass event objects as the first parameter like IE).
	///		If the delegate function does not need access to event information you can use Function.createDelegate instead.
	///</remarks>
	/// <remarks>
	///	NOTE: There is a bug in IE with this function where if the first known parameter (at the Function.createDelegate call)
	///	or first local parameter (when there are no known parameters) is an event object then it will not be passed to the delegate function.
	///	If an event object needs to be used with createDelegate make sure it isn't the first parameter or if there are no other parameters pass
	///	in a dummy value like null or new Object() or the same object twice.
	///</remarks>
	/// <remarks>
	///		Example of Function.createDelegateWithEvent when no extra parameters.
	///		button.onclick = Function.createDelegateWithEvent(this, this.sort);
	///		sort: function(e)
	///		{
	///		}
	///		or
	///		sort: function() if you don't care about the event.
	///
	///		Example of Function.createDelegateWithEvent with known parameters
	///		button.onclick = Function.createDelegateWithEvent(this, this.sort, arg1, arg2, ..., argN);
	///		sort: function(e, arg1, arg2, ..., argN)
	///		{
	///		}
	///
	///		Example of Function.createDelegateWithEvent with known parameters and local parameters.
	///		var myFunction = Function.createDelegateWithEvent(this, this.sort, knownParameter1, knownParameter2, ..., knownParameterN);
	///		myFunction(localParameter1, localParameter2, ..., localParameterN);
	///
	///		sort: function(e, knownArg1, knownArg2, ..., knownArgN, localArg1, localArg2, ..., localArgN)
	///		{
	///		}
	/// </remarks>
	var functionArguments = arguments;

	return function()
	{
		var callerArguments = [];

		//If there are no arguments or the first parameter isn't an event add a dummy object as the first parameter to the delegate function (needed for IE)
		var skipFirstLocalArgument = false;

		if (arguments.length === 0 || !arguments[0].target)
		{
			callerArguments.push({});
		}

		//the first local parameter is an event, add it first to the callerArguments.
		else if (arguments.length > 0 && arguments[0].target)
		{
			callerArguments.push(arguments[0]);
			skipFirstLocalArgument = true;
		}

		//Now add the arguments to the array. We need to add the arguments known at the time of the createDelegate call and the arguments known when the method is called
		//For example
		//var myFunction = Function.createDelegateWithEvent(this, blahFunction, 1, 2);
		//myFunction(3, 4);
		//In this example 1 and 2 will be stored in the functionArguments variable
		//and 3 and 4 will be stored in the local arguments variable.
		var i, n;

		//Add arguments passed into the createDelegate method.
		for (i = 2, n = functionArguments.length; i < n; i++)
		{
			callerArguments.push(functionArguments[i]);
		}

		//Add any local arguments that might of been added during the method call (i.e. not the arguments defined at the creation of createDelegate)
		for (i = skipFirstLocalArgument ? 1 : 0, n = arguments.length; i < n; i++)
		{
			callerArguments.push(arguments[i]);
		}

		return method.apply(object, callerArguments);
	};
};

// *** Array prototypes

if (typeof Array.push === "undefined")
{
	Array.prototype.push = function()
	{
		/// <summary>defines Array.push if it is not already defined by the browser (i.e., IE5)</summary>

		for (var i = 0, n = arguments.length; i < n; i++)
		{
			this[this.length] = arguments[i];
		}

		return this.length;
	};
}

Array.prototype.isInArray = function(element)
{
	/// <summary>Indicates whether an element is contained in an array</summary>
	/// <param name="element" type="object">The item to see if it is in the array</summary>
	/// <returns type="Boolean">True if the element is in the array else false</returns>

	return this.indexOf(element) !== -1;
};

if (typeof Array.indexOf === "undefined")
{
	Array.prototype.indexOf = function(item)
	{
		/// <summary>Returns the index of the item in the array</summary>
		/// <returns type="Integer">The index of the item in the array, else -1 if it is not in the array</summary>

		for (var i = 0, n = this.length; i < n; i++)
		{
			if (this[i] === item)
			{
				return i;
			}
		}

		return -1;
	};
}

//Define the outerHTML property for browsers that do not natively support it (i.e. Mozilla)
if ((typeof HTMLElement !== "undefined") && HTMLElement.prototype.__defineGetter__ !== "undefined" && HTMLElement.prototype.__defineGetter__ !== undefined)
{
	HTMLElement.prototype.__defineGetter__("outerHTML", function()
	{
		return OneNet.Utility.DOM.getOuterHTML(this);
	});
}


//Define the click method for links for browsers that do not natively support the method (i.e. Mozilla)
if ((typeof HTMLAnchorElement !== "undefined") && typeof HTMLAnchorElement.prototype.click === "undefined")
{
	HTMLAnchorElement.prototype.click = function()
	{
		//NOTE: for mozilla we need to pass in an event handler as the first parameter to the onclick event handler.
		//so we need to create a dummy event object to pass in.
		//TODO: What other properties do we need to define for the event object?
		if (this.onclick)
		{
			var eventObject = {};
			eventObject.eventPhase = 2;

			eventObject.preventDefault = function()
			{
				this.returnValue = false;
			};

			eventObject.stopPropagation = function()
			{
				this.cancelBubble = true;
			};

			eventObject.target = this;

			//TODO: Do we need to check the values of returnValue and cancelBubble and if necessary call the onclick event handlers of the parents?
			var returnValue = this.onclick.call(this, eventObject);

			if (returnValue === true)
			{
				window.location = this.href;
			}

			return returnValue;
		}

		else
		{
			window.location = this.href;
		}
	};
}

// *** XMLHttpRequest Object

/// XMLHttpRequest - defines the XMLHttpRequest object if it is not already defined by the browser.
if (typeof XMLHttpRequest === "undefined" && window.ActiveXObject)
{
	function XMLHttpRequest()
	{
		var activeXObjects = ["MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];

		for (var i = 0, n = activeXObjects.length; i < n; i++)
		{
			try
			{
				var request = new ActiveXObject(activeXObjects[i]);
				return request;
			}

			catch(error)
			{
				// activeXObject not supported
			}
		}

		throw new Error("XMLHttpRequest is not supported");
	}
}

OneNet.Utility.String = OneNet.Utility.String ||
{
	format: function(theString)
	{
		/// <summary>Returns the string passed in with the placeholder values replaced with the arguments passed in.</summary>
		/// <param name="theString" type="String">The string to format</param>
		/// <param type="arguments" optional="true">Optional number of arguments to do the replace with</param>

		var stringToReturn = theString;

		for (var i = 1, n = arguments.length; i < n; i++)
		{
			stringToReturn = stringToReturn.replace(new RegExp("\\{" + (i - 1).toString() + "\\}", "g"), arguments[i].toString());
		}

		return stringToReturn;
	},

	trim: function(value)
	{
		/// <summary>Removes leading, trailing, and extraneous white space characters from a string.</summary>
		/// <param name="value" type="String">The string to trim</param>
		/// <returns>A trimmed string</returns>

		if (value !== null)
		{
			return value.toString().replace(/\s{2,}/g, " ").replace(/[\t\v\f\n\r]/g, " ").replace(/^\s+|\s+$/g, "");
		}
		else
		{
			return "";
		}
	},

	stripHTML: function(value)
	{
		/// <summary>Removes html tags and non-breaking spaces from an html string. Returns the element's text and alt text.</summary>
		/// <param name="value" type="String">A string containing html markup</param>
		/// <returns type="String">A string without html markup and alt text in brackets (i.e. [alt text])

		if (value !== null && value !== "")
		{
			value = value.replace(/alt=\"\"/g, "");
			value = value.replace(/alt=\"([^\"]*)\"/g, "> [$1] <"); // replace 'alt="alt text"' with '> [alt text] <'
			value = value.replace(/alt=([^ |^\/|^\>]*)/g, "> [$1] <"); // replace "alt=alttext" with "> [alttext] <"
			value = value.replace(/\<[^>]*\>/g, ""); // remove "<" + anything + ">"
			value = value.replace(/&nbsp;/gi, " "); // replace non-breaking spaces with spaces
			value = value.replace(/\s+/g, " "); // replace multiple whitespace characters with single spaces
			value = value.replace(/^ /, ""); // remove leading space
			value = value.replace(/ $/, ""); // remove trailing space

			return value;
		}

		else
		{
			return "";
		}
	},

	htmlEncode: function(value)
	{
		/// <summary>HTML encodes a string</summary>
		/// <param name="value" type="String">A string to HTML encode</param>
		/// <returns type="String">Returns an HTML-encoded string ("&" replaced with "&amp;", "<" replaced with "&lt;", and ">" replaced with "&gt;")</returns>

		if (value !== null && value !== "")
		{
			value = value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
			return value;
		}

		else
		{
			return "";
		}
	},

	htmlDecode: function(value)
	{
		/// <summary>HTML decodes a string</summary>
		/// <param name="value" type="String">A string to HTML decode</param>
		/// <returns type="String">Returns an HTML-decoded string ("&quot;" replace with ", "&gt;" replaced with ">", "&lt;" replaced with "<", and "&amp;" replaced with "&")</param>

		if (value !== null && value !== "")
		{
			value = value.replace(/&quot;/g, "\"").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
			return value;
		}

		else
		{
			return "";
		}
	},

	/// convertEscapedCharacters - Converts escaped characters from word/wordperfect into their ascii html equivalent.
	/// returns: string - The string to convert
	/// returns: string - The converted string
	convertEscapedCharacters: function(string)
	{
		return string.replace(/\u2019/gi, "'").replace(/\u2018/gi, "'").replace(/\u201C/gi, "\"").replace(/\u201D/gi, "\"").replace(/\u2022/gi, "*").replace(/\u2013/gi, "-").replace(/\u2014/gi, "-").replace(/\u00A9/gi, "&copy;").replace(/\u00BC/gi, "1/4").replace(/\u00BD/gi, "1/2").replace(/\u00BE/gi, "3/4").replace(/\u00AE/gi, "&reg;").replace(/\u2122/gi, "TM");
	},

	/// stripUnwantedHTML - Removes <font>, <center>, and <u> tags
	/// returns: string - A string without <font>, <center>, and <u> tags
	stripUnwantedHTML: function(text)
	{
		if(text && text !== "")
		{
			text = text.replace(/<\/?FONT[^>]*>/gi, "").replace(/<\/?CENTER[^>]*>/gi, "").replace(/<\/?U>/gi, "");
		}

		return text === null ? "" : text;
	}
};

OneNet.Utility.String.StringBuilder = OneNet.Utility.String.StringBuilder || function()
{
	/// <summary>Contructs a new StringBuilder object</summary>

	this._strings = [];
};

OneNet.Utility.String.StringBuilder.prototype =
{
	append: function(string)
	{
		/// <summary>Appends the string passed into the string builder</summary>
		/// <returns type="OneNet.Utility.String.StringBuilder">The string builder object</returns>
		/// <remarks>The StringBuilder is returns so you can chain appends in a row for example stringBuilder.append("hello ").append(firstName).append(" ").append(lastName);.</remarks>

		this._strings.push(string);
		return this;
	},

	toString: function()
	{
		/// <summary>Returns the contents of the StringBuilder object</summary>
		/// <returns type="String">The contents of the StringBuilder object</returns>

		return this._strings.join("");
	}
};

//NOTE: Cookie code borrowered from "Chapter 16 of Professional Javascript for Web Developers"
OneNet.Utility.Cookie = OneNet.Utility.Cookie ||
{
	setCookie: function(sName, sValue, oExpires, sPath, sDomain, bSecure)
	{
		var sCookie = sName + "=" + encodeURIComponent(sValue);

		if (oExpires) {
			sCookie += "; expires=" + oExpires.toGMTString();
		}

		if (sPath) {
			sCookie += "; path=" + sPath;
		}

		if (sDomain) {
			sCookie += "; domain=" + sDomain;
		}

		if (bSecure) {
			sCookie += "; secure";
		}

		document.cookie = sCookie;
	},

	getCookie: function(sName)
	{
		var sRE = "(?:; )?" + sName + "=([^;]*);?";
		var oRE = new RegExp(sRE);

		if (oRE.test(document.cookie)) {
			return decodeURIComponent(RegExp["$1"]);
		} else {
			return null;
		}
	},

	deleteCookie: function(sName, sPath, sDomain)
	{
		var sCookie = sName + "=; expires=" + (new Date(0)).toGMTString();

		if (sPath) {
			sCookie += "; path=" + sPath;
		}

		if (sDomain) {
			sCookie += "; domain=" + sDomain;
		}

		document.cookie = sCookie;
	}
};

OneNet.Utility.DOM = OneNet.Utility.DOM ||
{
	/// hasClass
	/// param: element, htmlElement
	/// param: variable list of class names, string
	/// returns: true if the element passed in is in one of the classes in the argument list, else false.
	hasClass: function(element)
	{
		var elementClassNames = " " + element.className + " ";

		for (var i = 1, n = arguments.length; i < n; i++)
		{
			if (elementClassNames.indexOf(" " + arguments[i] + " ") !== -1)
			{
				return true;
			}
		}

		return false;
		//return (" " + element.className + " ").indexOf(" " + className + " ") != -1;
	},

	/// addClass
	/// param: element, htmlElement
	/// param: variable list of class names, string
	/// NOTE: if the class name to add is already associated with the element it will not be added a second time.
	addClass: function(element)
	{
		for (var i = 1, n = arguments.length; i < n; i++)
		{
			if (!OneNet.Utility.DOM.hasClass(element, arguments[i]))
			{
				element.className = element.className === "" ? arguments[i] : element.className + " " + arguments[i];
			}
		}
	},

	/// removeClass
	/// param: element, htmlElement
	/// param: variable list of class names, string
	removeClass: function(element)
	{
		for (var i = 1, n = arguments.length; i < n; i++)
		{
			element.className = OneNet.Utility.String.trim(element.className.replace(new RegExp("\\b" + arguments[i] + "\\b"), ""));
		}

		//element.className = OneNet.Utility.String.trim(element.className.replace(new RegExp("\\b" + className + "\\b"), ""));
	},

	/// removeClasses
	/// param: element
	/// param: classNameArray, array of strings
	removeClasses: function(element, classNameArray)
	{
		OneNet.Utility.DOM.removeClass.apply(this, [element].concat(classNameArray));
	},

	/// getInnerText - Cross-browser version of IE innerText
	/// param: element, htmlElement
	/// returns: string
	getInnerText: function(element)
	{
		if (element && element.innerHTML)
		{
			return OneNet.Utility.String.stripHTML(element.innerHTML);
		}

		else
		{
			return "";
		}
	},

	/// isElementEmpty
	/// param: element, htmlElement
	/// returns: boolean
	isElementEmpty: function(element)
	{
		return OneNet.Utility.DOM.getInnerText(element) === "";
/*
		for (var i = 0, n = element.childNodes.length; i < n; i++)
		{
			if (element.childNodes[i].nodeType == 3 // text node
			&& OneNet.Utility.String.trim(element.childNodes[i]) != "")
			{
				return false;
			}

			else if (element.childNodes[i].nodeType == 1) // element
			{
				if (element.childNodes[i].tagName.toLowerCase() == "img" && OneNet.Utility.String.trim(element.childNodes[i].alt) != "")
				{
					return false;
				}

				else if (OneNet.Utility.DOM.isElementEmpty(element.childNodes[i]) == false)
				{
					return false;
				}
			}
		}

		return true;
*/
	},

	/// moveChildrenToNewElement
	/// param: newElement, htmlElement - The element that will receive the children of oldElement
	/// param: oldElement, htmlElement - The element whos children elements will get moved to newElement
	/// NOTE: this is a destructive operation, since oldElement will no longer have children elements after this is called.
	moveChildrenToNewElement: function(newElement, oldElement)
	{
		while (oldElement.childNodes.length > 0)
		{
			newElement.appendChild(oldElement.childNodes[0]);
		}
	},

	/// replaceElementWithChildren
	/// param: element, htmlElement
	replaceElementWithChildren: function(element)
	{
		for (var i = 0, n = element.childNodes.length; i < n; n--)
		{
			element.parentNode.insertBefore(element.childNodes[i], element);
		}

		element.parentNode.removeChild(element);
	},

	/// isAncestor - Indicates whether possibleAncestor is an ancestor of element.
	/// NOTE: an element is considered to be an ancestor of itself
	/// param: element, htmlElement
	/// param: parentElement, htmlElement
	/// returns: boolean
	isAncestor: function(element, possibleAncestor)
	{
		var ancestor = element;

		while (ancestor)
		{
			if (ancestor === possibleAncestor)
			{
				return true;
			}

			ancestor = ancestor.parentNode;
		}

		return false;
	},

	/// getAncestorWithTagName - Returns the element's most immediate ancestor with a given tagName
	/// note: an element is considered to be an ancestor of itself
	/// param: element list - A list of tag names to look for.
	getAncestorWithTagName: function(element)
	{
		var ancestor = element;
		var argumentsLength = arguments.length;

		while (ancestor)
		{
			//NOTE: need to check that tagName is supported browsers like Mozilla include the document object for a parent node and this property is not defined for it.
			if (ancestor.tagName)
			{
				var tagName = ancestor.tagName.toLowerCase();

				for (var i = 1; i < argumentsLength; i++)
				{
					if (tagName === arguments[i])
					{
						return ancestor;
					}
				}
			}

			ancestor = ancestor.parentNode;
		}

		return ancestor;
	},

	/// show
	/// param: element, element
	show: function(element)
	{
		element.style.display = "block";
	},

	/// hide
	/// param: element, element
	hide: function(element)
	{
		element.style.display = "none";
	},

	getUniqueID: function(prefix, documentToUse)
	{
		///	<summary>Returns an ID value that is not currently assigned to any element in the document.</summary>
		///	<param name="prefix" type="String"></param>
		/// <param name="documentToUse" type="HTML Document">The document to get the unique id for. If this isn't passed in then the document for the current window is used.</param>
		///	<returns type="String"></returns>
		/// <remarks>To be valid HTML, prefix must begin with a letter and contain only letters, digits, hyphens, and/or underscores.</remarks>

		if (typeof documentToUse === "undefined")
		{
			documentToUse = document;
		}

		var i = 1;

		while (documentToUse.getElementById(prefix + i.toString()))
		{
			i++;
		}

		return prefix + i.toString();
	},

	/// getChildElements - Returns the child elements for the element passed in.
	/// NOTE: This differs from element.childNodes since this function will not return text nodes.
	/// returns: Array
	getChildElements: function(element)
	{
		var childElements = [];

		for (var i = 0, n = element.childNodes.length; i < n; i++)
		{
			if (element.childNodes[i].nodeType === 1)
			{
				childElements.push(element.childNodes[i]);
			}
		}

		return childElements;
	},

	getOuterHTML: function(node)
	{
		var str = "";

		switch (node.nodeType) {
			case 1: // ELEMENT_NODE
				str += "<" + node.nodeName;

				for (var i=0; i<node.attributes.length; i++)
				{
					if (node.attributes.item(i).nodeValue !== null)
					{
						str += " ";
						str += node.attributes.item(i).nodeName;
						str += "=\"";
						str += node.attributes.item(i).nodeValue;
						str += "\"";
					}
				}

				if (node.childNodes.length === 0 && (node.nodeName.toLowerCase() === "img" || node.nodeName.toLowerCase() === "hr" || node.nodeName.toLowerCase() === "br" || node.nodeName.toLowerCase() === "input"))
				{
					str += ">";
				}

				else
				{
					str += ">";
					str += OneNet.Utility.DOM.getInnerHTML(node);
					str += "</" + node.nodeName + ">";
				}

				break;

			case 3:   //TEXT_NODE
				str += node.nodeValue;
				break;

			case 4: // CDATA_SECTION_NODE
				str += "<![CDATA[" + node.nodeValue + "]]>";
				break;

			case 5: // ENTITY_REFERENCE_NODE
				str += "&" + node.nodeName + ";";
				break;

			case 8: // COMMENT_NODE
				str += "<!--" + node.nodeValue + "-->";
				break;
		}

		return str;
	},

	getInnerHTML: function(node)
	{
		var str = "";

		for (var i=0; i < node.childNodes.length; i++)
		{
			str += OneNet.Utility.DOM.getOuterHTML(node.childNodes.item(i));
		}

		return str;
	},

	/// getNextSiblingElement - Gets the next sibling that is an element (to mimic the behavior of nextSibling in IE)
	getNextSiblingElement: function(element)
	{
		var current = element.nextSibling;

		while (current !== null && current.nodeType !== 1)
		{
			current = current.nextSibling;
		}

		return current;
	},

	/// getPreviousSiblingElement - Gets the previous sibling that is an element (to mimic the behavior of previousSibling in IE)
	getPreviousSiblingElement: function(element)
	{
		var current = element.previousSibling;

		while (current !== null && current.nodeType !== 1)
		{
			current = current.previousSibling;
		}

		return current;
	},

	getPosition: function(element)
	{
		var x;
		var y;

		var curleft = 0;
		var currentElement = element;

		if(currentElement.offsetParent)
		{
			while(1)
			{
				curleft += currentElement.offsetLeft;

				if(!currentElement.offsetParent)
				{
					break;
				}

				currentElement = currentElement.offsetParent;
			}
		}

		else if(currentElement.x)
		{
			curleft += currentElement.x;
		}

		var curtop = 0;
		currentElement = element;

		if(currentElement.offsetParent)
		{
			while(1)
			{
				curtop += currentElement.offsetTop;

				if(!currentElement.offsetParent)
				{
					break;
				}

				currentElement = currentElement.offsetParent;
			}
		}

		else if(currentElement.y)
		{
			curtop += currentElement.y;
		}

		return { x: curleft, y: curtop };
	},

	getComputedStyle: function(element, property)
	{
		if (element.currentStyle)
		{
			return element.currentStyle[property];
		}

		else if (document.defaultView)
		{
			property = property.replace(/([A-Z])/g, "-$1").toLowerCase();
			return document.defaultView.getComputedStyle(element, null).getPropertyValue(property);
		}
	}
};

OneNet.Utility.Forms = OneNet.Utility.Forms ||
{
	/// formatPhoneNumber - Returns a phone number in the form (###) ###-####
	/// param: value, string
	/// returns: string
	formatPhoneNumber: function(value)
	{
		if (value.replace(/\D/g, "").match(/([2-9]\d{2})(\d{3})(\d{4})/))
		{
			return value.replace(/\D/g, "").replace(/[01]*([2-9]\d{2})(\d{3})(\d{4})\d*/, OneNet.Constants.Forms.formatedPhoneNumberReplaceExpression);
		}

		else
		{
			return value;
		}
	},

	/// getLabelText - Gets the text of the label associated with a form field; if there is no label, gets the field's title attribute.
	/// param: formField, htmlElement
	/// returns: string
	getLabelText: function(formField)
	{
		var labelText = "";
		var label = OneNet.Utility.Forms.getLabelElement(formField);

		labelText = label === null ? "" : OneNet.Utility.DOM.getInnerText(label).replace(/:\s*$/,""); // remove trailing colon

		if (labelText === "" && formField.title)
		{
			labelText = formField.title;
		}

		return labelText;
	},

	///	getLabelElement - Returns the label element associated with formElement
	///	param: formElement, element - The form element to get the label element for
	///	returns: element - The label element associated with this form field or null if a label does not exist
	getLabelElement: function(formField)
	{
		var labels = document.getElementsByTagName("label");

		for (var i = 0, n = labels.length; i < n;  i++)
		{
			if (labels[i].htmlFor === formField.id)
			{
				return labels[i];
			}
		}

		return null;
	},

	/// getLegendText - Gets the text of the legend associated with a form field
	/// param: formField, htmlElement
	/// returns: string
	getLegendText: function(formField)
	{
		var fieldset = OneNet.Utility.DOM.getAncestorWithTagName(formField, "fieldset");

		if (fieldset)
		{
			var legends = fieldset.getElementsByTagName("legend");

			if (legends.length > 0)
			{
				return OneNet.Utility.DOM.getInnerText(legends[0]);
			}
		}

		return "";
	},

	/// getLegendAndLabelText - Gets the text of the legend and label associated with a form field
	/// param: formField, htmlElement
	/// returns: string
	getLegendAndLabelText: function(formField)
	{
		var legendAndLabelText = "";
		var legendText = OneNet.Utility.Forms.getLegendText(formField);
		var labelText = OneNet.Utility.Forms.getLabelText(formField);
		if (legendText && !labelText.match(legendText))
		{
			legendAndLabelText = legendText + " " + labelText;
		}
		else
		{
			legendAndLabelText = labelText;
		}
		return legendAndLabelText;
	},

	/// setFormFieldTitles - Sets title attributes on form fields so that Dragon NaturallySpeaking users can use "click [label]"
	setFormFieldTitles: function()
	{
		var forms = document.getElementsByTagName("form");

		for (var i = 0, n = forms.length; i < n; i++)
		{
			for (var j = 0, m = forms[i].elements.length; j < m; j++)
			{
				var formField = forms[i].elements[j];

				if (formField.title === "")
				{
					var labelText = OneNet.Utility.Forms.getLabelText(formField);
					formField.title = labelText;
				}
			}
		}
	},

	/// makeCheckBoxesReadOnly
	makeCheckBoxesReadOnly: function()
	{
		var inputs = document.getElementsByTagName("input");
		for (var i = 0, n = inputs.length; i < n;  i++)
		{
			if (inputs[i].type.toLowerCase() === "checkbox" && inputs[i].readOnly)
			{
				inputs[i].onclick = function() { return false; };
				inputs[i].title = OneNet.Utility.String.format(OneNet.Constants.Forms.readOnlyFormFieldTitle, OneNet.Utility.Forms.getLabelText(inputs[i]));

				var labelElement = OneNet.Utility.Forms.getLabelElement(inputs[i]);
				labelElement.title = inputs[i].title;
			}
		}
	},

	/// convertReadOnlyDropDownListsIntoTextBoxes
	convertReadOnlyDropDownListsIntoTextBoxes: function()
	{
		var allSelects = document.getElementsByTagName("select");

		for(var i = 0; i < allSelects.length; i++)
		{
			if(OneNet.Utility.DOM.hasClass(allSelects[i], "readonly") === true)
			{
				//create a hidden value and a hidden text box where the drop down list is it.
				var hiddenValue = document.createElement("input");
				hiddenValue.type = "hidden";
				hiddenValue.value = allSelects[i].value;
				hiddenValue.defaultValue = hiddenValue.value;
				hiddenValue.id = allSelects[i].id + "ReadOnly";
				hiddenValue.name = allSelects[i].name;

				allSelects[i].parentNode.insertBefore(hiddenValue, allSelects[i]);

				var readonlyTextBox = document.createElement("input");
				readonlyTextBox.type = "text";
				readonlyTextBox.value = allSelects[i].options[allSelects[i].selectedIndex].text;
				readonlyTextBox.defaultValue = readonlyTextBox.value;
				readonlyTextBox.readOnly = true;
				readonlyTextBox.id = allSelects[i].id;
				readonlyTextBox.className = allSelects[i].className;
				OneNet.Utility.DOM.addClass(readonlyTextBox, "readonly");

				allSelects[i].parentNode.insertBefore(readonlyTextBox, allSelects[i]);
				allSelects[i].parentNode.removeChild(allSelects[i]);

				i--;
			}
		}
	},

	/// setDropDownListValue - Sets the selected index of the dropdown list to the index of the option with the matching value; returns true if value exists in the list, false if it does not.
	/// param: dropDownList, htmlSelectElement
	/// param: value, string
	/// returns: boolean
	/// NOTE: why do we need this function? Can't we just say dropDownList.value = someValue?
	setDropDownListValue: function(dropDownList, value)
	{
		if (dropDownList && dropDownList.options)
		{
			for (var i = 0, n = dropDownList.options.length; i < n; i++)
			{
				if (dropDownList.options[i].value === value)
				{
					dropDownList.selectedIndex = i;
					return true;
				}
			}
		}
		return false;
	},

	/// getClassMatchingSelectOption - gets an element's class name matching one of a select's option values
	/// param: element, element
	/// param: select, element
	/// returns: className, string
	getClassMatchingSelectOption: function(element, select)
	{
		if (element && select && select.options)
		{
			for (var i = 0, n = select.options.length; i < n; i++)
			{
				if (select.options[i].value && OneNet.Utility.DOM.hasClass(element, select.options[i].value))
				{
					return select.options[i].value;
				}
			}
		}

		return "";
	},

	/// replaceDropDownListOptions - Replaces the options of a dropdown list with the options from another.
	/// param: destinationDropDownList, htmlSelectElement
	/// param: sourceDropDownList, htmlSelectElement
	replaceDropDownListOptions: function(destinationDropDownList, sourceDropDownList)
	{
		while (destinationDropDownList.childNodes.length !== 0)
		{
			destinationDropDownList.removeChild(destinationDropDownList.childNodes[0]);
		}
		if (sourceDropDownList.options.length === 0)
		{
			destinationDropDownList.add(new Option("", ""));
		}

		else
		{
			for (var i = 0; i < sourceDropDownList.options.length; i++)
			{
				destinationDropDownList.add(new Option(sourceDropDownList.options[i].text, sourceDropDownList.options[i].value));
			}
		}
	},
	
	/// sortDropDownListOptions - Sorts the options for a drop down list
	/// param: dropDownList, htmlSelectElement
	/// param: sortOnOptionText, boolean. If true the option text is used to sort, if false the value attribute is used to sort.
	/// remarks: This function is needed because the dropDownList.options object does not implement the sort function.
	sortDropDownListOptions: function(dropDownList, sortOnOptionText, sortFunction)
	{
		var selectedValue = dropDownList.value;
		var options = [];
		
		for (var i = 0, n = dropDownList.options.length; i < n; i++)
		{
			options.push({ value: dropDownList.options[i].value, text: dropDownList.options[i].text, optionElement: dropDownList.options[i] });
		}
		
		options.sort(
			sortFunction ? sortFunction :
			sortOnOptionText === true ? 
				function(a, b)
				{
					return a.text < b.text ? -1 : a.text > b.text ? 1 : 0;
				} :
				function(a, b)
				{
					return a.value < b.value ? -1 : a.value > b.value ? 1 : 0;
				});
		
		for (var i = 0, n = options.length; i < n; i++)
		{
			dropDownList.options.appendChild(options[i].optionElement);
		}
		
		dropDownList.value = selectedValue;
	},

	/// setDisabled
	/// param: field, element
	setDisabled: function(field)
	{
		field.value = "";
		field.readOnly = false;
		OneNet.Utility.DOM.removeClass(field, "readonly");
		field.disabled = true;
		OneNet.Utility.DOM.addClass(field, "disabled");
	},

	/// setReadOnly
	/// param: field, element
	/// note: needs logic added to handle checkboxes, radio buttons & selects
	setReadOnly: function(field) {
		field.readOnly = true;
		OneNet.Utility.DOM.addClass(field, "readonly");
		field.disabled = false;
		OneNet.Utility.DOM.removeClass(field, "disabled");

		switch(field.type)
		{
			case "text" :
			case "password" :
			case "textarea" :
				field.readOnly = true;
				break;
			case "checkbox" :
			case "submit" :
			case "reset" :
			case "button" :
				field.onclick = function(e) { OneNet.Utility.Events.getEvent().preventDefault(); };
			case "radio" :
				field.onclick = function() { return false; };
			case "select-one" :
			case "select-multiple" :
				field.onchange = OneNet.Utility.Forms.cancelSelectChange;
				break;
		}
	},

	/// setEditable
	/// param: field, element
	setEditable: function(field)
	{
		field.readOnly = false;
		OneNet.Utility.DOM.removeClass(field, "readonly");
		field.disabled = false;
		OneNet.Utility.DOM.removeClass(field, "disabled");
	},

	cancelSelectChange: function(event)
	{
		var optionGroup = this.options;

		for (var i = 0, n = optionGroup.length; i < n; i++)
		{
			optionGroup[i].selected = optionGroup[i].defaultSelected;
		}
	},

	/// getSelectOptionValues
	/// param: select, element
	/// param: includeNulls, boolean - true to include null/empty string values, false to exclude them
	/// returns: array of strings
	getSelectOptionValues: function(select, includeNulls)
	{
		var optionValues = [];

		if (select.options)
		{
			for (var i = 0, n = select.options.length; i < n; i++)
			{
				if (includeNulls || select.options[i].value)
				{
					optionValues[optionValues.length] = select.options[i].value;
				}
			}
		}

		return optionValues;
	},

	/// setFocusToFirstVisibleFormField - Sets focus to the first visiable form field.
	setFocusToFirstVisibleFormField: function()
	{
		window.focus();

		for (var i = 0, n = document.forms.length; i < n; i++)
		{
			for (var j = 0, m = document.forms[i].elements.length; j < m; j++)
			{
				//hidden and invisible elements (should) have no offsetHeight
				if (document.forms[i].elements[j].type !== "hidden" && document.forms[i].elements[j].offsetHeight)
				{
					document.forms[i].elements[j].focus();
					return;
				}
			}
		}
	}
};

OneNet.Utility.Forms.Validation = OneNet.Utility.Forms.Validation ||
{
	/// setFieldValidationEvents - Assigns validadation events to text fields based on class names
	setFieldValidationEvents: function()
	{
		var inputs = document.getElementsByTagName("input");

		for (var i = 0, n = inputs.length; i < n; i++)
		{
			if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.dateTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateDate;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.timeTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateTime;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.integerTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateInteger;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.phoneTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validatePhone;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.zipCodeTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateZip;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.ssnTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateSSN;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.moneyTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateMoney;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.percentTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validatePercent;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.emailTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateEmail;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.numberTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateNumber;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.userNameTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateUsername;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.digitsTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateDigits;
			}

			else if (OneNet.Utility.DOM.hasClass(inputs[i], OneNet.Constants.Forms.charactersTextBoxClass))
			{
				inputs[i].onblur = OneNet.Utility.Forms.Validation.validateCharacters;
			}
		}
	},

	/// validateDate - Validate & format text field value as Date (mm/dd/yyyy)
	validateDate: function()
	{
		if (this.value !== "")
		{
			var stringValue = OneNet.Utility.String.trim(this.value.replace(new RegExp("-", "g"), "/"));

			// if 6- or 8-digits, add slashes (e.g., 01012001 becomes 01/01/2001)
			if (stringValue.match(/^\d{6}(\d{2})?$/))
			{
				stringValue = stringValue.replace(/(\d{2})(\d{2})(\d{2,4})/, "$1/$2/$3");
			}

			var dateValue = new Date(stringValue);

			if (isFinite(dateValue))
			{
				// if two-digit year, set correct century
				if (stringValue.match(/\D\d{1,2}$/))
				{
					if (dateValue.getFullYear() < (new Date().getFullYear() - 96))
					{
						dateValue.setFullYear(dateValue.getFullYear() + 100);
					}
				}

				var minValue = this.className.match(/\bminvalue-(\d{4})_(\d{2})_(\d{2})\b/) ? new Date(RegExp.$1 + "/" + RegExp.$2 + "/" + RegExp.$3) : OneNet.Constants.Forms.minDate;
				var maxValue = this.className.match(/\bmaxvalue-(\d{4})_(\d{2})_(\d{2})\b/) ? new Date(RegExp.$1 + "/" + RegExp.$2 + "/" + RegExp.$3) : OneNet.Constants.Forms.maxDate;

				// check date range (SQL server 2000)
				if (dateValue < minValue || dateValue > maxValue)
				{
					OneNet.Utility.Forms.Validation.showError(this, OneNet.Utility.String.format(OneNet.Constants.Forms.dateOutOfRange, "{0}", (minValue.getMonth() + 1) + "/" + minValue.getDate() + "/" + minValue.getFullYear(), (maxValue.getMonth() + 1) + "/" + maxValue.getDate() + "/" + maxValue.getFullYear()));
				}

				else
				{
					this.value = (dateValue.getMonth() + 1) + "/" + dateValue.getDate() + "/" + dateValue.getFullYear();
				}
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidDate);
			}
		}
	},

	/// validateTime - Validate & format text field value as Time (hh:mm am|pm)
	validateTime: function()
	{
		if (this.value !== "")
		{
			var digits = this.value.replace(/[^\d]/g, "");
			var hours = -1;
			var minutes = -1;

			switch(digits.length)
			{
				case 1 :
				case 2 :
					hours = digits;
					minutes = 0;
					break;
				case 3 :
					hours = digits.substr(0,1);
					minutes = digits.substring(1,3);
					break;
				case 4 :
					hours = digits.substr(0,2);
					minutes = digits.substring(2,4);
					break;
				default :
					break;
			}

			if ((hours > 0 && hours < 13) &&(minutes > -1 && minutes < 60))
			{
				var meridiem = "am";

				if (this.value.toLowerCase().indexOf("p") !== -1 || this.value.toLowerCase().indexOf("noon") !== -1 ||(this.value.toLowerCase().indexOf("a") === -1 && (Number(hours) < 7 || Number(hours) === 12)))
				{
					meridiem = "pm";
				}

				if (minutes.toString().length === 1)
				{
					minutes = "0" + minutes;
				}

				this.value = hours + ":" + minutes + " " + meridiem;
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidTime);
			}
		}
	},

	/// validateInteger - Validate & format text field value to Integer (strip out non-numeric characters & round)
	validateInteger: function()
	{
		if (this.value !== "")
		{
			//var thisMatch = this.value.replace(/[^\d.]/g, "").match(/\d*.?\d*/);
			var thisMatch = OneNet.Utility.String.trim(this.value).match(/^\d+$/);

			if (thisMatch)
			{
				this.value = OneNet.Utility.String.trim(this.value);
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidInteger);
			}
		}
	},

	/// validateNumber - Validates that the user typed in a number
	validateNumber: function()
	{
		if (isFinite(this.value) === false)
		{
			OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidNumber);
		}
	},

	/// validateMoney - Validates that the user typed in a money value.
	validateMoney: function()
	{
		if (OneNet.Utility.String.trim(this.value) && !OneNet.Utility.String.trim(this.value).match(/^\$?\d{0,3},?\d{0,3},?\d{0,3},?\d{0,3},?\d{1,3}\.?\d{0,2}$/))
		{
			OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidMoney);
		}
	},

	/// validatePhone - Validate & format text field value as Phone Number ((###) ###-####)
	validatePhone: function()
	{
		if (this.value !== "")
		{
			var thisMatch = this.value.replace(/\D/g, "").match(/([2-9]\d{2})(\d{3})(\d{4})/);

			if (thisMatch)
			{
				this.value = this.value.replace(/\D/g, "").replace(/[01]*([2-9]\d{2})(\d{3})(\d{4})\d*/, OneNet.Constants.Forms.formatedPhoneNumberReplaceExpression);
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidPhone);
			}
		}
	},

	/// validateUsername - Validates Username at dhsxxxxxx;
	validateUsername: function()
	{
		if (this.value !== "")
		{
			var thisMatch = this.value.replace(/ /g, "").match(OneNet.Constants.Forms.userNameRegExp);

			if (thisMatch)
			{
				this.value = this.value.replace(/ /g, "").toLowerCase();
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidUsername);
			}
		}
	},

	/// validateZip - Validate & format text field value as Zip Code (#####)
	validateZip: function()
	{
		if (this.value !== "")
		{
			var digits = this.value.replace(/\D/g, "");

			if (digits.length >= 9)
			{
				this.value = digits.replace(/(\d{5})(\d{4})\d*/, OneNet.Constants.Forms.nineDigitsZipCodeReplaceExpression);
			}

			else if (digits.length >= 5)
			{
				this.value = digits.replace(/(\d{5})\d*/, "$1");
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidZip);
			}
		}
	},

	/// validateSSN - Validate & format text field value as SSN (###-##-####)
	validateSSN: function()
	{
		if (this.value !== "")
		{
			var thisMatch = this.value.replace(/\D/g, "").match(/(\d{3})(\d{2})(\d{4})/);

			if (thisMatch)
			{
				this.value = this.value.replace(/\D/g, "").replace(/(\d{3})(\d{2})(\d{4})\d*/, OneNet.Constants.Forms.ssnReplaceExpression);
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidSSN);
			}
		}
	},

	/// validatePercent - Validate & format text field value as Percent (strip out non-numeric characters)
	validatePercent: function()
	{
		if (this.value !== "")
		{
			var thisMatch = this.value.replace(/[^\d.]/g, "").match(/\d*.?\d*/);

			if (thisMatch !== "")
			{
				this.value = this.value.replace(/[^\d.]/g, "");
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidPercent);
			}
		}
	},

	validateDigits: function()
	{
		/// <summary>Validates & formats text field value as Year (4 digits).</summary>
		/// <remarks>minlength, minvalue, and maxvalue can be set in className, e.g. class="digits minlength-4 minvalue-1900 maxvalue-2100"</remarks>

		if (this.value !== "")
		{
			var minlength = this.className.match(/\bminlength-(\d+)\b/) ? parseFloat(this.className.match(/\bminlength-(\d+)\b/)[1]) : 0;
			var minvalue = this.className.match(/\bminvalue-(\d+)\b/) ? parseFloat(this.className.match(/\bminvalue-(\d+)\b/)[1]) : 0;
			var maxvalue = this.className.match(/\bmaxvalue-(\d+)\b/) ? parseFloat(this.className.match(/\bmaxvalue-(\d+)\b/)[1]) : Infinity;

			var thisMatch = this.value.replace(/[\D]/g, "").match(/\d+/);

			if (thisMatch && thisMatch[0].length >= minlength && parseFloat(thisMatch[0]) >= minvalue && parseFloat(thisMatch[0]) <= maxvalue)
			{
				this.value = thisMatch[0];
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(
					this,
					OneNet.Utility.String.format(OneNet.Constants.Forms.invalidDigits, "{0}", minvalue, maxvalue));
			}
		}
	},

	validateCharacters: function()
	{
		/// <summary>Validates length of characters for text field</summary>
		/// <remarks>minlength and maxlength can be set in className, e.g. class="characters minlength-4 maxlength-2100"</remarks>

		if (this.value !== "")
		{
			var minlength = this.className.match(/\bminlength-(\d+)\b/) ? parseFloat(this.className.match(/\bminlength-(\d+)\b/)[1]) : 0;
			var maxlength = this.className.match(/\bmaxlength-(\d+)\b/) ? parseFloat(this.className.match(/\bmaxlength-(\d+)\b/)[1]) : 999999999999999;

			if (this.value.length < minlength || this.value.length > maxlength)
			{
				OneNet.Utility.Forms.Validation.showError(
					this,
					OneNet.Utility.String.format(OneNet.Constants.Forms.invalidCharacters, "{0}", minlength, maxlength));
			}
		}
	},

	/// validateEmail - Validate & format text field vaue as Email
	validateEmail: function()
	{
		if (this.value !== "")
		{
			var trimmedValue = OneNet.Utility.String.trim(this.value);

			if (trimmedValue.match(OneNet.Constants.Forms.emailAddressRegExp))
			{
				this.value = trimmedValue;
			}

			else
			{
				OneNet.Utility.Forms.Validation.showError(this, OneNet.Constants.Forms.invalidEmail);
			}
		}
	},

	/// showError - Show alert message with field label text and error message
	/// param: formField, htmlElement
	/// param: errorMessage, string
	showError: function(formField, errorMessage)
	{
		var labelText = OneNet.Utility.Forms.getLabelText(formField);

		if (labelText === "")
		{
			labelText = OneNet.Constants.Forms.defaultFormFieldName;
		}

		formField.select();
		alert(OneNet.Utility.String.format(errorMessage, labelText));
	},

	//the submit button that was clicked for the required field event handler functions.
	_submitButtonClicked: null,

	/// setRequiredFieldEventHandlers
	setRequiredFieldEventHandlers: function()
	{
		var forms = document.getElementsByTagName("form");

		for (var i = 0, n = forms.length; i < n; i++)
		{
			if (OneNet.Utility.DOM.hasClass(forms[i], OneNet.Constants.Forms.formWithRequiredFieldsClass))
			{
				forms[i].onsubmit = OneNet.Utility.Forms.Validation.checkForRequiredFieldsEventHandler;
				var inputs = forms[i].getElementsByTagName("input");

				for (var j = 0, m = inputs.length; j < m; j++)
				{
					if (inputs[j].type.match(/submit/i) && OneNet.Utility.DOM.hasClass(inputs[j], OneNet.Constants.Forms.checkForRequiredFieldsButtonClass))
					{
						inputs[j].onclick = OneNet.Utility.Forms.Validation.captureSubmitButtonClick;
					}
				}
			}
		}
	},

	/// checkForRequiredFieldsEventHandler
	checkForRequiredFieldsEventHandler: function()
	{
		var returnValue = OneNet.Utility.Forms.Validation.checkForRequiredFields(OneNet.Utility.Forms.Validation._submitButtonClicked);
		OneNet.Utility.Forms.Validation._submitButtonClicked = null;
		return returnValue;
	},

	/// checkForRequiredFields
	/// note: This method differs from OneNet.Utility.Forms.Validation.checkForRequiredFieldsEventHandler since it does not require an onsubmit on the form and onclick events on the submit button.
	checkForRequiredFields: function(submitButton)
	{
		if (submitButton === null)
		{
			return true;
		}

		var fields = submitButton.form.elements;
		var invalidFields = [];

		for (var i = 0, n = fields.length; i < n; i++)
		{
			// hidden and invisible elements (should) have no offsetHeight
			if (OneNet.Utility.DOM.hasClass(fields[i], OneNet.Constants.Forms.requiredFormFieldClass) && (fields[i].offsetHeight || OneNet.Utility.DOM.hasClass(fields[i], OneNet.Constants.Forms.requiredFormFieldEvenWhenHiddenClass)))
			{
				var type = fields[i].tagName.toLowerCase();

				if ((type === "input" || type === "textarea" || type === "select") && OneNet.Utility.String.trim(fields[i].value) === "")
				{
					invalidFields.push(OneNet.Utility.Forms.getLegendAndLabelText(fields[i]));
				}
			}
		}

		if (invalidFields.length === 0)
		{
			return true;
		}

		else
		{
			alert(OneNet.Utility.String.format(
				invalidFields.length === 1 ? OneNet.Constants.Forms.singleMissingRequiredFieldMessage : OneNet.Constants.Forms.multipleMissingRequiredFieldsMessage,
				invalidFields.join("\r\n")));

			return false;
		}
	},

	///	captureSubmitButtonClick
	captureSubmitButtonClick: function()
	{
		OneNet.Utility.Forms.Validation._submitButtonClicked = this;
	}
};

/// TODO: Perhaps these functions should get prototyped on the window.location object instead? Is this even possible?
OneNet.Utility.QueryString = OneNet.Utility.QueryString ||
{
	/// queryString
	/// param: key, string
	/// url: The url to get the query string value for. If this paramter is not present then the current window's location will be used.
	/// returns: string. If the key is not in the query string an empty string is returned (NOTE: should this be changed to a NULL value?)
	/// NOTE: if the query string is URL encoded wrap the return value in a decodeURIComponent function call (for ex. decodeURIComponent(OneNet.Utility.QueryString.getValue("Name"))).
	getValue: function(key, url)
	{
		if (typeof url === "undefined")
		{
			url = window.location.search;
		}

		var match = url.match(new RegExp("\\b" + key + "=([^&]*)", "i"));

		//TODO: If the key does not appear in the query string should we return null instead of an empty string?
		return match && match[1] ? unescape(match[1]) : "";
	}
};

// TODO: Rename this namespace to something else?
// TODO: Perhaps these functions should get prototyped on the XMLHttpRequest object instead.
OneNet.Utility.Http = OneNet.Utility.Http ||
{
	/// Http.post
	/// param: url, string
	/// param: parameters, string
	/// param: callBackFunction, function
	/// param: doAsynchronousRequest, boolean (default = true)
	post: function(url, parameters, callbackFunction, doAsynchronousRequest)
	{
		var request = new XMLHttpRequest();
		doAsynchronousRequest = typeof(doAsynchronousRequest) !== "undefined" ? doAsynchronousRequest : true;
		request.open("POST", url, doAsynchronousRequest);
		request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

		if (doAsynchronousRequest === true)
		{
			request.onreadystatechange = function()
			{
				if (request.readyState === 4 && request.status === 200 && callbackFunction !== null)
				{
					callbackFunction(request);
				}
			};
		}

		try
		{
			request.send(parameters);

			if (doAsynchronousRequest === false)
			{
				callbackFunction(request);
			}
		}

		catch(error)
		{
			alert(OneNet.Utility.String.format(OneNet.Constants.Http.errorCommunicatingWithServer, request.status));
		}
	},

	/// Http.addPostParameter - Adds an url encoded parameter to the end of a POST url string.
	/// param: postParameter, string
	/// param: parameterName, string
	/// param: parameterValue, string
	/// returns: string
	addPostParameter: function(postParameters, parameterName, parameterValue)
	{
		return postParameters + (postParameters.length > 0 ? "&" : "") + encodeURIComponent(parameterName) + "=" + encodeURIComponent(parameterValue);
	},

	/// get
	/// param: url, string
	/// param: callBackFunction, function
	/// param: doAsynchronousRequest, boolean (default = true)
	get: function(url, callbackFunction, doAsynchronousRequest)
	{
		var request = new XMLHttpRequest();
		doAsynchronousRequest = typeof(doAsynchronousRequest) !== "undefined" ? doAsynchronousRequest : true;

		request.open("GET", url, doAsynchronousRequest);

		if (doAsynchronousRequest === true)
		{
			request.onreadystatechange = function()
			{
				if (request.readyState === 4 && callbackFunction !== null)
				{
					callbackFunction(request);
				}
			};
		}

		try
		{
			request.send(null);

			if (doAsynchronousRequest === false)
			{
				callbackFunction(request);
			}
		}

		catch(error)
		{
			alert(OneNet.Utility.String.format(OneNet.Constants.Http.errorCommunicatingWithServer, request.status));
		}
	},

	/// Http.addGetParameter - Adds an url encoded parameter to the end of a GET url string.
	/// param: url, string
	/// param: parameterName, string
	/// param: parameterValue, string
	/// returns: string
	addGetParameter: function(url, parameterName, parameterValue)
	{
		return url + (url.indexOf("?") === -1 ? "?" : "&") + encodeURIComponent(parameterName) + "=" + encodeURIComponent(parameterValue);
	},

	///	getPostParameters - Gets the post parameters out of the form object passed in.
	///	param: form, Form object - The form containing the fields to get the post parameters for.
	///	returns: string - the string containing the post parameters for the form.
	getPostParameters: function(form)
	{
		//only include parameters for the form fields that contain the name attribute
		//do not include buttons in the post parameters.
		var postParameters = "";
		for(var i = 0; i < form.elements.length; i++)
		{
			if(form.elements[i].getAttributeNode("name") !== null && form.elements[i].name !== "" && form.elements[i].type.toLowerCase() !== "button" && form.elements[i].type.toLowerCase() !== "submit" && (form.elements[i].type.toLowerCase() !== "checkbox" || form.elements[i].checked === true))
			{
				//TODO: is there a bug with checkboxes in this code. Do they have a value property?
				//I think by default checkboxes pass in a value of "on" when they are checked.
				postParameters = OneNet.Utility.Http.addPostParameter(postParameters, form.elements[i].name, form.elements[i].value);
			}
		}

		return postParameters;
	}
};

/// TODO: Is there a better name for this namespace?
/// NOTE: Perhaps this shouldn't go in the Utility Namespace since it is dependent on our CMS. Other CMS won't have the same div ids.
/// Perhaps this should go in a OneNet.Sizing namespace.
OneNet.Utility.Sizing = OneNet.Utility.Sizing ||
{
	/// getBrowserHeight
	/// returns: integer
	/// TODO: Put in namespace OneNet.Utility.DOM?
	getBrowserHeight: function()
	{
		if (window.innerHeight) // W3C
		{
			return window.innerHeight;
		}

		else if (document.documentElement.offsetHeight) // IE 6 & 7
		{
			return document.documentElement.offsetHeight;
		}

		else if (document.body.offsetHeight) // IE 5
		{
			return document.body.offsetHeight;
		}

		return 0;
	},

	/// getBrowserWidth
	/// returns: integer
	/// TODO: Put in namespace OneNet.Utility.DOM?
	getBrowserWidth: function()
	{
		if (window.innerWidth) // W3C
		{
			return window.innerWidth;
		}

		else if (document.documentElement.offsetWidth) // IE 6 & 7
		{
			return document.documentElement.offsetWidth;
		}

		else if (document.body.offsetWidth) // IE 5
		{
			return document.body.offsetWidth;
		}

		else
		{
			return 0;
		}
	},

	/// getBorderHeight - Returns total height of element's top & bottom borders in pixels (integer)
	getBorderHeight: function(element)
	{
		if(element === null)
		{
			return 0;
		}

		else if(element.currentStyle) // IE 5 & 6
		{
			return(OneNet.Utility.Sizing.getSizeInPixels(element.currentStyle.borderTopWidth) + OneNet.Utility.Sizing.getSizeInPixels(element.currentStyle.borderBottomWidth));
		}

		else if(document.defaultView && document.defaultView.getComputedStyle) // W3C
		{
			return(OneNet.Utility.Sizing.getSizeInPixels(document.defaultView.getComputedStyle(element, null).getPropertyValue("border-top-width")) + OneNet.Utility.Sizing.getSizeInPixels(document.defaultView.getComputedStyle(element, null).getPropertyValue("border-bottom-width")));
		}

		else
		{
			return 0;
		}
	},

	/// getMarginHeight - Returns total height of element's top & bottom margins in pixels (integer)
	getMarginHeight: function(element)
	{
		if(element === null)
		{
			return 0;
		}

		else if(element.currentStyle) // IE 5 & 6
		{
			return(OneNet.Utility.Sizing.getSizeInPixels(element.currentStyle.marginTop) + OneNet.Utility.Sizing.getSizeInPixels(element.currentStyle.marginBottom));
		}

		else if(document.defaultView && document.defaultView.getComputedStyle) // W3C
		{
			return(OneNet.Utility.Sizing.getSizeInPixels(document.defaultView.getComputedStyle(element, null).getPropertyValue("margin-top")) + OneNet.Utility.Sizing.getSizeInPixels(document.defaultView.getComputedStyle(element, null).getPropertyValue("margin-bottom")));
		}

		else
		{
			return 0;
		}
	},

	/// getPaddingHeight - Returns total height of the element's top and bottom paddings in pixels (integer)
	getPaddingHeight: function(element)
	{
		if(element === null)
		{
			return 0;
		}

		else if(element.currentStyle) // IE 5 & 6
		{
			return(OneNet.Utility.Sizing.getSizeInPixels(element.currentStyle.paddingTop) + OneNet.Utility.Sizing.getSizeInPixels(element.currentStyle.paddingBottom));
		}

		else if(document.defaultView && document.defaultView.getComputedStyle) // W3C
		{
			return(OneNet.Utility.Sizing.getSizeInPixels(document.defaultView.getComputedStyle(element, null).getPropertyValue("padding-top")) + OneNet.Utility.Sizing.getSizeInPixels(document.defaultView.getComputedStyle(element, null).getPropertyValue("padding-bottom")));
		}

		else
		{
			return 0;
		}
	},

	/// getSizeInPixels - Returns numeric portion of string in format "#px"
	/// TODO: Replace with getPixelWidth?
	getSizeInPixels: function(styleString)
	{
		return(styleString.indexOf("px") !== -1) ? parseInt(styleString, 10) : 0;
	},

	/// getPixelWidth - Returns the width of an element's style property in pixels, or 0 if it cannot be determined
	/// param: element, htmlElement
	/// param: property, string - CSS property name in JavaScript format (e.g., marginLeft, borderRightWidth)
	/// returns: float
	/// note: in IE, CSS properties must be set in pixels for getPixelWidth to return a value
	/// TODO: Put in namespace OneNet.Utility.DOM?
	getPixelWidth: function(element, property)
	{
		var value = "";
		if (element.currentStyle)
		{
			value = element.currentStyle[property];
		}
		else if (document.defaultView)
		{
			property = property.replace(/([A-Z])/g, "-$1").toLowerCase();
			value = document.defaultView.getComputedStyle(element, null).getPropertyValue(property);
		}

		return parseFloat("0" + value.match(/.*\dpx/));
	}
};

OneNet.Utility.Events = OneNet.Utility.Events ||
{
	addEventHandler: function (target, eventType, functionHandler)
	{
		if (target.addEventListener)
		{
			target.addEventListener(eventType, functionHandler, false);
		}

		else if (target.attachEvent)
		{
			target.attachEvent("on" + eventType, functionHandler);
		}

		else
		{
			target["on" + eventType] = functionHandler;
		}
	},

	removeEventHandler: function (target, eventType, functionHandler)
	{
		if (target.removeEventListener)
		{
			target.removeEventListener(eventType, functionHandler, false);
		}

		else if (target.detachEvent)
		{
			target.detachEvent("on" + eventType, functionHandler);
		}

		else
		{
			target["on" + eventType] = null;
		}
	},

	formatEvent: function (e)
	{
		/// <summary>Formats an IE event object to act like a DOM event object</summary>
		/// <param name="element" type="EventElement">The event to format</param>

		e.charCode = e.type === "keypress" || e.type === "keydown" || e.type === "keyup" ? e.keyCode : 0;
		e.eventPhase = 2;
		e.isChar = (e.charCode > 0);
		e.pageX = e.clientX + document.body.scrollLeft;
		e.pageY = e.clientY + document.body.scrollTop;

		e.preventDefault = function ()
		{
			this.returnValue = false;
		};

		if (e.type === "mouseout")
		{
			e.relatedTarget = e.toElement;
		}

		else if (e.type === "mouseover")
		{
			e.relatedTarget = e.fromElement;
		}

		e.stopPropagation = function ()
		{
			this.cancelBubble = true;
		};

		e.target = e.srcElement;
		e.time = (new Date()).getTime();

		return e;
	},

	/// getEvent - Returns an event object that is modified in IE to enable cross browser event handling.
	/// parameter: a list of objects that might of thrown the current event (for example, an iframe). NOTE: by default this function checks if the current window threw the event.
	getEvent: function()
	{
		var eventToReturn = null;

		for (var i = 0, n = arguments.length; i < n; i++)
		{
			if (arguments[i] !== null)
			{
				eventToReturn = arguments[i];
				break;
			}
		}

		if (eventToReturn === null)
		{
			eventToReturn = window.event;
		}

		if (eventToReturn)
		{
			return OneNet.Utility.Helper.isIE() === true ? this.formatEvent(eventToReturn) : eventToReturn;
		}

		else
		{
			return OneNet.Utility.Events.getEvent.caller.arguments[0];
		}
	/*
		if (window.event) {
			return this.formatEvent(window.event);
		} else {
			return OneNet.Utility.Events.getEvent.caller.arguments[0];
		}
	*/
	}
};

/// TODO: Need to categorize the functions that are in this namespace (and possibly give it a different name)
OneNet.Utility.Helper = OneNet.Utility.Helper ||
{
	refreshJawsBuffer: function(theWindow)
	{
		/// <summary>Prompts the JAWS screen reader to refresh its virtual buffer</summary>
		/// <remarks>Call this method if JAWS doesn't recognize elements added or removed using appendChild, insertBefore, or removeChild.</remarks>
		/// <param name="theWindow">The window that needs its buffer refreshed />
		theWindow = theWindow || window;
		theWindow.setTimeout(function () { theWindow.document.body.removeChild(theWindow.document.body.appendChild(theWindow.document.createElement("div"))); }, 1000); // delay must be at least 1000 ms
	},

	/// isIE - Returns a boolean value indicating if the current browser is Internet Explorer.
	isIE: function()
	{
		return navigator.userAgent.indexOf("MSIE") !== -1;
	},

	getIEVersion: function()
	{
		var ieVersion = navigator.userAgent.match(/MSIE ([^;]+);/i);
		return ieVersion ? ieVersion[1] : "";
	},

	/// isPostBack - Indicates whether the page has posted to itself
	/// param: postBackURL, string optional - The url of the previous page. If this isn't defined then it will default to document.referrer.
	/// returns: boolean
	isPostBack: function(postBackURL)
	{
		if (typeof postBackURL === "undefined")
		{
			postBackURL = document.referrer;
		}

		return window.location.href === postBackURL;
	},

	/// setLongdescLinkEventHandlers
	setLongdescLinkEventHandlers: function() {
		var links = document.getElementsByTagName("a");

		for (var i = 0, n = links.length; i < n; i++)
		{
			if (OneNet.Utility.DOM.hasClass(links[i], "longdescLink") === true)
			{
				var match = links[i].hash.match(/#(for_(img\d+))/);

				if (match)
				{
					var imageId = match[2];
					var longdescId = match[1];

					if (imageId && longdescId)
					{
						var image = document.getElementById(imageId);
						var longdesc = document.getElementById(longdescId);

						if (image && longdesc)
						{
							links[i].onclick = OneNet.Utility.Helper.openLongdescWindow;
							longdesc.className = "hidden";
						}
					}
				}
			}
		}
	},

	/// openLongdescWindow
	/// param: this, element (implicit)
	openLongdescWindow: function()
	{
		//TODO: Need to fix this in the case where a friendly url is used along with a virtual directory.
		window.open("/Core/Common/longdesc.html" + this.hash, "longdesc", "width=600,height=400,directories=no,fullscreen=no,location=no,menubar=no,resizable=yes,scrollbars=yes,status=yes,toolbar=no");
		return false;
	},

	/// openDialogWindow: Opens a new dialog window using the window properties defined by OneNet.Constants.Helper.dialogWindowProperties
	/// returns: The window object that was opened.
	openDialogWindow: function(url, windowName)
	{
		windowName = windowName || "";
		var windowToReturn = window.open(url, windowName, OneNet.Constants.Helper.dialogWindowProperties);
		windowToReturn.focus();
		return windowToReturn;
	},

	/// getNextFocusableElement - Returns the next focusable element that appears in the reading order after the input parameter
	/// param: currentElement (optional), element - If this parameter is present then the next focusable element that appears in the reading order will be returned
	/// If this parameter is not present then the first focusable element in the reading order will be returned.
	getNextFocusableElement: function(currentElement)
	{
		var elements = document.getElementsByTagName("*");
		var focusableTagNames = ["a", "button", "input", "select", "textarea"];
		var indexToCheck = 0;
		var i, n;

		if (typeof currentElement !== "undefined")
		{
			for (i = 0, n = elements.length; i < n; i++)
			{
				if (elements[i] === currentElement)
				{
					indexToCheck = i + 1;
					break;
				}
			}
		}

		for (i = indexToCheck, n = elements.length; i < n; i++)
		{
			if (elements[i].offsetHeight) // invisible elements (should) have no offsetHeight
			{
				if (focusableTagNames.isInArray(elements[i].tagName.toLowerCase()) === true)
				{
					return elements[i];
				}

				//see if the element is focusable by checking if it has a tabindex attribute set on it or if one of its parent elements is focusable by the tabindex property.
				//In internet explorer you can't just check the tabindex property of an element because by default it will return '0'.
				//The trick is to see if it has a tabindex property as an attribute in the elements outerHTML.
				//TODO: Since this function uses outerHTML it will fail in browsers like Mozilla unless we define what the outerHTML property should be.
				var index = elements[i].outerHTML.indexOf(">");

				if(index === -1)
				{
					index = elements[i].outerHTML.indexOf("/>");
				}

				if (elements[i].outerHTML.substring(0, index).toLowerCase().indexOf(" tabindex=") > -1)
				{
					return elements[i];
				}
			}
		}

		return null;
	},

	setConstantValues: function(dropDownList, textNodeIsConstantAlso)
	{
		textNodeIsConstantAlso = textNodeIsConstantAlso || false;
		var options = dropDownList.options;

		for (var i = 0, n = options.length; i < n; i++)
		{
			var constantValue = null;

			if (options[i].value !== "")
			{
				window.eval("constantValue = " + options[i].value + ";");
				options[i].value = constantValue;
			}

			if (options[i].text !== "" && textNodeIsConstantAlso === true)
			{
				window.eval("constantValue = " + options[i].text + ";");
				options[i].text = constantValue;
			}
		}
	}
};
