/*****************************************************************************************************
*	JAVASCRIPT FORM VALIDATOR

*	Use this class to validate any form element easily. Simply include 
*	the needed files, create the form object, add elements to it, and 
*	validate it before you submit a form. Element options are set using 
*	JSON notation. The validateForm function returns a boolean value 
*	based on whether the form is fully validated or not.

*	REQUIRED FILES

*	formValidator.js (this file)
*	prototype.js
*	scriptaculous.js (include by putting 'scriptaculous.js?load=effects' in the src)
*	effects.js


*	SUPPORTED ELEMENTS

*	Required Field
*		Type: 'empty'
*		Description: A field that is required to have something entered
*		Options:
*			id: The id attribute of the form element (REQUIRED)
*			errorMsg: The message to be displayed if the element does not validate (REQUIRED)
			
*	Alpha-Numeric Field
*		Type: 'alpha'
*		Description: A field that is required to have only letters and numbers
*		Options:
*			id: The id attribute of the form element (REQUIRED)
*			errorMsg: The message to be displayed if the element does not validate (REQUIRED)
*			required: A boolean value that denotes whether or not the element is required (OPTIONAL)
*			fieldName: A label for the form element (REQUIRED IF required SET TO TRUE)

*	Numbers-Only Field
*		Type: 'number'
*		Description: A field that is required to have only numbers
*		Options:
*			id: The id attribute of the form element (REQUIRED)
*			errorMsg: The message to be displayed if the element does not validate (REQUIRED)
*			required: A boolean value that denotes whether or not the element is required (OPTIONAL)
*			fieldName: A label for the form element (REQUIRED IF required SET TO TRUE)

*	Exact Match Field
*		Type: 'match'
*		Description: A field that is required to match a given value
*		Options:
*			id: The id attribute of the form element (REQUIRED)
*			errorMsg: The message to be displayed if the element does not validate (REQUIRED)
*			matchVal: The value to match against the form element (REQUIRED)
*			required: A boolean value that denotes whether or not the element is required (OPTIONAL)
*			fieldName: A label for the form element (REQUIRED IF required SET TO TRUE)

*	Range Field
*		Type: 'range'
*		Description: A field that is required to fall between two given numbers
*		Options:
*			id: The id attribute of the form element (REQUIRED)
*			errorMsg: The message to be displayed if the element does not validate (REQUIRED)
*			low: The lowest number the value can be (REQUIRED)
*			high: The highest number the value can be (REQUIRED)
*			required: A boolean value that denotes whether or not the element is required (OPTIONAL)
*			fieldName: A label for the form element (REQUIRED IF required SET TO TRUE)

*	Email Field
*		Type: 'email'
*		Description: A field that is required to be a valid email address
*		Options:
*			id: The id attribute of the form element (REQUIRED)
*			errorMsg: The message to be displayed if the element does not validate (REQUIRED)
*			required: A boolean value that denotes whether or not the element is required (OPTIONAL)
*			fieldName: A label for the form element (REQUIRED IF required SET TO TRUE)

*	Regular Expression Field
*		Type: 'regex'
*		Description: A field that is to be checked against a given regular expression
*		Options:
*			id: The id attribute of the form element (REQUIRED)
*			errorMsg: The message to be displayed if the element does not validate (REQUIRED)
*			regex: The reqular expression the element is tested againse (ie '/[a-z]+/') (REQUIRED)
*			required: A boolean value that denotes whether or not the element is required (OPTIONAL)
*			fieldName: A label for the form element (REQUIRED IF required SET TO TRUE)

*	Required Length Field
*		Type: 'length'
*		Description: A field that is required to be at least a certain length
*		Options:
*			id: The id attribute of the form element (REQUIRED)
*			errorMsg: The message to be displayed if the element does not validate (REQUIRED)
*			length: The number of characters the element is required to be (REQUIRED)
*			required: A boolean value that denotes whether or not the element is required (OPTIONAL)
*			fieldName: A label for the form element (REQUIRED IF required SET TO TRUE)


*	EXAMPLE

*	Head Section

*	fv = new formValidator();

*	fv.addElement({
*		id: 'contact_name',
*		errorMsg: 'A contact name is required'
*		required: true,
*		fieldName: 'Name'
*	});

*	fv.addElement({
*		id: 'contact_email',
*		errorMsg: 'The email address is in an incorrect format'
*	});


*	Form Element
*	<form onsubmit="return fv.validateForm();">
*****************************************************************************************************/

var formValidator = function(param) {
	var elements	= [];
	var bgcolor 	= '#FFFFFF';
	var highlight 	= '#FFCCCC';
	
	var formValid 	= true;
	
	if (param != undefined) {
		bgcolor 	= param.bgcolor;
		highlight 	= param.highlight;
	}
	
	this.addElement = function(param) {
		var error = 0;
		var errorMsg = 'Form Validator Initialization Error(s) for Element #' + (elements.length + 1) + ':\n';
		
		if (param.id == undefined) {
			error++;
			errorMsg += '\tNo element id defined\n';
		}
		
		if (param.type == undefined) {
			error++;
			errorMsg += '\tNo element type defined\n';
		}
		
		if (param.errorMsg == undefined) {
			error++;
			errorMsg += '\tNo error message defined\n';
		}
		
		if (param.required && param.fieldName == undefined) {
			error++;
			errorMsg += '\tNo element label defined\n';
		}
		
		if (param.type == 'range') {
			if (param.low == undefined || param.high == undefined) {
				error++;
				errorMsg += '\tElement range value(s) not defined\n';
			}
		}
		
		if (param.type == 'match' && param.matchVal == undefined) {
			error++;
			errorMsg += '\tNo comparison value defined for element\n';
		}
		
		if (param.type == 'regex' && param.regex == undefined) {
			error++;
			errorMsg += '\tNo regular expression defined for element\n';
		}
		
		if (param.type == 'length' && param.length == undefined) {
			error++;
			errorMsg += '\tNo character length defined for element\n';
		}
		
		if (error > 0) {
			errorMsg += 'Please correct these errors.';
			alert(errorMsg);
			
			formValid = false;
			
			return false;
		} else {
			elements.push(param);
		}
	};
	
	var highlightElement = function(ele) {
		new Effect.Highlight(ele, {
			startcolor: highlight,
			endcolor: bgcolor,
			restorecolor: bgcolor,
			duration: 3
		});
	};
	
	this.validateForm = function() {
		var error = 0;
		var errorMsg = 'The following errors occured:\n';
		var errorEle = [];
		
		elements.each(function(ele) {
			switch(ele.type) {
				case 'empty':
					if (!$(ele.id).present()) {
						error++;
						errorMsg += '\t' + ele.errorMsg + '\n';
						errorEle.push(ele.id);
					}
					break;
				
				case 'alpha':
					if (ele.required && !$(ele.id).present()) {
						error++;
						errorMsg += '\tThe ' + ele.fieldName + ' field is missing\n';
						errorEle.push(ele.id);
					}
					
					if (!$F(ele.id).match(/^([a-zA-Z0-9]+)$/) && $(ele.id).present()) {
						error++;
						errorMsg += '\t' + ele.errorMsg + '\n';
						errorEle.push(ele.id);
					}
					break;
				
				case 'number':
					if (ele.required && !$(ele.id).present()) {
						error++;
						errorMsg += '\tThe ' + ele.fieldName + ' field is missing\n';
						errorEle.push(ele.id);
					}
					
					if (!$F(ele.id).match(/^([0-9]+)$/) && $(ele.id).present()) {
						error++;
						errorMsg += '\t' + ele.errorMsg + '\n';
						errorEle.push(ele.id);
					}
					break;
				
				case 'match':
					if (ele.required && !$(ele.id).present()) {
						error++;
						errorMsg += '\tThe ' + ele.fieldName + ' field is missing\n';
						errorEle.push(ele.id);
					}
					
					if ($F(ele.id) == ele.matchVal && $(ele.id).present()) {
						error++;
						errorMsg += '\t' + ele.errorMsg + '\n';
						errorEle.push(ele.id);
					}
					break;
				
				case 'range':
					if (ele.required && !$(ele.id).present()) {
						error++;
						errorMsg += '\tThe ' + ele.fieldName + ' field is missing\n';
						errorEle.push(ele.id);
					}
					
					if ($F(ele.id) >= ele.low && $F(ele.id) <= ele.high && $(ele.id).present()) {
						error++;
						errorMsg += '\t' + ele.errorMsg + '\n';
						errorEle.push(ele.id);
					}
					break;
				
				case 'email':
					if (ele.required && !$(ele.id).present()) {
						error++;
						errorMsg += '\tThe ' + ele.fieldName + ' field is missing\n';
						errorEle.push(ele.id);
					}
					
					if (!$F(ele.id).match(/^([a-zA-Z0-9._-])+@([a-zA-Z._-])+\.([a-zA-Z]){2,4}$/) && $(ele.id).present()) {
						error++;
						errorMsg += '\t' + ele.errorMsg + '\n';
						errorEle.push(ele.id);
					}
					break;
				
				case 'regex':
					if (ele.required && !$(ele.id).present()) {
						error++;
						errorMsg += '\tThe ' + ele.fieldName + ' field is missing\n';
						errorEle.push(ele.id);
					}
					
					if (!$F(ele.id).match(ele.regex) && $(ele.id).present()) {
						error++;
						errorMsg += '\t' + ele.errorMsg + '\n';
						errorEle.push(ele.id);
					}
				
				case 'length':
					if (ele.required && !$(ele.id).present()) {
						error++;
						errorMsg += '\tThe ' + ele.fieldName + ' field is missing\n';
						errorEle.push(ele.id);
					}
					
					if (!$(ele.id).length < ele.length) {
						error++;
						errorMsg += '\t' + ele.errorMsg + '\n';
						errorEle.push(ele.id);
					}
					break;
			}
		});
		
		if (!formValid) {
			alert('Form has initialization errors. Reload page to see complete list.');
			return false;
		}
		
		if (error > 0) {
			errorMsg += 'These errors need to be corrected before the form can be sent';
			alert(errorMsg);
			
			errorEle.each(function(x) {
				highlightElement(x);
			});
			
			return false;
		} else {
			return true;
		}
	};
};