// (c) 1999-2006 Bright Interactive Limited. All rights reserved.
// http://www.bright-interactive.com | info@bright-interactive.com
// Tel: 0870 240 6520
// Author: Eric Clack, d8, 23July06

// Check that fields on a form are properly filled.
// Configured by using special _validate_* fields on the form, or
// by calling the set_* functions below.
//
// Use the following hidden fields to control validation:
// 		<input type="hidden" name="_validate_required" 
//					 value="fieldname1,fieldname2,etc">
// 		<input type="hidden" name="_validate_email" 
//					 value="fieldname1,fieldname2,etc">
// They only affect the field in the form in which they are used and
// the hidden fields can appear more than once in the form (e.g. if
// the form has repeated elements generated by a loop).
//
// Finally, use title tags on your fields to make errors more readable.
//   <input name="tel1" title="First Phone Number" ...>
//
// Simply add an event onsubmit="return validate(this);" to your form.


//-------------------------------------------------------------------
// Functions to set required, numeric, emailaddr fields
// Call these in <body onload="">
// e.g. set_required( ['username', 'password'] );
// OR USE _validate_* hidden fields.
//
// In all of these functions you can specify an optional
// form parameter which is the form object in which the
// field resides. Not specifying this results in only
// the first field matching on name being set -- not
// good for pages with multiple forms!
//-------------------------------------------------------------------


// What colour should error fields be?
var error_bg_color = "#fcc";

function set_required( field_array, form )
{
	var n;
	for( n = 0; n < field_array.length; n++ ) {
		try {
			if (form === undefined) {
				document.getElementsByName(field_array[n])[0].required = 1;	
			}
			else {
				// We have a form, but elements might return
				// an array if it's for a set of radio buttons
				if (form.elements[field_array[n]].value === undefined) {
					// Radios, so set the first one
					form.elements[field_array[n]][0].required = 1;
				}
				else {
					form.elements[field_array[n]].required = 1;
				}
			}
		}
		catch (error) {
			if (!error instanceof TypeError) {
				alert("Unexpected error : " + error);
			}
		}
	}
}

function unset_required( field_array, form )
{
	var n;
	for( n = 0; n < field_array.length; n++ ) {
			if (form === undefined) {
				document.getElementsByName(field_array[n])[0].required = 0;	
			}
			else {
				form.elements[field_array[n]].required = 0;
			}
	}
}


function set_numeric( field_array, form )
{
	var n;
	for( n = 0; n < field_array.length; n++ ) {
		try {

			if (form === undefined) {
				document.getElementsByName(field_array[n])[0].numeric = 1;
			}
			else {
				form.elements[field_array[n]].numeric = 1;
			}
		}
		catch (error) {
			if (!error instanceof TypeError) {
				alert("Unexpected error : " + error);
			}
		}
	}
}


function set_emailaddr( field_array, form )
{
	var n;
	for( n = 0; n < field_array.length; n++ ) {
		try {
			if (form === undefined) {
				document.getElementsByName(field_array[n])[0].emailaddr = 1;	
			}
			else {
				form.elements[field_array[n]].emailaddr = 1;
			}
		}
		catch (error) {
			if (!error instanceof TypeError) {
				alert("Unexpected error : " + error);
			}
		}
	}
}


function parse_validation_rules(f)
	// Find _validate_* hidden fields in form f and
	// call above functions as required.
{

	function value_list(field)
	// Return a list of names from the field or array
	// of field. Values are assumed to be comma separated.
	{
		var items = null;
		
		// field might be a list? In which case append
		// values from elements
		if (field.value === undefined) {
			var values = "";
			for (var i=0; i< field.length; i++) {
				if (values) { values += ","; }
				values += field[i].value;
			}
			items = values.split(',');
		}
		else {
			items = field.value.split(',');
		}
		return items;
	}

	// Find the hidden fields
	var req_list = f.elements["_validate_required"];
	var email_list = f.elements["_validate_email"];
	
	// Now call appropriate functions to register field names
	if (req_list) {
		set_required( value_list(req_list), f );
	}
	if (email_list) {
		set_emailaddr( value_list(email_list), f );
	}
}



//-------------------------------------------------------------------
// The validate function
// Call this using onSubmit="return validate(this);"
//-------------------------------------------------------------------


function validate(f)
{

	function concat_error_message(error, e, msg) 
	// Generate error string for e, using message msg
	// and concatenate it onto end of error
	// Set first_bad_field if not set
	{

		if (error != "") error += ", ";
		if (msg) msg = " "+msg;

		// Generate error string
		if (e.alt) error += e.alt + msg;
		else if (e.title) error += e.title + msg;
		else error += e.name + msg;
		
		// Record first bad field
		if (first_bad_field == null) first_bad_field = e;
		
		// Colour field
		e.style.backgroundColor = error_bg_color;
		
		return error;
	}

	var msg;
	var empty_fields = "";
	var errors = "";
	var first_bad_field = null;
	
	// Which radio buttons have we checked?
	var checked_radios = [];
	
	// Parse _validate hidden fields
	parse_validation_rules(f);
	

	for(var i = 0; i < f.length; i++ ) {
		var e = f.elements[i];
		
		
		if ((e.type == "text") || (e.type == "textarea") || (e.type == "password")
				|| (e.type == "file")) {
		
			// is the field required, but empty?
			if (e.required && ((e.value == null) || (e.value == "") || isblank(e.value))) {
				empty_fields = concat_error_message(empty_fields, e, "");
				continue;
			}

			// If the field is required, or it's optional, but has content...
			
			if (e.required || ((e.value != null) && (e.value != "") && (!isblank(e.value)))) {
				
				// now check numerics
				if ((e.numeric) && (!isnumber(e.value))) {
					errors = concat_error_message(errors, e, "must be a number");
				}
				// now check email addresses
				if ((e.emailaddr) && (!isemail(e.value))) {
					errors = concat_error_message(errors, e, "is not an email address");
				}	
			}	
		}
		else if ((e.type == "radio" || e.type == "checkbox") && e.required && !checked_radios[e.name]) {
			// Check radio buttons, provided we've not checked this one before
			if (!radio_value(e.name)) {
				empty_fields = concat_error_message(empty_fields, e, "");
			}
			checked_radios[e.name] = 1;			
		}
		else if (e.type == "select-one" && e.required && e.options[0].selected) {
			// For select boxes, check whether default value selected
			empty_fields = concat_error_message(empty_fields, e, "");
		}

	}

	// any errors?
	if (!empty_fields && !errors) {
		return true;
	}

	msg =  "The form was not submitted because of the following ";
	msg += "errors. Please correct them and try again.\n-\n";

	if (empty_fields) {
		msg += "The following required fields are empty:\n" + empty_fields;
		if (errors) msg += "\n-\n";
	}
	msg += errors;
	alert (msg);
	
	first_bad_field.focus();
	return false;
}


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 isnumber(n)
{
	var v = parseFloat(n);
	if (isNaN(v)) {
		return false;
	}
	return true;
}


function isemail(e)
{
	return e.match( /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z0-9_\-\.]+)$/);
}


function radio_value(rname) {
	// Return the value of the checked radio button or null
	// otherwise.
	var radios = document.getElementsByName(rname);
	var value = null;
	for (var i=0; i<radios.length; i++){
		if (radios[i].checked) {
			value = radios[i].value;
		}
	}
	return value;
}
