var formValidator = new Object();
var messagingAvailable;

formValidator = {

	FORMS : [],
	VALIDATORS : [],
	messagingAvailable : messagingAvailable,
	
	isNS4 :  (document.layers) ? true : false,
	isIE4 : (document.all && !document.getElementById) ? true : false,
	isIE5 : (document.all && document.getElementById) ? true : false,
	isNS6 : (!document.all && document.getElementById) ? true : false,
	
	className: "clearfix inline-message-container",
	messageContainer: null,
	
	autoWireup : function() {
		formValidator.FORMS = document.getElementsByTagName("form");
		
		if (formValidator.FORMS.length) {
			// loop over the forms and add validation
			for (var i = 0; i < formValidator.FORMS.length; i++) {
				// check to see if there's any required fields
				if (formValidator.FORMS[i].getElementsByClassName("required").length) {
					Event.observe(formValidator.FORMS[i], "submit", formValidator.validate);
				}
			}
			
		}
	},
	
	wireup : function(oForm) {
		if (typeof oForm == "string") {
			oForm = document.getElementById(oForm);
		}
		
		if (oForm) {
			formValidator.FORMS[formValidator.FORMS.length] = oForm;
			Event.observe(oForm, "submit", formValidator.validate);
		}
	},
	
	validate : function(e) {
		formValidator.initValidators();
			
		var result = null;
		var arrClasses = [];
		var arrReturn = [];
		
		if (!formValidator.FORMS.length) {
			//alert("retutn no len");
			return;
		}
		
		
		for (var i = 0; i < formValidator.FORMS.length; i++) {
			var oForm = formValidator.FORMS[i];
			var oMessageDiv = null; 	// used to show a neato status message if found.
			var arrReqElements = oForm.getElementsByClassName("required");
			var strMessage = "";
					
			// if there are required elements
			if (arrReqElements.length) {
			
				// loop over the required fields and ensure they are filled out
				for (var j = 0; j < arrReqElements.length; j++) {
					
					// put the classes for this field inot an array
					arrClasses = arrReqElements[j].className.split(" ");
					
					// loop the array and find something to validate
					for (var c = 0; c < arrClasses.length; c++) {	
						if (arrClasses[c] != "required") {
							// alert("chcking class: " + arrClasses[c])
							if (formValidator.messagingAvailable) {
								oMessageDiv = document.getElementById(arrReqElements[j].id + "-message");
								if (oMessageDiv) {
									oMessageDiv.parentNode.removeChild(oMessageDiv);
								}
							}
							
							// get the validation results 
							result = formValidator.checkClass(arrReqElements[j], arrClasses[c]);			
							
							// if we got a negative result - return it out.
							if (! result.passed) {
								formValidator.displayMessage(arrReqElements[j], result);		
								Event.stop(e);
							}
						}
					}
					
				}	
			}
			
			if (arrReturn.length) {
			//	alert("The following error prevented this form from submitting:" + strMessage);
				break;	
			}
			
		}
		
		
	},	
	
	displayMessage : function(o, result) {
		var strMessage = "";
		var arrReturn = [];
		
		oMessageDiv = document.createElement("div");
		oMessageDiv.id = o.id + "-message";
		oMessageDiv.className = formValidator.className;
		
		// append this div after the form element
		if (o && document.getElementById(o.id)) {
			o.parentNode.appendChild(oMessageDiv);
		}
		
		//alert("negative event found -= stopping : " + Event);
		arrReturn[arrReturn.length] = { id: o.id, message: result.message };
		
		strMessage += "\n" + o.id + " " + result.message;
		
		if (o && formValidator.messagingAvailable) {
			messageObj = { messageCode:result.code, type:"exception", message:result.message, detail: result.detail, container: "message-shell"};
			appendMessage(oMessageDiv, messageObj);
		}				
	},	
	
	checkClass : function(object, className) {
		var result = null;
		var splitClass = [];
		var operator = "";
		var arg =[];
		
		if (!formValidator.VALIDATORS.length) {
			formValidator.initValidators();
		}
		
		operator = className.split("=")[0];	// should always exist!
		args = className.split("=")[1];
		
		for (var v = 0; v < formValidator.VALIDATORS.length; v++) {
			if (operator == formValidator.VALIDATORS[v].classname) {
				//alert("found a required classname: " + formValidator.VALIDATORS[v].classname);
				// validate this guy
				
				switch(object.type) {
					case "select-one":
					case "select-multiple":
					case "select":
						result = formValidator.VALIDATORS[v].handler(object[object.selectedIndex], args);
						break;
					case "radio":
					case "checkbox":
						result = formValidator.VALIDATORS[v].handler(object, args);
						break;
					default:
						result = formValidator.VALIDATORS[v].handler(object, args);
						break;
				}
				
				return result;
			}
		}
		return true;
		
	},
	
	setClassName : function(className) {
		formValidator.className = className;
	},
	
	initValidators : function() {
		formValidator.VALIDATORS[0] = { name: "string", handler:isZeroLengthString, classname: "string" };
		formValidator.VALIDATORS[1] = { name: "checked", handler:isChecked, classname: "checked" };	// used for radios and checkboxes
		formValidator.VALIDATORS[2] = { name: "email", handler: isEmail, classname: "email" };
		formValidator.VALIDATORS[3] = { name: "password", handler: isPassword, classname: "password" };
		formValidator.VALIDATORS[4] = { name: "matches", handler: matches, classname: "matches" };
		formValidator.VALIDATORS[5] = { name: "phone", handler:isPhone, classname: "phone" };
		formValidator.VALIDATORS[6] = { name: "intlphone", handler: isInternationalPhone, classname: "intlphone" };
		formValidator.VALIDATORS[7] = { name: "zip", handler:isZip, classname: "zip" };
		formValidator.VALIDATORS[8] = { name:"uscurrency", regex: /\$\d{1,3}(,\d{3})*\.\d{2}/, classname: "uscurrency" };
		formValidator.VALIDATORS[9] = { name: "date", rhandler:isDate, classname: "date" };
	}
}


/***************************************************
 * Function: 
 * isZeroLengthString
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that a form field is not a zero length string
 * 
 * Arguments:
 * oField - the form field to check
 * 
 * Returns:
 * true/false
 * 
 * ****************************************************/
function isZeroLengthString(oElement) {
	var theString = oElement.value;
	var result = { passed: true, message: "" };
	
	var theString = trim(theString);
	
	if (theString.length < 1) {
		result.passed = false;
		result.message = "This field is required.";
		return result;
	}
	
	return result;

}

/***************************************************
 * Function: 
 * isChecked
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that an input or checkbox has been checked
 * 
 * Arguments:
 * oField - the form field to check
 * 
 * Returns:
 * true/false
 * 
 * ****************************************************/
function isChecked(oElement) {
	var result = { passed: true, message: "" };
	
	if(!oElement) {
		result.passed = false;
		return result;
	}	
	
	// have to get all the elements since we only apply the class to one.
	var oFields = document.getElementsByName(oElement.name); 
	
	// loop over all of the options
	for ( var i = 0; i < oFields.length; i++) {
		if (oFields[i].type == oElement.type && oFields[i].checked) {
			return result;
		}
	}
	
	// if we get here - nothing was checked
	result.passed = false;
	if (oElement.type == "radio" || oFields.length > 1) {
		result.message = "You must choose one of these options";
	}
	else {
		if (oFields.length == 1) {
			result.message = "You must check this checkbox";
		}
		else {
			result.message = "You must check at least one of these checkboxes";	
		}
	}
	return result;

}


/***************************************************
 * Function: 
 * isNumber
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that a form field is a valid number
 * 
 * Arguments:
 * oField - the form field to check
 * 
 * Returns:
 * true/false
 * 
 * ****************************************************/	
function isNumber(oElement) {
	var result = { passed: true, message: "" };
	
	var theString = trim(oElement.value);
	
	if(isNaN(theString) || theString.length < 1) {
		result.passed = false;
		result.message = "This field requires a valid number."
	}
	
	return result;
}

/***************************************************
 * Function: 
 * isEmail
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that a form field is a valid email
 * 
 * Arguments:
 * oField - the form field to check
 * 
 * Returns:
 * true/false
 * 
 * ****************************************************/	
function isEmail(oElement) {
	var regex = /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,2})(\]?)$/;
	var result = { passed: true, message: "" };
	
	var theString = trim(oElement.value);
	
	if( ! regex.test(theString)) {
		result.passed = false;
		result.message = "This field requires a valid email address.";
	}
	return result;
}


/***************************************************
 * Function: 
 * isDate
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that a form field is a valid date
 * 
 * Arguments:
 * oField - the form field to check
 * 
 * Returns:
 * true/false
 * 
****************************************************/	
function isDate(oElement) {
	var result = { passed: true, message: "" };
	var regex = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/;
	
	if (typeof oElement == "string") {
		var theString = oElement;
	}
	else {
		var theString = trim(oElement.value);
	}
	
	count = 0;
	while (theString.indexOf('-') > 0) 
	{
		alert('found index @ ' + theString.indexOf('-'));
	   	count++;
		theString = theString.replace('-', '/');
		if (count >2) {
			break;
		}
	}
	count = 0;
	while (theString.indexOf(' ') > 0) 
	{
	   	count++;
		theString = theString.replace(' ', '/');
		if (count >2) {
			break;
		}
	}
	count = 0;
	while (theString.indexOf('.') > 0) 
	{
	   	count++;
		theString = theString.replace('.', '/');
		if (count >2) {
			break;
		}
	}
	if (! regex.test(theString)) {
		result.passed = false;
		result.message = "An invalid date was supplied";
	}
	return result;
	
}



/***************************************************
 * Function: 
 * isValidPassword
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that a form field is a valid password
 * 
 * Arguments:
 * oField - the form field to check
 * 
 * Returns:
 * true/false
 * 
 * ****************************************************/	
function isPassword(oElement) {
	var regex = /[a-zA-Z0-9_.-]{4,20}/;
	var result = { passed : true, message: ""};
	
	var theString = trim(oElement.value);
	
	if (!regex.test(theString)) {
		result.passed = false;
		result.message = "This field requires a valid password.";
	}
	return result;
}



/***************************************************
 * Function: 
 * isPhone
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that a form field is a valid US Phone Number
 * 
 * Arguments:
 * oField - the form field to check
 * 
 * Returns:
 * true/false
 * 
****************************************************/	
function isPhone(oElement) {
	var regex =  /^\(?\d{3}\)?\s|-\d{3}-\d{4}$/;
	var result = { passed: true, message: ""};
	
	var theString = trim(oElement.value);

	
	if (! regex.test(theString)) {
		result.passed = false;
		result.message = "This field requires a valid phone number";
	}
	return result;
	
}

/***************************************************
 * Function: 
 * isZip
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that a form field is a valid US Zip code
 * 
 * Arguments:
 * oField - the form field to check
 * 
 * Returns:
 * true/false
 * 
 * ****************************************************/	
function isZip(oElement) {
	var regex = /\d{5}(-\d{4})?/;
	var result = { passed: true, message: ""};
	theString = trim(oElement.value);
		
	if (! regex.test(theString)) {
		result.passed = false;
		result.message = "This field requires a valid zip code.";
	}
	return result;
}

function isInternationalPhone(oElement) {
	var theString = trim(oElement.value);
	var regex = /^\d(\d|-){7,20}/;
	
}

/***************************************************
 * Function: 
 * stringsMatch
 * 
 * Author:
 * Dan Uyemura
 * 
 * Description: 
 * Validates that two form fields strings match
 * 
 * Arguments:
 * oField1 - the form field to check
 * oField2 - the form field to match
 * 
 * Returns:
 * true/false
 * 
 * ****************************************************/	
function matches(oElement,args) {
	var theString1 = trim(oElement.value);
	var result = { passed: true, message: ""};
	
	if (typeof args == "object") {
		var niceFieldString = "";
		var theString2 = trim(args.value);
	}
	else {
		var strField2ID = args.split(":")[0];
		var niceFieldString = args.split(":")[1];
		
		if (niceFieldString == undefined) {
			niceFieldString = strField2;
		}
		niceFieldString = niceFieldString.replace(/_/, " ");
		var theString2 = trim(document.getElementById(strField2ID).value);
	
	}	
	
		
	if(theString1 != theString2) {
		result.passed = false;
		result.message = "This value must match the value of " + niceFieldString;
	}
	
	return result;
}


	