/* CLASSES */

	var aCachedREs = new Array();
	function classCacheRE(sClass) {
		if(!aCachedREs[ sClass ])
			aCachedREs[ sClass ] = new RegExp('^\\s*(.*)\\b('+ sClass +')\\b(.*)\\s*$');
		return( aCachedREs[ sClass ] );
	}

	function classMatch(oObject, sClass) {
		if(oObject && oObject.className)
			return(classCacheRE(sClass).exec(oObject.className));
		return(false);
	}

	function classAdd(oObject, sClass) {
		if(oObject && !classMatch(oObject, sClass))
			oObject.className += ' '+ sClass;
	}

	function classDel(oObject, sClass) {
		var aMatches = classMatch(oObject, sClass);
		if(aMatches)
			oObject.className = aMatches[1] + aMatches[ aMatches.length - 1 ];
	}

/* BY CLASS NAME */

	// Moz or IE.6
	if(!navigator.userAgent.match(/MSIE/) ||
		navigator.userAgent.match(/MSIE 6\./)) {

		function getElementsByClassName(sClassName, oObject, bNoRecursion) {
			var aoReturnValue = new Array();

			// Default the object to the document
			if(!oObject) {
				oObject = document.body;
			}

			// Recursion: get all the elements and run through them
			if(!bNoRecursion) {
				var aoElements = oObject.getElementsByTagName('*');
				for(var iElement = 0; iElement < aoElements.length; iElement++) {
					if(classMatch(aoElements[ iElement ], sClassName)) {
						aoReturnValue.push( aoElements[ iElement ] );
					}
				}

			// No recursion: Just run run through all the children
			} else {
				for(var oChild = oObject.firstChild; oChild; oChild = oChild.nextSibling) {
					if(classMatch(oChild, sClassName)) {
						aoReturnValue.push(oChild);
					}
				}
			}

			return(aoReturnValue);
		}

	// IE 5.x
	} else {
		function getElementsByClassName(sClassName, oObject, bNoRecursion) {
			var aoReturnValue = new Array();

			// Object supplied
			if(oObject) {
				for(var oChild = oObject.firstChild; oChild; oChild = oChild.nextSibling) {
					if(classMatch(oChild, sClassName)) {
						aoReturnValue.push(oChild);
					}

					// Recurse if possible / allowed
					if(oChild.hasChildNodes() && !bNoRecursion) {
						aoReturnValue = aoReturnValue.concat( getElementsByClassName(sClassName, oChild) );
					}
				}

			// No object and *no* recursion: Just run run through all the children
			} else if(bNoRecursion) {
				for(var oChild = document.body.firstChild; oChild; oChild = oChild.nextSibling) {
					if(classMatch(oChild, sClassName)) {
						aoReturnValue.push(oChild);
					}
				}

			// No object and recursion: get all the elements and run through them
			} else {
				for(var iElement = 0; iElement < document.all.length; iElement++) {
					if(classMatch(document.all[ iElement ], sClassName)) {
						aoReturnValue.push(document.all[ iElement ]);
					}
				}
			}

			return(aoReturnValue);
		}
	}

/* IN ARRAY */

	function bInArray(mNeedle, aHaystack) {
    	for (var i = 0; i < aHaystack.length; i++) {
        	if (aHaystack[i] == mNeedle) {
            	return true;
        	}
    	}
    	return false;

	}

/* EVENTS */

	function bAddEvent(oObj, sType, fCallBack){
		if (oObj.addEventListener){
			oObj.addEventListener(sType, fCallBack, false);
			return true;
		} else if (oObj.attachEvent){
			var bRet = oObj.attachEvent("on"+sType, fCallBack);
			return bRet;
		} else {
			return false;
		}
	}

/* CHAINING */

	function processChain(aChain) {
		// Run each init routine in the chain
		if(aChain) {
			for(var iFunc = 0; iFunc < aChain.length; iFunc++) {
				aChain[ iFunc ]();
			}
		}
	}

	function addToOnPreLoadChain(oObject, pFunction) {
		// Add a function to the chain of things to run
		if(!oObject.aPreOnLoadFuncs) {
			oObject.aPreOnLoadFuncs = new Array();
		}
		oObject.aPreOnLoadFuncs.push( pFunction );
	}

	function addToOnLoadChain(oObject, pFunction) {
		// Add a function to the chain of things to run
		if(!oObject.aOnLoadFuncs) {
			oObject.aOnLoadFuncs = new Array();
		}
		oObject.aOnLoadFuncs.push( pFunction );
	}

	function processOnLoadChain() {
		// Process the pre-onLoad chain and then the onLoad chain
		processChain(this.aPreOnLoadFuncs);
		processChain(this.aOnLoadFuncs);
	}

	// Set the above function to be the window's onLoad handler
	//window.onload = new Function('', 'setTimeout(processOnLoadChain, 250);');
	window.onload = processOnLoadChain;

/* FORM FIELD CHANGES WARNING */

	// This variable can be used to turn off warnings when not appropriate
	window.bUseWarnings = true;

	// This is used to keep a track of changes that are made
	window.iFieldChanges = 0;

	// This is the warning that will be show to users when they haven't saved
	// their changes. It can be overwritten later if needed.
	window.sWarningMessage = 'You have made changes that have not been saved, if you navigate away from this page they will be discarded. To save your changes click the "Save Changes" button at the bottom of the page.';

	window.onbeforeunload = function() {
	
		if (this.bUseWarnings && this.iFieldChanges > 0)
			return window.sWarningMessage;

	};

	function vInitChangesWarn() {

		// This function sets event handlers on all form elements that track when changes
		// are made. Changes are ignored if the user is trying to submit (save) the form.

		var aoInputs = document.getElementsByTagName('input');

		for (var i = 0; i < aoInputs.length; i++) {

			switch (aoInputs[i].type) {

				case 'submit':
				case 'image':
					// If this "input" is an image/submit button then clear the exit
					// warning as they're trying to save changes
					aoInputs[i].onclick = function() { window.iFieldChanges = 0; return true; };
					break;

				default:
					aoInputs[i].onchange = function() { window.iFieldChanges++; return true; };
					break;

			}

		}

		// Don't forget about selects...
		var aoSelects = document.getElementsByTagName('select');
		for (var i = 0; i < aoSelects.length; i++) {
			aoSelects[i].onchange = function() { window.iFieldChanges++; return true; };
		}

	}

	addToOnLoadChain(window, vInitChangesWarn);
