// ----------------------------------------------------------------------
// Javascript form validation routines.
// Author: Stephen Poley
// Modified by FSCO
//
// Simple routines to quickly pick up obvious typos.
// All validation routines return true if executed by an older browser:
// in this case validation must be left to the server.
//
// Update Aug 2004: have tested that IE 5.0 and IE 5.5 both support DOM model
// sufficiently well, so innerHTML option removed (redundant).
//
// Update Jun 2005: discovered that reason IE wasn't setting focus was
// due to an IE timing bug. Added 0.1 sec delay to fix.
//
// Update Oct 2005: minor tidy-up: unused parameter removed
// ----------------------------------------------------------------------

var nbsp = 160;    // non-breaking space char
var node_text = 3; // DOM text node-type
var emptyString = /^\s*$/
var glb_vfld;      // retain vfld for timer thread

// Errors will prevent the form from being submitted until corrected
var error_msg = new Array();
error_msg["required"] = "ERROR: Please enter something.";
error_msg["required_sel"] = "ERROR: Please select an option.";
error_msg["required_email"] = "ERROR: An email address is required";
error_msg["email_nomatch"] = "ERROR: Email addresses do not match";
error_msg["invalid_tel"] = "ERROR: not a valid telephone number - use digits, space ()- and leading +";
error_msg["phone_short"] = "ERROR: too few digits";
error_msg["phone_long"] = "ERROR: too many digits";
error_msg["len_short"] = "ERROR: too short";
error_msg["len_long"] = "ERROR: too long";
error_msg["val_low"] = "ERROR: too low";
error_msg["val_high"] = "ERROR: too high";
error_msg["val_NaN"] = "ERROR: not a number";
error_msg["invalid_postal"] = "ERROR: not a valid postal code";
error_msg["invalid_age"] = "ERROR: not a valid age";

// Warnings are "are you sure" messages - should be double-checked by user, but will not stop form submission
var warn_msg = new Array();
warn_msg["unusual_email"] = "Unusual email address. Are you sure that address is correct?";
warn_msg["www_email"] = "Please check this email address. Email addresses starting with www or http may not be correct.";
warn_msg["age_young"] = "Bit young for this, aren't you?";
warn_msg["age_old"] = "Older than 110? Check if correct";



// -----------------------------------------
//                  trim
// Trim leading/trailing whitespace off string
// -----------------------------------------

function trim(str)
{
  return str.replace(/^\s+|\s+$/g, '')
};

///////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------
//                  setfocus
// Delayed focus setting to get around IE bug
// -----------------------------------------

function setFocusDelayed()
{
  glb_vfld.focus()
}

function setfocus(vfld)
{
  // save vfld in global variable so value retained when routine exits
  glb_vfld = vfld;
  setTimeout( 'setFocusDelayed()', 100 );
}

///////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------
//                  msg
// Display warn/error message in HTML element
// commonCheck routine must have previously been called
// -----------------------------------------

function msg(fld,     // id of element to display message in
             msgtype, // class to give element ("formwarn" or "formerror")
             message) // string to display
{
  // setting an empty string can give problems if later set to a 
  // non-empty string, so ensure a space present. (For Mozilla and Opera one could 
  // simply use a space, but IE demands something more, like a non-breaking space.)
  var dispmessage;
  if (emptyString.test(message)) 
    dispmessage = String.fromCharCode(nbsp);    
  else  
    dispmessage = message;

  var elem = document.getElementById(fld);
  elem.firstChild.nodeValue = dispmessage;  
  
  elem.className = msgtype;   // set the CSS class to adjust appearance of message
};

function highlightVfld (fld, // element to be validated)
						cond) // condition to display
{
  
  fld.className = cond
}

///////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------
//            commonCheck
// Common code for all validation routines to:
// (a) check for older / less-equipped browsers
// (b) check if empty fields are required
// Returns true (validation passed), 
//         false (validation failed) or 
//         proceed (don't know yet)
// -----------------------------------------

var proceed = 2;  

function commonCheck    (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd)   // true if required
{
  if (!document.getElementById) 
    return true;  // not available on this browser - leave validation to the server
  var elem = document.getElementById(ifld);
  if (!elem.firstChild)
    return true;  // not available on this browser 
  if (elem.firstChild.nodeType != node_text)
    return true;  // ifld is wrong type of node  

  if (emptyString.test(vfld.value)) {
    if (reqd) {
      msg (ifld, "formerror", error_msg["required"]);  
   	  highlightVfld(vfld, "formerrorField");
      setfocus(vfld);
      return false;
    }
    else {
      msg (ifld, "formwarn", "");   // OK
	  highlightVfld(vfld, "");
      return true;  
    }
  }
  return proceed;
}

// -----------------------------------------
//            validatePresent
// Validate if something has been entered
// Returns true if so 
// -----------------------------------------

function validatePresent(vfld,   // element to be validated
                         ifld )  // id of element to receive info/error msg
{
  var stat = commonCheck (vfld, ifld, true);
  if (stat != proceed) return stat;

  msg (ifld, "formwarn", ""); 
  highlightVfld(vfld, "");
  return true;
};
///////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------
//               validateEmail
// Validate if e-mail address
// Returns true if so (and also if could not be executed because of old browser)
// -----------------------------------------

function validateEmail  (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd)   // true if required
{
  var stat = commonCheck (vfld, ifld, reqd);
  if (stat != proceed) return stat;

  var tfld = trim(vfld.value);  // value of field with whitespace trimmed off
  var email = /^[^@]+@[^@.]+\.[^@]*\w\w$/
  if (!email.test(tfld)) {
    msg (ifld, "formerror", error_msg["required_email"]);
    setfocus(vfld);
	highlightVfld(vfld, "formerrorField");
    return false;
  }

  var email2 = /^[A-Za-z][\w.-]+@\w[\w.-]+\.[\w.-]*[A-Za-z][A-Za-z]$/ // Check that it looks like an email address
  var email3 = /^(www\.|http)/ // Catch addresses starting with www or http
	
  if (!email2.test(tfld)) {
    msg (ifld, "formwarn", warn_msg["unusual_email"]);
	highlightVfld(vfld, "formwarnField");
    }
  else if ( email3.test(tfld) ) {
    msg (ifld, "formwarn", 	warn_msg["www_email"]);
	highlightVfld(vfld, "formwarnField");
    }
  else { 
	  
    msg (ifld, "formwarn", "");
	highlightVfld(vfld, "clear");
  }
  return true;
};

///////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------
//            validateTelnr
// Validate telephone number
// Returns true if so (and also if could not be executed because of old browser)
// Permits spaces, hyphens, brackets and leading +
// -----------------------------------------

function validateTelnr  (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd)   // true if required
{
  var stat = commonCheck (vfld, ifld, reqd);
  if (stat != proceed) return stat;

  var tfld = trim(vfld.value);  // value of field with whitespace trimmed off
  var telnr = /^\+?[0-9 ()-]+[0-9]$/
  if (!telnr.test(tfld)) {
    msg (ifld, "formerror", error_msg["invalid_tel"]);
	   	  highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;
  }

  var numdigits = 0;
  for (var j=0; j<tfld.length; j++)
    if (tfld.charAt(j)>='0' && tfld.charAt(j)<='9') numdigits++;

  if (numdigits<6) {
    msg (ifld, "formerror", "ERROR: " + numdigits + " digits - too short");
       	  highlightVfld(vfld, "formerrorField");
	setfocus(vfld);
    return false;
  }

  if (numdigits>14) {
     highlightVfld(vfld, "formwarnField");
    msg (ifld, "formwarn", numdigits + " digits - check if correct");
  }
  else { 
    if (numdigits<10) {
      msg (ifld, "formwarn", "Only " + numdigits + " digits - check if correct");
	  highlightVfld(vfld, "formwarnField");
	}
    else {
      msg (ifld, "formwarn", "");
	  highlightVfld(vfld, "");
	}
  }
  return true;
};

///////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------
//             validateAge
// Validate person's age
// Returns true if OK 
// -----------------------------------------

function validateAge    (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd)   // true if required
{
  var stat = commonCheck (vfld, ifld, reqd);
  if (stat != proceed) return stat;

  var tfld = trim(vfld.value);
  var ageRE = /^[0-9]{1,3}$/
  if (!ageRE.test(tfld)) {
    msg (ifld, "formerror", error_msg["invalid_age"]);
	   	  highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;
  }

  if (tfld>=200) {
    msg (ifld, "formerror", error_msg["invalid_age"]);
	   	  highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;
  }

  if (tfld>110) { 
    msg (ifld, "formwarn", warn_msg["age_old"]);
  	highlightVfld(vfld, "formwarnField");
  }
  else {
    if (tfld<7) {
		msg (ifld, "formwarn", warn_msg["age_young"]);
	     highlightVfld(vfld, "formwarnField");
	}
    else {
		msg (ifld, "formwarn", "");
		highlightVfld(vfld, "");
	}
  }
     	 
  return true;
};

///////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------
//             validatePostal
// Validate Canadian postal code - A1A1A1
// Returns true if OK 
// -----------------------------------------

function validatePostal  (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd)   // true if required
{
  var stat = commonCheck (vfld, ifld, reqd);
  if (stat != proceed) return stat;

  var tfld = trim(vfld.value);
  var postalRE = /^\s*[a-ceghj-npr-tvxy]\d[a-z](\s)?\d[a-z]\d\s*$/i
  if (!postalRE.test(tfld)) {
    msg (ifld, "formerror", error_msg["invalid_postal"]);
	highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;
  }

   	  highlightVfld(vfld, "");
    msg (ifld, "formerror", "");
  return true;
};

///////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------
//             validateLen
// Validate length of field >=min, <=max
// Returns true if OK 
// -----------------------------------------

function validateLen  (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd,   // true if required
						 minsize, // max size of  field
						 maxsize) // min size of field
{
  var stat = commonCheck (vfld, ifld, reqd);
  if (stat != proceed) return stat;

  var tfld = trim(vfld.value);
  if (tfld.length>maxsize) {
    msg (ifld, "formerror", error_msg["len_long"]);
	   	  highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;
  }
  else if (tfld.length<minsize) {
    msg (ifld, "formerror", error_msg["len_short"]);
	   	  highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;
  }

   	  highlightVfld(vfld, "");
  msg (ifld, "formerror", "");
  return true;
};

///////////////////////////////////////////////////////////////////////////////////////////////

function validateSelect  (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd)   // true if required
{
  var stat = commonCheck (vfld, ifld, reqd);
  if (stat != proceed) return stat;

  var tfld = trim(vfld.value);
 
  if (tfld ==0) {
    msg (ifld, "formerror", error_msg["required_sel"]);
	   	  highlightVfld(vfld, "");
    setfocus(vfld);
    return false;
  }

    msg (ifld, "formerror", "");
	   	  highlightVfld(vfld, "formerrorField");
	return true;
};

///////////////////////////////////////////////////////////////////////////////////////////////

function validateRadio (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd)   // true if required
{

	
	fldOption = -1;
	for (i=vfld.length-1; i > -1; i--) {
		if (vfld[i].checked) {
			fldOption = i; i = -1;
		}
	}
				
	// Nothing selected - display error
	if (fldOption == -1) {
		msg (ifld, "formerror", error_msg["required_sel"]);
		setfocus(vfld[0]);
		return false;
	}

	// Something has been selected - clear error
    msg (ifld, "", "");
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////

function validateNumber (vfld,   // element to be validated
                         ifld,   // id of element to receive info/error msg
                         reqd,   // true if required
						 minvalue, // max value of  field
						 maxvalue) // min value of field
{
	var stat = commonCheck (vfld, ifld, reqd);
  if (stat != proceed) return stat;

  var tfld = vfld.value;
  if (isNaN(tfld)) {
    msg (ifld, "formerror", error_msg["val_NaN"]);
	   	  highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;	  
  }
  else if (tfld>maxvalue) {
    msg (ifld, "formerror", error_msg["val_high"]);
	   	  highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;
  }
  else if (tfld<minvalue) {
    msg (ifld, "formerror", error_msg["val_low"]);
	   	  highlightVfld(vfld, "formerrorField");
    setfocus(vfld);
    return false;
  }

   	  highlightVfld(vfld, "");
  msg (ifld, "", "");
  return true;
}

