if (! Validator) {
var Validator = Class.create();

Validator.prototype = {
	initialize: function (formId) {
		this.formId = formId;
		this.handlers = {};
		this.rules = new Array();
		this.ruleName = {};
	},

	addValidationHandlers : function (library) {
		var newHandlers = library.getHandlers();
		for (var i in newHandlers) {
			this.handlers[i] = { library : library, method : newHandlers[i] };
		}
	},

	addRule : function (fieldId, isRequired, checkType, errorMessage, name, enabled, options) {
		checkType = checkType.toLowerCase();
		this.rules.push({
			fieldId : fieldId,
			isRequired : isRequired,
			checkFunction : (this.handlers[checkType]) ? this.handlers[checkType].library[this.handlers[checkType].method] : null,
			errorMessage : errorMessage,
			enabled : ((enabled == null) || enabled) ? true : false,
			options : (options) ? options : {}
		});
		if (name && (name != "")) {
			this.ruleName[name] = this.rules[this.rules.length - 1];
		}
	},

	/**
	 * Clears all validation rules so no validation is performed.
	 */
	clearRules : function () {
		this.rules = new Array();
	},

	setRuleEnabled : function (ruleNameList, enabled) {
		for (var i = 0; i < ruleNameList.length; i++) {
			this.ruleName[ruleNameList[i]].enabled = enabled;
			if (! enabled) {
				Element.removeClassName(this.ruleName[ruleNameList[i]].fieldId, "exceptionField");
			}
		}
	},

	/**
	 * Validates all rules for this validation object and calls the appropriate
	 * callback function depending on success or failure.
	 * Returns: True if validation succeeds, false otherwise.
	 */
	validate : function () {
		var errors = new Array();
		var success = new Array();
		var currRule = null;
		var currValue = null;
		var result = false;

		for (var i = 0; i < this.rules.length; i++) {
			currRule = this.rules[i];

			if ($(currRule.fieldId) && $F(currRule.fieldId) != null) {
				currValue = $F(currRule.fieldId);

				if (currRule.enabled) {
					if (currRule.isRequired && this.isEmpty(currValue)) {
						errors.push({fieldId: currRule.fieldId, errorMessage: currRule.errorMessage});
					} else if (currRule.isRequired && currRule.checkFunction) {
						// Test using the appropriate check function
						if (currRule.checkFunction(currValue, currRule.options)) {					
							success.push({fieldId: currRule.fieldId});
						}
						else {
							errors.push({fieldId: currRule.fieldId, errorMessage: currRule.errorMessage});
						}
					} else {
						success.push({fieldId: currRule.fieldId});
					}
				}
			}
		}

		if (errors.length == 0) {
			this.onValidateSuccess();
			this.doSuccessDisplay(success);

			result = true;
		} else {
			this.onValidateFailure(errors);
			this.doSuccessDisplay(success);
			this.doFailureDisplay(errors);
		}

		return result;
	},

	onFormSubmit : function (event) {
		var isValid = this.validate();
		if (!isValid) {
			Event.stop(event);
		}
	},

	onValidateSuccess : function () {
		var formValElement = $("FormValidation-" + this.formId);
		formValElement.innerHTML = "";
		Element.hide(formValElement);
	},

	doSuccessDisplay : function (fieldArray) {
		var formId = this.formId;
		fieldArray.each(function(currField) {
			var field = $(currField.fieldId);
			if (field) {
				Element.removeClassName(currField.fieldId, "exceptionField");
	 			$$("#" + formId + " .validationFail_" + field.id).each(
					function(item) {
						item.hide();
				});
			}
		});
	},

	onValidateFailure : function (errors) {
		var formValElement = $("FormValidation-" + this.formId);
		var valHtml = '<div class="formValidationHeader">Submission Problems</div>';
		valHtml += '<p>The following problems were found when processing your submission:</p>';
		valHtml += '<ul>';

		for (var i = 0; i < errors.length; i++) {
			valHtml = valHtml + '<li>' + errors[i].errorMessage + '</li>';
		}

		valHtml += '</ul>';
		valHtml += '<p>Please scroll down to correct the problems and submit the form again.</p>';

		formValElement.innerHTML = valHtml;
		Element.show(formValElement);
		new Effect.ScrollTo(formValElement);
	},

	doFailureDisplay : function (fieldArray) {
		var formId = this.formId;
		fieldArray.each(function(currField) {
			var field = $(currField.fieldId);
			if (field) {
				Element.addClassName(field, "exceptionField");
				$$("#" + formId + " .validationFail_" + field.id).each(
					function(item) {
						item.show();
					});
				field.title = currField.errorMessage;
			}
		});
	},

	/**
	 * Returns true if a value has been entered into the given field,
	 * false otherwise.
	 */
	isEmpty : function (value) {
		return (value.replace(/^\s+/,'').replace(/\s+$/,'').length == 0) ? true : false;
	}
}
}