/*----------------------------------------------------------------------------

	FormValidator V1.1.3
	(C)2001 StealthNET

	All rights reserved
	
	Author:        Paul Bates
	Description:   Simple client-side validation for form elements.
	Restrictions:  JavaScript1.2 (Due to RegExp)
	
	
	updates V1.1.3
	--------------
	* LENGTH_RANGE validation added.
	* NUMERICAL_RANGE validation added.
	* VALUE_RANGE validation added.
	* ZIPCODE validation added.
	
	updates V1.1.2
	--------------
	* FIXED_LENGTH validation added.
	
	updates V1.1.1
	--------------
	* EMAIL bug fixed.
	
	updates V1.1.0
	--------------
	* can now supply additional parameters when decalring a field to
	be validated.
	* can set border colour for unvalidated form element.
	
----------------------------------------------------------------------------*/

/*---------------------------------
Variable
---------------------------------*/

// holds the lists of forms
var forms = new Array();
var killProcess = false;
var Validated = true;

/*---------------------------------
Constants
---------------------------------*/

// Validation Constants
// Constants may be or-ed together to form a more complex validation
var NONE 		= 0;
var NAME 		= 1;
var FULLNAME 		= 3;
var EMAIL 		= 2;
var POSTCODE 		= 4;
var TELEPHONE 		= 8;
var NOT_EMPTY 		= 16;
var NUMERICAL 		= 32;
var ALPHA 		= 64;
// added 1.1.2
var FIXED_LENGTH	= 128; // additonal field in ValidateElement is required. this is the length
// added 1.1.3
var LENGTH_RANGE	= 256; // requires two additional parameters - min length and max length
var NUMERICAL_RANGE	= 512; // requires two additional parameters - min value and max value
var VALUE_RANGE		= 1024; // requires two additional parameters - min value and max value
var ZIPCODE		= 2048; // international support

/*---------------------------------
FormValidator object
---------------------------------*/

// constructor function for FormValidator object
function FormValidator(formName, borderStyle, originalStyle){
	if (document[formName] == null){
		alert("Cannot find form " + formName);
		killProcess = true;
	}else{
		var counter = 0;
		if (forms.length != null) counter = forms.length;

		forms[counter] = document[formName];
		forms[counter].hashCode = formName;

		this.index = counter;
		this.elements = new Object();
		
		if (borderStyle != null){
			this.borderStyle = borderStyle;
		}else{
			this.borderStyle = '2px solid red';
		}
		
		if (originalStyle != null){
			this.originalBorderStyle = originalStyle;
		}else{
			this.originalBorderStyle = "2px inset white";
		}
			
	}
}

// retrieve a FormValidator object by its name
function __getFormByName(formName){
	if (!(killProcess)){
		for (var i = 0; i < forms.length; i++){
			if (forms[i].hashCode == formName) return form[i];
		}
	}

	// if all else fails
	return null;
}

// add a form element to the list to be validated
function __validateElement(elementName, validator, errorText){
	if (!(killProcess)){
		if (this.elements[elementName] == null){
			this.elements[elementName] = new Object();
		}
		var additionalArgs = new Array();
		for (var i = 3; i < __validateElement.arguments.length; i++){
			additionalArgs[(i - 3)] = __validateElement.arguments[i];
		}
		this.elements[elementName][validator] = new ValidationElement(forms[this.index][elementName], elementName, validator, errorText, this.originalBorderStyle, additionalArgs);
	}
}

// validate all of the form elements in the list of those added
function __validateAll(){
	var result = true;
	if (!killProcess){
		for (var elementName in this.elements){
			for (var validator in this.elements[elementName]){
				var tempresult = this.elements[elementName][validator].validate();
				result = (result && tempresult)
				this.elements[elementName][validator].validated = tempresult;

			}
		}
		if (!(result)) this.displayReport();
	}
	
	Validated = result // must be used with on submit
	return result;
}

function __displayReport(){
	var getFirstFlag = false;
	var firstElement;
	for (var elementName in this.elements){
		for (var validator in this.elements[elementName]){
			this.elements[elementName][validator].formElement.style.border = this.elements[elementName][validator].borderBackup;
		}
	}
	
	var output = "Before submiting this form, there are a few\nerrors that need correcting, these are detailed below\n\n" +
		"---------------------------------------------------------------------------------------\n";
	for (var elementName in this.elements){
		for (var validator in this.elements[elementName]){
			if (!this.elements[elementName][validator].validated){
				output += this.elements[elementName][validator].text + "\n";
				this.elements[elementName][validator].formElement.style.border = this.borderStyle;
				if (!getFirstFlag){
					firstElement = this.elements[elementName][validator].formElement;
					getFirstFlag = true;
				}
			}
		}
	}
	
	output += "---------------------------------------------------------------------------------------\n\n" +
		"Once you have made the ammendment your information\nmay be submitted\n\nThank You";
	alert(output);
	firstElement.focus();
}

/*---------------------------------
ValidationElement object
---------------------------------*/

// constructor for ValidationElement object
function ValidationElement(element, elementName, validator, errorText, borderStyle, additional){
	if (element == null){
		alert("Cannot find form element " + elementName + " on form");
		killProcess = true;
	}else{
		this.formElement = element;
		this.elementName = elementName;
		this.validator = validator;
		this.text = errorText;
		this.validated = false;
		this.borderBackup = element.style.border != "" ? element.style.border : borderStyle;
		this.additional = additional;
		//alert(element.style.border)
		element.style.border = this.borderBackup;
	}
}

// validate a ValidationElement object
function __validate(){
	var value = this.formElement.value;
	var additionalArgs = this.additional;
	switch (this.validator){
		case FULLNAME:
			return validateFullName(value);
		case NONE:
			return true;
		case NAME:
			return validateName(value);
		case EMAIL:
			return validateEmail(value);
		case POSTCODE:
			return validatePostcode(value);
		case TELEPHONE:
			return validateTelephone(value);
		case NOT_EMPTY:
			return validateNotEmpty(value);
		case NUMERICAL:
			return validateNumerical(value);
		case ALPHA:
			return validateAlpha(value);
		case FIXED_LENGTH:
			return validateFixedLength(value, additionalArgs);
		case LENGTH_RANGE:
			return validateLengthRange(value, additionalArgs);
		case NUMERICAL_RANGE:
			return validateNumericalRange(value, additionalArgs);
		case VALUE_RANGE:
			return validateValueRange(value, additionalArgs);
		case ZIPCODE:
			return validateZipCode(value);
		default:
			alert("Error invalid validation on form element " + this.elementName);
			return false;
	}
}

/*---------------------------------
Global functions
---------------------------------*/

function validateFullName(str){
	// must be at least one space
	return ((str.indexOf(" ") != -1) && validateNotEmpty(str) &&  validateAlpha(str));
}

function validateName(str){
	// must be one work only
	return ((str.indexOf(" ") == -1) && validateNotEmpty(str) &&  validateAlpha(str));
}

function validateEmail(str){
	// must be a @ and . and be at least 6 chars long
	return ((str.indexOf("@") > -1) && (str.indexOf(".") > -1) &&
		(str.length >= 6) && (str.indexOf("@.") == -1));
}

function validatePostcode(str){
	// must have a space and have 3 or 4 chars in the first and last
	return ((str.length <= 9) && validateNotEmpty(str));
}

function validateTelephone(str){
	// must be a string of numbers between 9 and 11 chars
	return ((str.length >= 7) && (str.length <= 20));
}

function validateNotEmpty(str){
	// must not be a null entry
	return str != "";
}

function validateNumerical(str){
	// must only be numbers
	return (((str.match(/\D+/)) == null) || ((str.match(/\D+/)).length == 0));
}

function validateAlpha(str){
	// must only be alphanumeric
	return (((str.match(/\d+/)) == null) || ((str.match(/\d+/)).length == 0));
}

function validateFixedLength(str, additionalArgs){
	// the value must be a fixed length
	return (str.length == additionalArgs[0]);
}

function validateLengthRange(str, additionalArgs){
	// the values length must be between a min and a max
	var sl = str.length;
	return ((sl >= additionalArgs[0]) && (sl <= additionalArgs[1]));
}

function validateNumericalRange(str, additionalArgs){
	// a numerical value must be between a min and a max
	return (validateNumerical(str) && validateValueRange(str, additionalArgs));
}

function validateValueRange(str, additionalArgs){
	// a value must be between a min and a max
	return ((str >= additionalArgs[0]) && (str <= additionalArgs[1]));
}

function validateZipcode(str){
	// validates a us Zipcode
	var arr = new Array(1);
	arr[0] = 5;
	return (validateNumerical(str) && validateFixedLength(str, arr));
}


/*---------------------------------
Object associations
---------------------------------*/

// Attach the methods to the FormValidator object

FormValidator.prototype.getFormByName 	= __getFormByName;
FormValidator.prototype.validateElement = __validateElement;
FormValidator.prototype.validateAll 	= __validateAll;
FormValidator.prototype.displayReport 	= __displayReport;

// Attach the methods to the ValidationElement object

ValidationElement.prototype.validate 	= __validate;

