// Copyright 2002 AlphaPlex, Inc.
// http://www.alphaplex.net
// 
// validate.js v1.015 Modified 11/6/2002
//
//	v 1.001: Added validation for select combo boxes
//		 Added validation for radio buttons
//		 Added validation for checkboxes
//		 Added custom popup message capability
//	v 1.002: Added "maxLength" property to limit the number of chars in a field
//	v 1.003: Fixed Netscape 6 bug where maxLength is defaulted to -1
//	v 1.004: Added "minLength" property to require a minimum number of chars in a field
//	v 1.005: Enhanced performance for checking radio and checkboxes
//	v 1.006: Changed "minLength" to allow blank if the field is not required
//	v 1.007: Added a "dateonly" validator that does not allow times
//		 Added a "jpeg" validator that only allows .jpg filenames
//		 Changed phone validator to allow extensions of any form
//	v 1.008: Added "video" validator
//		 Added "mpeg" validator
//	v 1.009: Added "pdf" validator
//	v 1.010: Changed the "required" criteria for select-multiple combo boxes to actually require at least one selection.  Before, it handled these the same a single select boxes, which was illogical.
//	v 1.011: Added field names (actual field name) to generic alert messages.
//	v 1.012: Fixed a bug introduced in the last version (used wrong variable name)
//  v 1.013: Added validatorMessage property to form fields for use in adding a custom
//       message when a form field has a validator property specified.  For example,
//       instead of using the default alert message for an improperly formatted 
//       field that has the "float" validator, you could provide a custom message.
//  v 1.014: Modified the "date" and "dateonly" validators to handle Opera's slightly
//       screwed regular expression parser (NOTE TO SELF: it does not handle in-expression
//       matches - e.g. use of \2 within the RE itself).  As a result, the date validators
//       will now only accept something like MM/DD/YYYY instead of that and MM-DD-YYYY.
//  v 1.015: Modified "int" and "float" validators to allow negative numbers.  Added two new
//       validators: "unsignedint" and "unsignedfloat" that still allow only positive entries.

/**
* Usage:	In the HTML page, write in a javascript function "validate(theForm)"
*		with the last statement as:
*				return validateForm(theForm);
*		Within this function, add statements for each form field that you wish
*		to require and/or validate. Syntax and notes for these statements are 
*		given below.  In the HTML form tag, add the property:
*				onSubmit="return validate(this)"
*		
*
* Requiring 	For all form fields of type other than "radio" and "checkbox", 
* Fields:	use the statement:
*				theForm.fieldname.required = true;
*		to require the field.
*		
*		For RADIO and CHECKBOX fields, use the statement:
*				theForm.fieldname[0].required = true;
*		to require the field.
*	
*		NOTE: For SELECT fields, requiring this field has the effect that
*		the first option is not valid!!
*
* Validating	To validate a field, use a statement such as:
* Fields:			theForm.fieldname.validator = "date";
*		Where the validator can be any of the following:
*				"dateonly"
*				"date"/"datetime"
*				"time"
*				"currency"/"money"
*				"zip"/"zipcode"/"zip_code"/"zip-code"
*				"email"/"e-mail"/"e_mail"
*				"phone"/"phonenumber" ********* ALLOWS FREE-FORM EXTENSIONS
*				"image"/"image-file"/"imagefile"/"img"
*				"jpeg"/"image-jpeg"/"image/jpeg"
*				"int"/"integer"/"number"/"num"
*				"float"/"real"
*				"mpg"/"mpeg"
*				"video"/"movie"
*				"pdf"
*
* Alert		A default message is shown when a required field is empty upon form
* Messages:	submission.  However, you may override this message by including
*		a statement of the form:
*				theForm.fieldname.alertMessage = "Some alert text here";
*		Note that RADIO and CHECKBOX fields must use the syntax:
*				theForm.fieldname[0].alertMessage = "Some alert text here";
*
*		NOTE: This message is for the requiring of fields ONLY, not for
*		field validation using the "validator" property!!  For this, please
*       use the "validatorMessage" property instead.  It works the same way,
*       except it will pre-empt the validator-specific message.
**/

function isBlank(s) {
	for (var i=0; i<s.length; i++) {
		var c = s.charAt(i);
		if ((c != ' ') && (c != '\n') && (c != '\t')) return false;
	}
	return true;
}

function checkLength(theField) {
	var len = theField.value.length;
	if (theField.maxLength < 0)
		return true;
	if (len <= theField.maxLength) {
		return true;
	}
	else {
		alert("Please enter no more than " + theField.maxLength + " characters in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
}

function checkMinLength(theField) {
	var len = theField.value.length;
	if (len >= theField.minLength || (!theField.required && len == 0)) {
		return true;
	}
	else {
		alert("Please enter at least " + theField.minLength + " characters in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
}

function isValidInteger (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^[-]?\d+$/;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Please enter an integer number value (digits only) for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidUnsignedInteger (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^\d+$/;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Please enter an integer number value (digits only) for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidFloat (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^[-]?\d+(\.\d+)?$/;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Please enter a floating point number value for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidUnsignedFloat (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^\d+(\.\d+)?$/;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Please enter a floating point number value for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidImage (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^.+\.(gif|jpg)$/i;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Invalid image file name: please enter a .gif or .jpg filename for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidVideo (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^.+\.(mpg|mpeg|mov|avi|asf)$/i;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Invalid video file name: please enter a filename with extension of .mpg, .mpeg, .mov, .avi, or .asf for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidMPEGVideo (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^.+\.(mpg|mpeg)$/i;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Invalid video file name: please enter a .mpg or .mpeg filename for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidJPEGImage (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^.+\.(jpg)$/i;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Invalid image file name: please enter a JPEG (.jpg) filename for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidPDF (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^.+\.(pdf)$/i;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Invalid PDF file name: please enter a PDF (.pdf) filename for the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidPhone (theField) {
	var str = null;
	str = theField.value;
	var pattern = /^((\d{3}|\(\d{3}\))([ ]|-|\.)?\d{3}([ ]|-|\.)?\d{4})/;
	var matchArray = str.match(pattern);
	if (matchArray == null && str != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Phone number is not in a valid format in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidTime(theField) {
	var timeStr = null;
	timeStr = theField.value;
	
	//var timePat = /^([0-1]?[0-9]|2[0-3]):[0-5]\d$/;
	var timePat = /^(((0?[1-9]|1[0-2]):[0-5]\d(:[0-5]\d)?\s*(AM|PM))|(([0-1]?[0-9]|2[0-3]):[0-5]\d(:[0-5]\d)?))\s*$/i;
	
	var matchArray = timeStr.match(timePat);
	if (matchArray == null && timeStr != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Time is not in a valid format in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidCurrency(theField) {
	var currencyStr = null;
	currencyStr = theField.value;
	
	var currencyPat = /^\$?((\d{1,3}(,\d{3})*)|(\d+))(\.\d{2})?$/;
	
	var matchArray = currencyStr.match(currencyPat);
	if (matchArray == null && currencyStr != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Currency is not in a valid format in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidZip(theField) {
	var zipStr = null;
	zipStr = theField.value;
	
	var zipPat = /^\d{5}(-\d{4})?$/;
	
	var matchArray = zipStr.match(zipPat);
	if (matchArray == null && zipStr != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Zip code is not in a valid format in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}

function isValidDateTime(theField) {
	var dateStr = null;
	dateStr = theField.value;

	var monthArray = [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
	// ORIGINAL: var datePat = /^(\d{1,2})(\/|-)(\d{1,2})\2(\d{4}|\d{2})\s*/;
	var datePat = /^(\d{1,2})([\/])(\d{1,2})[\/](\d{4}|\d{2})\s*/;
	var timePat = /^(((0?[1-9]|1[0-2]):[0-5]\d(:[0-5]\d)?\s*(AM|PM))|(([0-1]?[0-9]|2[0-3]):[0-5]\d(:[0-5]\d)?))\s*$/i;

	// To require a 4 digit year entry, use this line instead:
	// var datePat = /^(\d{1,2})([\/])(\d{1,2})[\/](\d{4})\s*/;
	
	//First check to see if we have an empty string to avoid a Javascript bug after
	//the matching is performed.
	if (dateStr == "") {
		return true;
	}

	var matchArray = dateStr.match(datePat); // is the format ok?
	if (matchArray == null && dateStr != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Date is not in a valid format in the \"" + theField.name + "\" field.  Format: MM/DD/YYYY.");
		theField.focus();
		return false;
	}
	month = matchArray[1]; // parse date into variables
	day = matchArray[3];
	year = matchArray[4];
	
	if (month < 1 || month > 12) { // check month range
		alert("Month must be between 1 and 12 in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	if (day < 1 || day > 31) { // check overall days range
		alert("Error: Day must be between 1 and 31 in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	if ((month==4 || month==6 || month==9 || month==11) && day==31) { // check for months with only 30 days
		alert("Error: "+monthArray[month]+" doesn't have 31 days.");
		theField.focus();
		return false;
	}
	if (month == 2) { // check for february 29th
		var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
		if (day>29 || (day==29 && !isleap)) {
			alert("Error: February " + year + " doesn't have " + day + " days.");
			theField.focus();
			return false;
		}
	}
	
	var timeStr = dateStr.replace(datePat, "");
	var timeMatchArray = timeStr.match(timePat);
	if (timeMatchArray == null && timeStr != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Time within date field is not in a valid format in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	
	return true;  // date is valid
}

function isValidDate(theField) {
	var dateStr = null;
	dateStr = theField.value;

	var monthArray = [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
	var datePat = /^(\d{1,2})([\/])(\d{1,2})[\/](\d{4}|\d{2})\s*$/;

	// To require a 4 digit year entry, use this line instead:
	// var datePat = /^(\d{1,2})([\/])(\d{1,2})[\/](\d{4})\s*/;
	
	//First check to see if we have an empty string to avoid a Javascript bug after
	//the matching is performed.
	if (dateStr == "") {
		return true;
	}

	var matchArray = dateStr.match(datePat); // is the format ok?
	if (matchArray == null && dateStr != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Date is not in a valid format in the \"" + theField.name + "\" field.  Format: MM/DD/YYYY.");
		theField.focus();
		return false;
	}
	month = matchArray[1]; // parse date into variables
	day = matchArray[3];
	year = matchArray[4];
	
	if (month < 1 || month > 12) { // check month range
		alert("Month must be between 1 and 12 in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	if (day < 1 || day > 31) { // check overall days range
		alert("Error: Day must be between 1 and 31 in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	if ((month==4 || month==6 || month==9 || month==11) && day==31) { // check for months with only 30 days
		alert("Error: "+monthArray[month]+" doesn't have 31 days.");
		theField.focus();
		return false;
	}
	if (month == 2) { // check for february 29th
		var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
		if (day>29 || (day==29 && !isleap)) {
			alert("Error: February " + year + " doesn't have " + day + " days.");
			theField.focus();
			return false;
		}
	}
		
	return true;  // date is valid
}

function isValidEmail(theField) {
	var emailStr = null;
	emailStr = theField.value;
	
	var emailPat = /^[^\/\\<>\(\)\{\}":,;\[\]@\. ]+(\.[^\/\\<>\(\)\{\}":,;\[\]@ ]+)?\@[^\/\\<>\(\)\{\}":,;\[\]@\. ]+\.[^\/\\<>\(\)\{\}":,;\[\]@\. ]+(\.[^\/\\<>\(\)\{\}":,;\[\]@ ]+)?$/;
	
	var matchArray = emailStr.match(emailPat);
	if (matchArray == null && emailStr != "") {
		if (theField.validatorMessage != null)
			alert(theField.validatorMessage);
		else
			alert("Email address is not in a valid format in the \"" + theField.name + "\" field.");
		theField.focus();
		return false;
	}
	return true;
}


function validateForm(theForm) {
// Note that elements[] array of the FORM object, EVERY element (including multiple radio buttons
// of the same group) is treated individually!
	for (var i=0; i < theForm.length; i++) {  // loop through form elements
		var e = theForm.elements[i];  // current element
		//if ((e.type == "Submit") || (e.type == "Reset")) continue;

		if (e.required) {  // check to see if a required field is empty
			if (e.type == "radio" || e.type == "checkbox") {
				var radioSelected = false;
				for (var j = i; j < theForm.length; j++) {
					if (theForm.elements[j].name == e.name && theForm.elements[j].checked) {
						radioSelected = true;
						break;
					}
				}// end for
				if (!radioSelected) {
					if (e.alertMessage == null)
						alert("Please select one of the \"" + e.name + "\" options.");
					else
						alert(e.alertMessage);
					e.focus();
					return (false);
				}// end if					
			}// end if
			else if (e.type == "select-one") {
				if (e.selectedIndex == 0) {
					if (e.alertMessage == null)
						alert("The first \"" + e.name + "\" option is not a valid selection.  Please choose one of the other options.");
					else
						alert(e.alertMessage);
					e.focus();
					return (false);
				}				
			}
			else if (e.type == "select-multiple") {
				if (e.selectedIndex == -1) {
					if (e.alertMessage == null)
						alert("Please select at least one value for the \"" + e.name + "\" field.");
					else
						alert(e.alertMessage);
					e.focus();
					return (false);
				}
			}
			else {
				if ((e.value == null) || (e.value == "") || isBlank(e.value)) {
					if (e.alertMessage == null)
						alert("Please enter a value in the \"" + e.name + "\" field.");
					else
						alert(e.alertMessage);
					e.focus();
					return false;
				}
			}
		}
		if (e.validator) {		
			var v = e.validator;
		} else {
			var v = "";
		}
		//alert (e.required);
		v = v.toLowerCase();
		var valid = true;
		switch (v) {
			case 'dateonly':
				valid = isValidDate(e);
				break;
			case 'date':
			case 'datetime':
				valid = isValidDateTime(e);
				break;
			case 'time':
				valid = isValidTime(e);
				break;
			case 'currency':
			case 'money':
				valid = isValidCurrency(e);
				break;
			case 'zip':
			case 'zipcode':
			case 'zip_code':
			case 'zip-code':
				valid = isValidZip(e);
				break;
			case 'email':
			case 'e-mail':
			case 'e_mail':
				valid = isValidEmail(e);
				break;
			case 'phone':
			case 'phone_no':
			case 'phone_number':
			case 'phonenumber':
				valid = isValidPhone(e);
				break;
			case 'image':
			case 'imagefile':
			case 'image_file':
			case 'img':
				valid = isValidImage(e);
				break;
			case 'video':
			case 'movie':
				valid = isValidVideo(e);
				break;
			case 'mpg':
			case 'mpeg':
				valid = isValidMPEGVideo(e);
				break;
			case 'pdf':
				valid = isValidPDF(e);
				break;
			case 'jpeg':
			case 'image-jpeg':
			case 'jpeg-image':
			case 'image/jpeg':
				valid = isValidJPEGImage(e);
				break;
			case 'integer':
			case 'int':
			case 'number':
			case 'num':
				valid = isValidInteger(e);
				break;
			case 'unsignedint':
				valid = isValidUnsignedInteger(e);
				break;			
			case 'float':
			case 'real':
				valid = isValidFloat(e);
				break;
			case 'unsignedfloat':
				valid = isValidUnsignedFloat(e);
				break;
		}
		if (!valid) return false;
		
		if ((e.maxLength != null) && (e.maxLength != "")) {
			if (! checkLength(e))
				return false;
		}
		
		if ((e.minLength != null) && (e.minLength != "")) {
			if (! checkMinLength(e))
				return false;
		}
	}			
	return true;  // all form fields are valid
}
