var HelperValidators = {
	errroMsg: new Array(),
	
	resetErrorMsg: function() {
		this.errorMsg = new Array();
	},
	
	getFormattedErrorMsg: function() {
		return "The following fields are missing or incomplete:\n" + this.errorMsg.join("\n");
	},
	
	getErrorMsgNbr: function() {
		return this.errorMsg.length;
	},
	
	addErrorMsg: function(msg) {
		this.errorMsg.push(msg)
	},
	
	notEmpty: function(value, description) {
		var valid = value != null && !value.toString().match("^\s*$");
		if(!valid) {
			this.addErrorMsg("- " + description);
		}
		return valid;
	},

	validForRegexp: function(value, regexp, description) {
		var valid = regexp.test(value);
		if(!valid) {
			this.addErrorMsg("- " + description);
		}
		return valid;
	},
	
	shortEnough: function(value, length, description) {
		var valid = value.toString().length <= length;
		if(!valid) {
			this.addErrorMsg("- " + description);
		}
		return valid;
	}
};

// general form validator

var FormValidator = { // CALL INIT IN ONLOAD
	validatedFormId: null,
	validatorArray: null,

	// - sets up FormValidator to validate form with id = validatedFormId using validators coming from
	//		validatorArray, which should be indexed with IDs of all form elements that have IDs
	// 		and contain functions validating appropriate elements(use HelperValidators)
	// - adds validation to the elements marked in html with class = validationClass (if submitted)
	// - sets up Highlighter to highlight invalid form elements to highlightColor (if null, Highlighter defaults to red)
	init: function(validatedFormId, validatorArray, validationClass, highlightColor, submitOnValidate) {
		this.submitOnValidate = (submitOnValidate === undefined ? false : submitOnValidate);
		
		if(validatedFormId == null) {
			throw "Must supply id of the validated form";
		} else {
			this.validatedFormId = validatedFormId;
		}
		
		if(validatorArray == null) { // add check for instanceof
			throw "Must supply array of validators";
		} else {
			this.validatorArray = validatorArray;
		}
		
		Highlighter.init(highlightColor);
		this.addValidationToElements(validationClass);
	},
	
	addValidationToElements: function(className) {
		var elements = document.getElementsByTagName("*");
		var elementsLength = elements.length;
		for(var idx = 0; idx < elementsLength; idx++) {
			if(ClassNameHelper.hasClassName(elements[idx], className)) {
				if(elements[idx].onclick instanceof Function) {
					var fn = elements[idx].onclick;
					elements[idx].onclick = function() {
						var ret = FormValidator.validate();
						fn();
						return ret;
					};
				} else {
					elements[idx].onclick = FormValidator.validate;
				}
			}
		}
	},

	getElementValue: function(element) {
		return ValueHelper.getValue(element);
	},

	// runs validators from validatorArray
	// - if some validators fail, alerts the user with a message generated by HelperValidators
	//		and highlights invalid elements using Highlighter
	// - if all elements are valid, submits the form
	validate: function() {
		var registerForm = document.getElementById(FormValidator.validatedFormId);
		var allValid = true;
		var currentErrorMsg = "";

		HelperValidators.resetErrorMsg();
		
		for(var idx = 0; idx < registerForm.length; idx++) {
			var currentId = registerForm.elements[idx].id;
			
			if(currentId != null && currentId.toString().length > 0) {
				var valueEntered = FormValidator.getElementValue(document.getElementById(currentId));
				var currentElementValid = FormValidator.validatorArray[currentId](valueEntered);

				if(!currentElementValid) {
					Highlighter.highlightElement(currentId);
				} else {
					Highlighter.clearHighlight(currentId);
				}
			}
		}

		if(HelperValidators.getErrorMsgNbr() == 0) {
			if(this.submitOnValidate) {
				registerForm.submit();
			} else {
				return true;
			}
		} else {
			alert(HelperValidators.getFormattedErrorMsg());
		}
		
		return false;
	}
};

var Highlighter = {
	IE: !!(window.attachEvent && !window.opera),
	errorClassName: "error",
	savedElements: new Array(),

	init: function(errorClassName) {
		if(errorClassName != null) {
			this.errorClassName = errorClassName;
		}
	},

	getElementById: function(elementId) {
		var element = document.getElementById(elementId);
		
		if((element.nodeName.toLowerCase() == "input" && element.getAttribute("type").toLowerCase() == "checkbox") ||
			 (element.nodeName.toLowerCase() == "input" && element.getAttribute("type").toLowerCase() == "radio") ||
				(this.IE && element.nodeName.toLowerCase() == "select")) {
			element = this.getLabelForElement(element.id);
		}

		return element;
	},

	getLabelForElement: function(elementId) {
		var labels = document.getElementsByTagName('label');
		for(var idx = 0; idx < labels.length; idx++) {
			if(labels[idx].htmlFor == elementId) {
				return labels[idx];
			}
		}
		return null;
	},

	highlightElement: function(currentId) {
		var element = this.getElementById(currentId);
		ClassNameHelper.addClassName(element, this.errorClassName);
	},

	clearHighlight: function(currentId) {
		ClassNameHelper.removeClassName(this.getElementById(currentId), this.errorClassName);
	}
};