/*****************************************************************************************************************************************/
/* 
For maximum length, please use the maxlength attribute in a tag, this stops users from inputting more characters than required
For minimum length, please use the min_length attribute
 
Regular Expression Patterns
Numeric: pattern="^\d*[0-9](|.\d*[0-9]|,\d*[0-9])?$" -- allows negatives, commas and decimals. No validation on number of commas or decimal points
currency: pattern="/^-?[\£\$\€][0-9\.\,]+$/;"
String: pattern="^([1-zA-Z0-1@.\s]{1,255})$" -- A general string validation to insure no malicious code is being passed through user input. General enough too allow email address, names, address, passwords, so on. Disallows ',\*&$<> or other characters that could cause issues. 
Password: pattern="^([a-zA-Z0-9!&amp;amp;quot;#$%&amp;amp;amp;',/:;&amp;amp;lt;=&amp;amp;gt;@_`|~ \(\)\*\+\-\.\?\[\]\\\^\{\}])*$" -- validate passwords to make sure that they only contain ascii character 32 through ascii character 126.
Hour: pattern="([0-1][0-9]|2[0-3]):[0-5][0-9]" == Validate an hour entry to be between 00:00 and 23:59 
*/
/*****************************************************************************************************************************************/
 
/*****************************************************************************************************************************************/
 /* global variables
  sFinalErrorMessage  - the alert message sent to the user
  bSubmitForm   - return to submit the form
  sElementsChecked  - used for any radio and checkboxes that have more than one element in the array
        so that if already checked we don't check them again
  iDateMonth   - used to hold month if not a number
  sDateString   - used for datetime functionality
 */
/*****************************************************************************************************************************************/
 
var sFinalErrorMessage, bSubmitForm, sElementsChecked, iDateMonth, sDateString;
 
/*****************************************************************************************************************************************/
 /*  control function for the validation
 
  wish to split into 3 groups so that we are not validating hidden elements, button elements and submit elements.
 */
/*****************************************************************************************************************************************/
function validateForm(bWeAreSubmittingForm) { 
 // reset global varaibles
 
 sFinalErrorMessage = "Following are required fields.    \n\n"; 
 sElementsChecked = "";
 bSubmitForm = true;
 iDateMonth = "";
 sDateString = "";
 
 validateInputFields();  // validate the fields that have type='input'
 validateTextAreas();     // validate the fields that have type='textarea'
 validateSelectFields();  // validate the fields that have type='select'
 
 if (bWeAreSubmittingForm) {
  if (!bSubmitForm) {
   alert(sFinalErrorMessage);
  }
 }
 return bSubmitForm;
}
 
/* returns the element attribute value */
function getAttributeValue(oElement, sAttribute, bReturn_null) {
  var sAttribute = oElement.getAttribute(sAttribute); 
  if (sAttribute == null && !bReturn_null) {
   sAttribute = 0;
  }
 return sAttribute;
}
 
/* generates the error message and sets the submit form boolean to false if there is an error */
function generateErrorMessage(bValidated, sErrorMessage) {
 if (!bValidated) {
  if (bSubmitForm) {
   bSubmitForm = false;
  }
  sFinalErrorMessage += sErrorMessage + "\n"
 }
 // no return required
}
 
function generateFieldSettings(oElement, sColour) {
 // sets the background colour of the elements
 oElement.style.background = sColour;
}
 
/*****************************************************************************************************************************************/
 /* validate the input elements
   - texttype="xxx"
     this is used to distinguish between the input elements and the type of checking that will be conducted.
   - errmessage="xxx"
     this is used to have the input element checked, 
     if it is mandatory then min_length=1 is required
 */
/*****************************************************************************************************************************************/
function validateInputFields() {
 var oElement, sType, sErrMsg;
 
 // get the elements that have type='input'
 var elements = document.getElementsByTagName('input'); 
 
 // loop through all input elements in form 
 for(var i = 0; i < elements.length; i++) { 
  oElement = elements.item(i);
  sType = getAttributeValue(oElement, 'type', true);
  sErrMsg = getAttributeValue(oElement, 'errmessage', true);
 
  if (sErrMsg != null) {
   switch (sType) {
    case "text":
    case "hidden":
     switch (getAttributeValue(oElement, 'texttype', true)) {
      case "email":
       validateEmailText(oElement, sErrMsg);
       break;
      case "date":
       validateDate(oElement, sErrMsg);
       break;
      case "numeric":
       validateNumeric(oElement, sErrMsg);
       break;
      default:
       validateTextPattern(oElement, sErrMsg);
       break;
     }
     break;
    case "checkbox":
     validateCheckbox(oElement, sErrMsg);
     break;
    case "radio":
     validateRadio(oElement, sErrMsg);
     break;
   }
  }
 }
}
 
/*****************************************************************************************************************************************/
 /* validates the textarea elements 
   - if mandatory min_length>0
     If min_length is 1 then the email addres is mandatory and there must be a value in this field, min_length defaults to 0 if not set in the tag
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
   - pattern="xxx"
     If there is a pattern match for the textarea field, must be a reg exp type
 */
/*****************************************************************************************************************************************/
function validateTextAreas() {
 var oElement, sErrMsg;
 var elements = document.getElementsByTagName('textarea'); 
 
 for(var i = 0; i < elements.length; i++) { 
  // loop through all textarea elements in form 
  oElement = elements.item(i);
  sErrMsg = getAttributeValue(oElement, 'errmessage', true);
 
  if (sErrMsg != null) {
   if (validateMinMax(oElement.value.length, getAttributeValue(oElement, 'min_length', true), getAttributeValue(oElement, 'maxlength', true), sErrMsg)) {
    validateTextPattern(oElement, sErrMsg);
   }
  }
 }
 //no return required
}
 
/*****************************************************************************************************************************************/
 /* validates the select elements, single and multiple
   - if mandatory min_length>0
     If min_length is 1 then the email addres is mandatory and there must be a value in this field, min_length defaults to 0 if not set in the tag
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
   - pattern="xxx"
     If there is a pattern match for the textarea field, must be a reg exp type
 */
/*****************************************************************************************************************************************/
function validateSelectFields() {
 // Validates all elements of the form that have a select tag
 var oElement, sErrMsg;
 var elements = document.getElementsByTagName('select'); 
 
 for(var i = 0; i < elements.length; i++) { 
  // loop through all select elements in form 
  oElement = elements.item(i);
  sErrMsg = getAttributeValue(oElement, 'errmessage', true);
 
  if (sErrMsg != null) {
   if (getAttributeValue(oElement, 'multiple', true)) {
    // multiple select
    validateMultipleSelectBox(oElement, sErrMsg);
   
   } else {
    // single select
    validateSelectBox(oElement, sErrMsg);
   }
  }
 }
}
 
/*****************************************************************************************************************************************/
 /*  validates sincle select boxes for:
    minimum selected index
    maximum selected index
    if the selectedindex has another element attached to and that if the selectedindex matches then if the other element has text in it
 
  If you want to only validate numeric numbers, use pattern instead
   - if mandatory min_length > 0
     If min_length is 1 then the radio value is mandatory and there must be a value in this field.
     If min_length is not set the default is 0
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
   - formnumber="xxx"
     Used if we are not validating the first form, 
      this is due to the fact that we are referencing the particular element array and not just the elemnt.
   - min_req="xxx"
     The minimum selected index required for validation
   - max_req="xxx"
     The maximum selected index required for validation
   - other_index="xxx"
     The selected index that has an input element attached to it
   - attachedto="xxx"
     If a hidden element is attached to the select, this is the name of the hidden element
   - other_errmessage="xxx"
     The attachedto error message, this can also have a minimum length, and validation
   - formnumber="xxx"
     Used if we are not validating the first form, for the attachedto 
     
 */
/*****************************************************************************************************************************************/
function validateSelectBox(oElement, sErrorMessage) {
 var iSelectedIndex = oElement.selectedIndex;
 // check for minimum & maximum selected index
 if (validateMinMax(iSelectedIndex, getAttributeValue(oElement, 'min_req', true), getAttributeValue(oElement, 'max_req', true), sErrorMessage)) {
  if ((getAttributeValue(oElement, 'other_index', true)) != null) {
   // does the selectedindex have an attached element to it, if so do we need to validate this
   if (parseFloat(iSelectedIndex) == parseFloat(getAttributeValue(oElement, 'other_index', false))) {
    var sAttachedName = getAttributeValue(oElement, 'attachedto', true);
    var iFormNumber = getAttributeValue(oElement, 'formnumber', false);
    var oAttachedElement = document.forms[iFormNumber].elements[sAttachedName];
    var sAttachedErrorMessage = getAttributeValue(oAttachedElement, 'other_errmessage', true);
 
    validateTextPattern(oAttachedElement, sAttachedErrorMessage);
   }
  }
 }
}
 
/*****************************************************************************************************************************************/
 /* email validation requirements 
   - texttype="email"
     this must be email so that the input field is aware that it is an email validation type.
   - if mandatory min_length>0
     If min_length is 1 then the email addres is mandatory and there must be a value in this field, min_length defaults to 0 if not set in the tag
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
 */
/*****************************************************************************************************************************************/
/* Validate the email address to ensure it is correct. */
 
function validateEmailText(oElement, sErrorMessage) {
 // does the element value meet the min_length value, if min_length is not set then this is 0 and the length will pass through.
 if (oElement.value.length < getAttributeValue(oElement, 'min_length', false)) {
   generateErrorMessage(false, sErrorMessage);
   return false;
 }
 // if we have a value in the element then check that it is a valid email address
 if (oElement.value != "") {
  generateErrorMessage(emailCheck(oElement.value), sErrorMessage);
 }
}
 
function emailCheck (sEmailValue) {
 /* The following variable tells the rest of the function whether or not to verify that the address ends in a two-letter country or well-known TLD.  
  1 means check it, 0 means don't. */
 var checkTLD = 1;
 /* The following is the list of known TLDs that an e-mail address must end with. */
 var knownDomsPat = /^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;
 /* The following pattern is used to check if the entered e-mail address fits the user@domain format.  It also is used to separate the username from the domain. */
 var emailPat = /^(.+)@(.+)$/;
 /* The following string represents the pattern for matching all special characters.  We don't want to allow special characters in the address. 
  These characters include ( ) < > @ , ; : \ " . [ ] */
 var specialChars = "\\(\\)><@,;:\\\\\\\"\\.\\[\\]";
 /* The following string represents the range of characters allowed in a username or domainname.  It really states which chars aren't allowed.*/
 var validChars = "\[^\\s" + specialChars + "\]";
 /* The following pattern applies if the "user" is a quoted string (in which case, there are no rules about which characters are allowed and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com is a legal e-mail address. */
 var quotedUser = "(\"[^\"]*\")";
 /* The following pattern applies for domains that are IP addresses, rather than symbolic names.  
  E.g. joe@[123.124.233.4] is a legal e-mail address. NOTE: The square brackets are required. */
 var ipDomainPat = /^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
 /* The following string represents an atom (basically a series of non-special characters.) */
 var atom = validChars + '+';
 /* The following string represents one word in the typical username.
 For example, in john.doe@somewhere.com, john and doe are words. Basically, a word is either an atom or quoted string. */
 var word = "(" + atom + "|" + quotedUser + ")";
 // The following pattern describes the structure of the user
 var userPat = new RegExp("^" + word + "(\\." + word + ")*$");
 /* The following pattern describes the structure of a normal symbolic domain, as opposed to ipDomainPat, shown above. */
 var domainPat = new RegExp("^" + atom + "(\\." + atom +")*$");
 /* Finally, let's start trying to figure out if the supplied address is valid. */
 
 /* Begin with the coarse pattern to simply break up user@domain into different pieces that are easy to analyze. */
 var matchArray = sEmailValue.match(emailPat);
 
 if (matchArray == null) {
  /* Too many/few @'s or something; basically, this address doesn't even fit the general mould of a valid e-mail address. */
  //alert("Email address seems incorrect (check @ and .'s)");
  return false;
 }
 var user = matchArray[1];
 var domain = matchArray[2];
 
 // Start by checking that only basic ASCII characters are in the strings (0-127).
 for (i=0; i<user.length; i++) {
  if (user.charCodeAt(i)>127) {
   //alert("Ths username contains invalid characters.");
   return false;
    }
 }
 for (i=0; i<domain.length; i++) {
  if (domain.charCodeAt(i)>127) {
   //alert("Ths domain name contains invalid characters.");
   return false;
    }
 }
 
 // See if "user" is valid 
 if (user.match(userPat)==null) {
  // user is not valid
  //alert("The username doesn't seem to be valid.");
  return false;
 }
 
 /* if the e-mail address is at an IP address (as opposed to a symbolic host name) make sure the IP address is valid. */
 var IPArray=domain.match(ipDomainPat);
 if (IPArray!=null) {
 // this is an IP address
 for (var i=1;i<=4;i++) {
  if (IPArray[i]>255) {
   //alert("Destination IP address is invalid!");
   return false;
    }
 }
 return true;
 }
 
 // Domain is symbolic name.  Check if it's valid.
 var atomPat=new RegExp("^" + atom + "$");
 var domArr=domain.split(".");
 var len=domArr.length;
 for (i=0;i<len;i++) {
  if (domArr[i].search(atomPat)==-1) {
   //alert("The domain name does not seem to be valid.");
   return false;
    }
 }
 /* domain name seems valid, but now make sure that it ends in a known top-level domain (like com, edu, gov) or a two-letter word,
 representing country (uk, nl), and that there's a hostname preceding  the domain or country. */
 if (checkTLD && domArr[domArr.length-1].length!=2 && domArr[domArr.length-1].search(knownDomsPat)==-1) {
  //alert("The address must end in a well-known domain or two letter " + "country.");
  return false;
 }
 
 // Make sure there's a host name preceding the domain.
 if (len<2) {
  //alert("This address is missing a hostname!");
  return false;
 }
 
 // If we've gotten this far, everything's valid!
 return true;
}
 
/*****************************************************************************************************************************************/
 /* validates the text elements, using a pattern of regexp for reference, and a minimum length of 1 character is required
   - if mandatory min_length > 0
     If min_length is 1 then the text value is mandatory and there must be a value in this field.
     If min_length is not set the default is 0
   - pattern="xxx"
     If there is a pattern match for the input field, must be a reg exp type
   - nonnullvalue=" "
     If the input field needs to be empty, but we don't want to send a null to the database
   - formnumber=0
     If the form is not zero, used for the nonnullvalue
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
*/
/*****************************************************************************************************************************************/
function validateTextPattern(oElement, sErrorMessage) {
 var sValue = oElement.value;
 
 // does the element value meet the min_length value, if min_length is not set then this is 0 and the length will pass through.
 if (sValue.length < getAttributeValue(oElement, 'min_length', false)) {
   generateErrorMessage(false, sErrorMessage);
   return false;
 }
 
 if (getAttributeValue(oElement, 'nonnullvalue', true) != null) {
  if (sValue.length == 0) {
   document.forms[getAttributeValue(oElement, 'formnumber', false)].elements[oElement.name].value = getAttributeValue(oElement, 'nonnullvalue', true);
   return true;
  } else if (sValue == getAttributeValue(oElement, 'nonnullvalue', true)) {
   return true;
  }
 }
 
 // if we have a value and if there is a pattern set, check it.   
 var sPattern = getAttributeValue(oElement, 'pattern', true);
 
 if (sValue != "" && sPattern != null) {
   // validate the value of this element, using its defined pattern 
  var offendingChar = sValue.match(sPattern);
  // if an invalid character is found or the element was left emtpy 
  if (offendingChar == null) { 
   generateErrorMessage(false, sErrorMessage) ;
   return false;
  }
 }
 //no return required
}
 
/*****************************************************************************************************************************************/
 /* validates the date based on the requested dateformat, the user can use the standard separators
   - texttype="date"
     this must be date so that the input field is aware that it is a date validation type.
   - if mandatory min_length > 0
     If min_length >0  then the datetime field is mandatory and there must be a value in this field. 
     If this attribute is not set then the default is 0
   - dateformat="xxx"
     formats include null, ddmmyy, mmddyy
   - min_req="xxx" 
     minimum date that can be entered
   - max_req="xxx"
     maximum date that can be entered
   - nonnullvalue=" "
     If the input field needs to be empty, but we don't want to send a null to the database
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
*/
/*****************************************************************************************************************************************/
function validateDate(oElement, sErrorMessage) {
 
 var sValue = oElement.value;
 /*
 Using a forward slash is not correct date formatting in sql
 Need to change so that the database will accept this.
 */
 var rExp = /\\/gi;
 sValue = sValue.replace(rExp, "/");
 oElement.value = sValue;
 sDateString = sValue;
 
 if (getAttributeValue(oElement, 'nonnullvalue', true) != null) {
  if (sValue.length == 0) {
   document.forms[getAttributeValue(oElement, 'formnumber', false)].elements[oElement.name].value = getAttributeValue(oElement, 'nonnullvalue', true);
   return true;
  } else if (sValue == getAttributeValue(oElement, 'nonnullvalue', true)) {
   return true;
  }
 }
 
 // does the element value meet the min_length value, if min_length is not set then this is 0 and the length will pass through.
 if (sValue.length < getAttributeValue(oElement, 'min_length', false)) {
   generateErrorMessage(false, sErrorMessage);
   return false;
 }
 
 
 // if there is a value in the element, let's check it.
 if (sValue != "") {
  var sDateFormat = getAttributeValue(oElement, 'dateformat', true);
  if (sDateFormat == null) {
   sDateFormat = "ddmmyy";
  }
  
  if (!validateDateParts(oElement, sValue, sDateFormat, true, sDateFormat)) {
   generateErrorMessage(false, sErrorMessage);
  } else {
   validateMinMaxDate(sValue, sDateFormat, getAttributeValue(oElement, 'min_req', true), getAttributeValue(oElement, 'max_req', true), sErrorMessage)
  }
 }
 // no return required
}
 
function validateDateParts(oElement, sValue, sDateFormat, bConvertToFormat, sConvertToFormat) {
 var sPattern = "[-/\\ ]"
 var sSeparator = sValue.match(sPattern);
 
 var iPos1 = sValue.indexOf (sSeparator, 1); // where is the first date separator
 var sStr1 = sValue.substring(0, iPos1);  // what is the first part of the date string
 
 var iPos2 = sValue.indexOf (sSeparator, iPos1+1); // where is the second date separator
 var sStr2 = sValue.substring(iPos1+1, iPos2); // what tis the second part of the date string
 
 var sStr3 = sValue.substring(iPos2+1, sValue.length);  // what is the last part of the date string
 
 if (iPos1 == -1 || iPos2 == -1 || sStr3.length < 2) {
  // if there is no separators for the date and the length of the last part is less than 2
  return false;
 }
 
 var bValidated;
 switch (sDateFormat) {
  case "ddmmyy":
   bValidated = validateDateFields(sStr1, sStr2, sStr3);
   break;
  case "mmddyy":   
   bValidated = validateDateFields(sStr2, sStr1, sStr3);
   break;
  case "yymmdd":
   bValidated = validateDateFields(sStr3, sStr2, sStr1);
   break;
 }
 
 if (!bValidated) {
  return false; 
 } else {
  switch (sDateFormat) {
   case "ddmmyy":
    oElement.value = convertDateToFormat(sConvertToFormat, sStr1, sStr2, sStr3)
    return convertDateToFormat(sConvertToFormat, sStr1, sStr2, sStr3);
    break;
   case "mmddyy":  
    oElement.value = convertDateToFormat(sConvertToFormat, sStr2, sStr1, sStr3);
    return convertDateToFormat(sConvertToFormat, sStr2, sStr1, sStr3);
    break;
   case "yymmdd":
    oElement.value = convertDateToFormat(sConvertToFormat, sStr3, sStr2, sStr1);
    return convertDateToFormat(sConvertToFormat, sStr3, sStr2, sStr1);
    break;
  }
 
 }
}
 
function convertDateToFormat(sDateFormat, sDay, sMonth, sYear) {
 
 if (!isNaN(sMonth)) {
  sMonth = getMonthAsString(sMonth);
 }
 
 switch (sDateFormat) {
  case "ddmmyy":
   return sDay + " " + sMonth + " " + sYear;
   break;
  case "mmddyy":   
   return sMonth + " " + sDay + " " + sYear;
   break;
  case "yymmdd":
   return sYear + " " + sMonth + " " + sDay;
   break;
 }
}
 
function validateDateFields(iDay, iMonth, iYear) {
 // validates the date fields, making sure that they are the correct numbers ie. 1 to 12 for month
 // do we start with 0 in the date part string 
 if (iDay.charAt(0) == "0") {
  iDay = iDay.charAt(1);
 }

 if (iMonth.charAt(0) == "0") {
  iMonth = iMonth.charAt(1);
 }
 if (iYear.charAt(0) == "0") {
  iYear = iYear.charAt(1);
 }
 
 // are they integers?
 if (parseInt(iDay)) {
  iDay = parseInt(iDay);
 } else {
  return false;
 }
 
 if (parseInt(iMonth)) {
  iMonth = parseInt(iMonth);
 } else {
  if (isNaN(iMonth)) {
   iMonth = getMonthAsInteger(iMonth);
   if (iMonth == "") {
    return false;
   }
  }
 }
 
 if (parseInt(iYear)) {
  iYear = parseInt(iYear);
 } else {
  if (iYear != "00") {
   return false;
  }
 }
 
 // scaling the year to 4 digits
 if (iYear == "00") {
  iYear = 2000;
 } else if (iYear > 0 && iYear <= 49) {
  iYear = 2000 + iYear;
 } else if (iYear > 49 && iYear <= 99) {
  iYear = 1900 + iYear
 } 
 
 if (iDay < 1) {
  return false;
 }
 
 switch (iMonth) {
  case 1:
  case 3:
  case 5:
  case 7:
  case 8:
  case 10: 
  case 12: 
   // 31 days
   if (iDay > 31) {
    return false;
   }
   break;
  case 9:
  case 4:
  case 6:
  case 11:
   //30 days
   if (iDay > 30) {
    return false;
   }
   break;
  case 2:
   //feb
   if (iDay == 29) {
    if ((iYear % 4 == 0 && iYear % 100 != 0) || iYear % 400 == 0) {
     return true;
    } 
    return false;
   } else {
    if (iDay > 28) {
     return false;
    }
   }
   break;
  default:
   // not a valid month
   return false;
   break;
 }
 // return required
 return true;
}
 
function getMonthAsString(sValue) {
 switch (sValue) {
  case "1":
  case "01":
   return "Jan";
   break;
  case "2":
  case "02":
   return "Feb";
   break;
  case "3":
  case "03":
   return "Mar";
   break;
  case "4":
  case "04":
   return "Apr";
   break;
  case "5":
  case "05":
   return "May";
   break;
  case "6":
  case "06":
   return "Jun";
   break;
  case "7":
  case "07":
   return "Jul";
   break;
  case "8":
  case "08":
   return "Aug";
   break;
  case "9":
  case "09":
   return "Sep";
   break;
  case "10":
   return "Oct";
   break;
  case "11":
   return "Nov";
   break;
  case "12":
   return "Dec";
   break;
 }
}
 
function getMonthAsInteger(sValue) {
 sValue = sValue.toLowerCase( )
 switch (sValue) {
  case "jan":
  case "january":
   iDateMonth = 1;
   break;
  case "feb":
  case "february":
   iDateMonth = 2;
   break;
  case "mar":
  case "march":
   iDateMonth = 3;
   break;
  case "apr":
  case "april":
   iDateMonth = 4;
   break;
  case "may":
   iDateMonth = 5;
   break;
  case "jun":
  case "june":
   iDateMonth = 6;
   break;
  case "jul":
  case "july":
   iDateMonth = 7;
   break;
  case "aug":
  case "august":
   iDateMonth = 8;
   break;
  case "sep":
  case "september":
   iDateMonth = 9;
   break;
  case "oct":
  case "october":
   iDateMonth = 10;
   break;
  case "nov":
  case "november":
   iDateMonth = 11;
   break;
  case "dec":
  case "december":
   iDateMonth = 12;
   break;
  default:
   iDateMonth = "";
   break;
 }
 sDateString = sDateString.toLowerCase();
 sDateString = sDateString.replace(sValue, iDateMonth);
 
 return iDateMonth;
}
/*****************************************************************************************************************************************/
 /* validates a numeric field with a minimum &/or maximum request.
  If you want to only validate numeric numbers, use pattern instead
   - if mandatory min_length > 0
     If min_length is 1 then the text value is mandatory and there must be a value in this field.
     If min_length is not set the default is 0
   - min_req="xxx"
     Then a minimum number is required for the numeric
   - max_req="xxx"
     Then a maximum number is required for the numeric
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
 
 */
/*****************************************************************************************************************************************/
function validateNumeric(oElement, sErrorMessage) {
 var sValue = oElement.value; 
 
 // does the element value meet the min_length value, if min_length is not set then this is 0 and the length will pass through.
 if (sValue.length < getAttributeValue(oElement, 'min_length', false)) {
   generateErrorMessage(false, sErrorMessage);
   return false;
 }
 // if there is a value in the element, let's check it.
 if (sValue != "") {
  validateMinMax(sValue, getAttributeValue(oElement, 'min_req', true), getAttributeValue(oElement, 'max_req', true), sErrorMessage);
 }
 // no return required
}
 
function validateMinMaxDate(sValue, sDateFormat, sMin, sMax, sErrorMessage) {
 // Validates the date values with a minimum, maximum or both
 if (sMin == "") { sMin = null; }
 if (sMin != null) { 
  sMin = validateDateParts(sMin, sDateFormat, true, "mmddyy")
  sMin = new Date(sMin);
 }
 
 if (sMax == "") { sMax = null; }
 if (sMax != null) {
  sMax = validateDateParts(sMax, sDateFormat, true, "mmddyy")
  sMax = new Date(sMax);
 }
 sValue = validateDateParts(sValue, sDateFormat, true, "mmddyy")
 sValue = new Date(sValue);
 
 // is there a minimum & maximum attribute?
 if (sMin != null && sMax != null) { 
  if (sValue < sMin || sValue > sMax) { 
   generateErrorMessage(false, sErrorMessage);
   return false;
  }
 }
 
 // is there only a minimum attribute?
 if (sMin != null && sMax == null) { 
  if (sValue < sMin) {
   generateErrorMessage(false, sErrorMessage);
   return false;
  }
 } 
 
 // is there only a maximum attribute?
 if (sMin == null && sMax != null) { 
  if (sValue > sMax) {
   generateErrorMessage(false, sErrorMessage);
   return false;
  }
 }
 return true;
}
 
function validateMinMax(sValue, sMin, sMax, sErrorMessage) {
 // Validates the numeric values with a minimum, maximum or both
 
 var fValue = parseFloat(sValue);
 var fMin = parseFloat(sMin);
 var fMax = parseFloat(sMax);
 
 // is there a minimum & maximum attribute?
 if (fMin != null && fMax != null) { 
  if (fValue < fMin || fValue > fMax) { 
   generateErrorMessage(false, sErrorMessage);
   return false;
  }
 }
 
 // is there only a minimum attribute?
 if (fMin != null && fMax == null) { 
  if (fValue < fMin) {
   generateErrorMessage(false, sErrorMessage);
   return false;
  }
 } 
 
 // is there only a maximum attribute?
 if (fMin == null && fMax != null) { 
  if (fValue > fMax) {
   generateErrorMessage(false, sErrorMessage);
   return false;
  }
 }
 
 return true;
}
 
/*****************************************************************************************************************************************/
 /*  validates the radio element(s) on the form, including a single radio button or multiple radio buttons with the same name
 
  If you want to only validate numeric numbers, use pattern instead
   - if mandatory min_length > 0
     If min_length is 1 then the radio value is mandatory and there must be a value in this field.
     If min_length is not set the default is 0
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
   - formnumber="xxx"
     Used if we are not validating the first form, 
      this is due to the fact that we are referencing the particular element array and not just the elemnt.
 */
/*****************************************************************************************************************************************/
function validateRadio(oElement, sErrorMessage) {
 var sRadioName = getAttributeValue(oElement, 'name', true); //what is the name?
 var iFormNumber = getAttributeValue(oElement, 'formnumber', false); // what is the form number? default is 0
 var oRadio = document.forms[iFormNumber].elements[sRadioName];  // radio elements
 var iRadioChecked = 0; //counter to check if a radio button has been selected.
 
 // have we already checked this radio element?
 if (sElementsChecked.indexOf(sRadioName,0) == -1) {
  // add the element name to global variable for future reference
  sElementsChecked += sRadioName + ',';
  // single radio element that hasn't been checked
  if (oRadio.length == null && oRadio.checked) {
    iRadioChecked++;
  }
  // multiple radio elements
  for (var x=0; x < oRadio.length; x++) {
   if (oRadio[x].checked) { 
    iRadioChecked++;
    break;  // the radio button has been selected, no need to continue through the loop
   }
  }
  
  if (iRadioChecked == 0) {
   generateErrorMessage(false, sErrorMessage);
  }
 }
 // no return required
}
 
/*****************************************************************************************************************************************/
 /* validates the checkbox elements on the form, including a single checkbox or multiple checkboxes with the same name
   will also validate the checkboxes if they are not checked but a value needs to be sent through to the next page
 
  If you want to only validate numeric numbers, use pattern instead
   - if mandatory min_length > 0
     If min_length is 1 then the radio value is mandatory and there must be a value in this field.
     If min_length is not set the default is 0
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
   - formnumber="xxx"
     Used if we are not validating the first form, 
      this is due to the fact that we are referencing the particular element array and not just the elemnt.
   - novalue="xxx"
     If we wish to pass a value through to the processing page, even if the checkbox hasn't been selected
     Must be attached to other_hidden="xxx"
   - attachedto="xxx"
     If a hidden element is attached to the checkbox, this is the name of the hidden element
   - min_req="xxx"
     Minimum number of checkboxes that can be selected
   - max_req="xxx"
     Maximum number of checkboxes that can be selected    
 */
/*****************************************************************************************************************************************/
 
function validateCheckbox(oElement, sErrorMessage) {
 var sCheckBoxName = getAttributeValue(oElement, 'name', true);
 var iFormNumber = getAttributeValue(oElement, 'formnumber', false);
 var oCheckbox = document.forms[iFormNumber].elements[sCheckBoxName];
 
 var sDefaultValue = getAttributeValue(oElement, 'novalue', true);
 var sAttachedValue = "";
 var iCheckboxChecked = 0;
 
 if (sElementsChecked.indexOf(sCheckBoxName,0) == -1) {
  // add the element name to global variable for future reference
  sElementsChecked += sCheckBoxName + ',';
  // single checkbox element
  if (oCheckbox.length == null && oCheckbox.checked) {
   iCheckboxChecked++;
  }
  // multiple checkbox elements
  for (var x=0; x < oCheckbox.length; x++) {
   if (oCheckbox[x].checked) {
    sAttachedValue += oCheckbox[x].value + ",";
    iCheckboxChecked++;
   } else if (!oCheckbox[x].checked && sDefaultValue != null) {
    // do we require a default value to be passed through if the checkbox hasn't been selected?
    sAttachedValue += sDefaultValue + ",";
   }
  }
  if (sDefaultValue != null) {
   // does the checkbox have an attachedto attribute, that will hold all the checkbox values
   var sHiddenElementName = getAttributeValue(oElement, 'attachedto', true);
   document.forms[iFormNumber].elements[sHiddenElementName].value = ""; // just in case we have done this step before
   if (sHiddenElementName != null) {
    document.forms[iFormNumber].elements[sHiddenElementName].value = sAttachedValue;
   }
  }
  if (iCheckboxChecked == 0) {
   generateErrorMessage(false, sErrorMessage);
  } else {
   // do we have a minimum and maximum checkboxes to be checked?
   validateMinMax(iCheckboxChecked, getAttributeValue(oElement, 'min_req', true), getAttributeValue(oElement, 'max_req', true), sErrorMessage);
  }
 }
 // no return value required
}
 
/*****************************************************************************************************************************************/
 /*  validates any multiple select elements on the form
  will validate for any selected items or that there are items in the multiple select but they do not require selection
  
  If you want to only validate numeric numbers, use pattern instead
   - if mandatory min_length > 0
     If min_length is 1 then the radio value is mandatory and there must be a value in this field.
     If min_length is not set the default is 0
   - errMessage="xxx"
     errMessage must have a value for the input field to be validated.
   - formnumber="xxx"
     Used if we are not validating the first form, 
      this is due to the fact that we are referencing the particular element array and not just the elemnt.
   - checkforselected="yes" 
     yes: if we need to check for items that have been selected in the multiple select.
     Null: If you don't want to check for selected items, but still want to pass all the items in the select through
   - attachedto="xxx"
     If a hidden element is attached to the select, this is the name of the hidden element
   - min_req="xxx"
     The minimum number of options to be selected 
   - max_req="xxx"
     The maximum number of options to be selected 
 */
/*****************************************************************************************************************************************/
function validateMultipleSelectBox(oElement, sErrorMessage) {
 var bChecked = false;
 var iOptionSelected = 0;
 var sCheckForSelected = getAttributeValue(oElement, 'checkforselected', true);
 var sAttachedTo = getAttributeValue(oElement, 'attachedto', true);
 var iFormNumber = getAttributeValue(oElement, 'formnumber', false);
 
 for (var i = 0; i < oElement.length; i++) {
  if (sCheckForSelected != null) {
   // does the select box item need to be checked for selection?
   if (oElement.options[i].selected) {
    if (sAttachedTo != null) {
     document.forms[iFormNumber].elements[sAttachedTo].value += oElement.options[i].value + ",";
    }
    iOptionSelected++;
   }
  } else {
   // does the selection have an attached element to it? Yes, add the value to the hidden. No,  select ot
   if (sAttachedTo != null) {
    document.forms[iFormNumber].elements[sAttachedTo].value += oElement.options[i].value + ",";
   } else {
    oElement.options[i].selected = true;
   }
   iOptionSelected++;
  }
 } 
  if (iOptionSelected == 0) {
   generateErrorMessage(false, sErrorMessage);
  } else {
   // do we have a minimum and maximum checkboxes to be checked?
   validateMinMax(iOptionSelected, getAttributeValue(oElement, 'min_req', true), getAttributeValue(oElement, 'max_req', true), sErrorMessage);
  }
 // no return required
}
 
/*****************************************************************************************************************************************/
 /*  validates 2 values if they are reliant on each other for form submission
  must be included in the page's validation after the validateForm function
  
*****************************************************************************************************************************************/
 
function checkValuesExistInBoth(sValue1, sValue2) {
 if (sValue1 != "" && sValue2 != "") {
  return true;
 }
 
 if (sValue1 == "") {
  if (sValue2 == "") {
   return true;
  } else {
   return false;
  }
 }
 
 if (sValue2 == "") {
  if (sValue1 == "") {
   return true;
  } else {
   return false;
  }
 }
 
}
 
 
 function submitForm(frmName){
 	
	if(! validateForm(frmName)){
		return false;
	}
	
	return true;
 }
