// *** BROWSER DETECTION VARIABLES ***
// Requires: None.

// isDOM: W3C-DOM compatible browser? (IE5+, NS6+, others like Opera, Konqueror, etc...)
// isIE: Internet Explorer (v4 and up), also Opera emulating it.
// isIE4, isNS4: Each of the 4-series browsers (not DOM compatible).
// isOp: Any Opera version (useful as Opera emulates IE above).
// isWin: True is Windows, false if Mac/Linux etc.
// isDyn: Any DHTML-capable browser.

var isDOM=document.getElementById?1:0,
	isIE=document.all?1:0,
	isNS4=navigator.appName=='Netscape'&&!isDOM?1:0,
	isIE4=isIE&&!isDOM?1:0,
	isOp=self.opera?1:0,
	isDyn=isDOM||isIE||isNS4,
	isWin=navigator.platform.indexOf('Win')!=-1?1:0;


/* String Functions */
String.prototype.trim = function() {
	//trims whitespace from the beginning and end of a string
	return this.replace(/^\s+/,'').replace(/\s+$/,'');
}


/* DOM Functions */
function getParentNode(thisNode) {
	//returns the parent node of thisNode
	if(isIE)
		return thisNode.parentElement;
	else
		return thisNode.parentNode;
}


/* Event Handler Functions */
function modifyEventHandler(obj, eventName, newFunction, addToLocation) {
	/*
		This function will do one of the following to modify the event handler:
		1. Add a newFunction before the current eventHandler.
		2. Add a newFunction after the current eventHandler.
		3. Replace the current eventHandler with a newFunction.
	*/
	if(typeof newFunction != "function")
		return;
	
	var oldEventHandler = obj[eventName];
	if(!oldEventHandler)
		addToLocation = "replace";
	
	if(addToLocation == "replace") {
		//set the newEventHandler to the newFunction
		var newEventHandler = newFunction;
	} else if(addToLocation == "after") {
		//make the newEventHandler a function that runs the oldEventHandler first
		//if the oldEventHandler doesn't return false, run and return the value of the newFunction
		var newEventHandler = function() {
			var returnValue = oldEventHandler();
			if(returnValue == false)
				return false;
			return newFunction();
		}
	} else {
		//make the newEventHandler a function that runs the newFunction first
		//if the newFunction doesn't return false, run and return the value of the oldEventHandler
		var newEventHandler = function() {
			var returnValue = newFunction();
			if(returnValue == false)
				return false;
			return oldEventHandler();
		}
	}
	
	obj[eventName] = newEventHandler;
}


/* Form and Element Functions */
function getNameOrId(formObject) {
	//returns the name of the form object
	//if it has no name, it returns the id of the form object
	var nameOrId = formObject.name;
	if(!nameOrId)
		nameOrId = formObject.id;

	return nameOrId;
}
	
function getErrorLabel(thisElement) {
	/*
		An errorLabel is the errorLabel defined in the tag.
		If no errorLabel is defined, it is the name of the tag.
		If no name is defined, it is the id of the tag.
	*/
	
	var errorLabel = thisElement.getAttribute("errorLabel");
	if(!errorLabel)
		errorLabel = getNameOrId(thisElement);

	return errorLabel;
}

function getStrictDisabled(thisElement) {
	/*
		Returns whether the element has strict checking disabled.
		This function first checks if disableStrictCheck is defined on the element.
		If it's not defined on the element, it will check the form next.
		If it's not defined on the form, then strict checking is not disabled (it's ON by default).
	*/
	var strictDisabled = thisElement.getAttribute("disableStrictCheck");
	if(!strictDisabled)
		strictDisabled = thisElement.form.getAttribute("disableStrictCheck");
	if(!strictDisabled)
		strictDisabled = false;
	return (strictDisabled == "true");
}

function getElementLength(thisElement, strictDisabled) {
	/*
		Returns a length value depending on the element type.
		Defaults to null if the type is not listed.
		
		TEXT VALUES:
			No Strict Checking - the length of the value of the field
			Strict Checking - the length of the value of the field after trimming it
		
		RADIO/CHECKBOX:
			Checked - 1
			Unchecked - 0
			
		SELECT BOX:
			No Strict Checking - the number of selected options
			Strict Checking - the number of selected options which do not have invalidOption set to true
	*/
	
	//if strictDisabled is not defined, set it
	if(strictDisabled == null)
		strictDisabled = getStrictDisabled(thisElement);
		
	switch(thisElement.type) {
		case ('file'):
		case ('hidden'):
		case ('textarea'):
		case ('password'):
		case ('text'):		
			if(!strictDisabled)
				return thisElement.value.trim().length;
			else
				return thisElement.value.length;
		
		case ('radio'):
		case ('checkbox'):
			var invalidOption = (thisElement.getAttribute("invalidOption") == "true");
			if (invalidOption) {
				return 0;
			} else {
				return thisElement.checked?1:0;
			}
			
		case ('select-one'):
		case ('select-multiple'):
			var numberOfSelectedOptions = 0;
			for(var i=0; i<thisElement.options.length; i++) {
				var selOption = thisElement.options[i];
				var invalidOption = (selOption.getAttribute("invalidOption") == "true");
				if(selOption.selected && (strictDisabled || !invalidOption))
					numberOfSelectedOptions++;
			}
			return numberOfSelectedOptions;
		
		default:
			//return null if the type is not listed
			return null;
			
	}
}

function isFieldEmpty(thisElement, strictDisabled) {
	/*
		Returns whether or not the element's length is equal to 0.
		Defaults to false if the type is not listed.
	*/
	
	// if the element is disabled, then it wont be submitted so it cant fulfill a requirement
	if (thisElement.disabled) {
		return true;
	}
			
	switch(thisElement.type) {
		case ('file'):
		case ('hidden'):
		case ('textarea'):
		case ('text'):
		case ('password'):
		case ('radio'):
		case ('checkbox'):
		case ('select-one'):
		case ('select-multiple'):
			return getElementLength(thisElement, strictDisabled) == 0;
			
		default:
			//return false if the type is not listed
			return false;
	}
}
	
function changeElementClass(thisElement, newClass) {
	/*
		This function changes the class of an element or a label (if the element is a checkbox or radio button) if it is not already that class.
	*/
	if(thisElement.className != newClass) {
		switch(thisElement.type) {
			case ('radio'):
			case ('checkbox'):
				var parentElement = getParentNode(thisElement);
				if((parentElement.tagName.toUpperCase() == 'LABEL') && (parentElement.className != newClass)) {
					parentElement.className = newClass;
				}
				break;
			case ('file'):
			case ('textarea'):
			case ('text'):
			case ('password'):
			case ('select-one'):
			case ('select-multiple'):
				thisElement.className = newClass;
		}
	}
}