var validation = {
	handlerClasses : {}
};

validation.Validation = function(formId) {
	this.formId = formId;
	this.formElement = jQuery("#" + formId);
	this.handlers = {};
	this.rules = new Array();
	this.ruleName = {};

	this.addValidationHandlers = function (library) {
		var newHandlers = library.getHandlers();
		for (var i in newHandlers) {
			this.handlers[i] = { library : library, method : newHandlers[i] };
		}
	}

	this.addRule = function(fieldId, isRequired, checkType, errorMessage, name, enabled, options) {
		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.
	 */
	this.clearRules = function() {
		this.rules = new Array();
	}

	this.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.
	 */

	this.validate = function() {
		var errors = new Array();
		var success = new Array();
		var currRule = null;
		var currValue = null;
		var result = false;

		var formArray = this.formElement.serializeArray();
		var formValues = {};
		for (var i = 0; i < formArray.length; i++) {
			formValues[formArray[i].name] = formArray[i].value; 
		}

		for (var i = 0; i < this.rules.length; i++) {
			currRule = this.rules[i];
			
			if (formValues[currRule.fieldId]) {
				currValue = formValues[currRule.fieldId];
			} else {
				currValue = "";
			}

			if (currRule.enabled) {
				if (this.isEmpty(currValue)) {
					if(currRule.isRequired){
						errors.push({fieldId: currRule.fieldId, errorMessage: currRule.errorMessage});
					} else {
						success.push({fieldId: currRule.fieldId});
					}
				} else if (currRule.checkFunction) {
					// Test using the appropriate check function
					if (currRule.checkFunction(currValue, currRule.options, formValues)) {					
						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;
	}

	this.onFormSubmit = function(event) {
		var isValid = this.validate();
		if (! isValid) {
			event.preventDefault();
		}
	}

	this.onValidateSuccess = function() {
	}

	this.doSuccessDisplay = function(fieldArray) {
		jQuery(fieldArray).each(function(index, currField) {
			var field = jQuery("#" + currField.fieldId);
			field.removeClass("exceptionField");
			field.parent(".ctrlHolder:eq(0)").each(function (index, item) {
				var item = jQuery(item);
				item.removeClass("error");
				item.children("p.errorField").remove();
			});
		});
		
	}

	this.onValidateFailure = function(errors) {
	}

	this.doFailureDisplay = function(fieldArray) {
		jQuery(fieldArray).each(function(index, currField) {
			var field = jQuery("#" + currField.fieldId);
			field.addClass("errorField");
			field.parents(".ctrlHolder:first").each(function (index, item) {
				var item = jQuery(item).addClass("error");
				if (item.children("p.errorField").length == 0) {
					item.prepend('<p class="errorField"><strong>' + currField.errorMessage + '</strong></p>');
				}
			});
		});
	}

	/**
	 * Returns true if a value has been entered into the given field,
	 * false otherwise.
	 */
	this.isEmpty = function(value) {
		return (value.replace(/^\s+/,'').replace(/\s+$/,'').length == 0) ? true : false;
	}

	// Initialization Code
	for (var i in validation.handlerClasses) {
		this.addValidationHandlers(new validation.handlerClasses[i]());
	}

}
