//**************************************
//Form Validation and Handling Functions
//**************************************

//######################################
//Perform form validation and submission
//######################################
  var FORM_SubmitWasClicked    = false;
  var FORM_TheFormWasSubmitted = false;
  var RequiredFields = new Array();

  function FORM_Validate(TheForm) {

    MM_showHideLayers('WaitDiv','','show');
    if (FORM_SubmitWasClicked) {
      alert('You already clicked Submit!');
      return false;
    }
    if (FORM_TheFormWasSubmitted) {
      if (!window.confirm("The form has already been submitted.\n"
         +"Are you sure you want to submit it again?")) {
        return false;
      }
    }
    FORM_SubmitWasClicked = true;


  //Trim leading and trailing blanks from textfields
    for (var i=1;i<=TheForm.elements.length;i++) {
      var tp = TheForm.elements[i-1].type;
      if (tp == "text" || tp == "password") {
        FORM_TrimValueInTextbox(TheForm.elements[i-1]);
        FORM_RemoveNonPrintingCharactersInTextbox(TheForm.elements[i-1]);
      }else if (tp == "textarea") {
        FORM_TrimValueInTextbox(TheForm.elements[i-1]);
      }
    }


  //Check for missing required fields
    var MissingDataFieldname   = "";
    var MissingDataDescription = "";
    var TheElmType, TheElmName;
    var TheElement, TheMissingElement;
    for (var i=1; i<=TheForm.elements.length; i++) {
      TheElement = TheForm.elements[i-1];
      TheElmType = TheForm.elements[i-1].type;
      TheElmName = TheForm.elements[i-1].name;
      for (var n=1; n<=RequiredFields.length-1; n++) { //RequiredFields is pseudo 1-based
        MissingDataFieldname = RequiredFields[n].Fieldname;
        if (TheElmName == MissingDataFieldname) {

          switch (TheElmType) {

            case "text":
              if (TheElement.value == "") {
                MissingDataDescription = RequiredFields[n].FieldDescription;
              }
            break;
            case "textarea":
              if (TheElement.value == "") {
                MissingDataDescription = RequiredFields[n].FieldDescription;
              }
            break;
            case "password":
              if (TheElement.value == "") {
                MissingDataDescription = RequiredFields[n].FieldDescription;
              }
            break;

            case "checkbox":
              if (!TheElement.checked) {
                MissingDataDescription = RequiredFields[n].FieldDescription;
              }
            break;

            case "radio":
              var AnOptionIsChecked = false;
              var TheRadioGroup;
              eval('TheRadioGroup = TheForm.'+TheElmName);
              for (var j=1; j<=TheRadioGroup.length; j++) {
                if (TheRadioGroup[j-1].checked) {
                  AnOptionIsChecked = true;
                  break;
                }
              }
              if (!AnOptionIsChecked) {
                MissingDataDescription = RequiredFields[n].FieldDescription;
              }
            break;

            case "select-one":
              if (TheElement[TheElement.selectedIndex].value == "") {
                MissingDataDescription = RequiredFields[n].FieldDescription;
              }
            break;
          }//end of switch

        }//end if this is a required field
        if (MissingDataDescription != "") {break;} //out of required fields loop

      }//end required fields loop
      if (MissingDataDescription != "") {
        TheMissingElement = TheElement;
        break;
      } //out of form elements loop

    }//end form elements loop


    if (MissingDataDescription == "") {

    //Validate email addresses
      for (var n=1; n<=RequiredFields.length-1; n++) {
        Fieldname = RequiredFields[n].Fieldname;
        if (Fieldname.toLowerCase().indexOf("email") > -1) {
          var Email = eval('TheForm.'+Fieldname+'.value');
          if (!FORM_ValidateEmail(Email)) {
            alert("Sorry: Invalid email address ("+Fieldname
               +")\nValid Example: name@domain.com");
            MM_showHideLayers('WaitDiv','','hide');
            FORM_SubmitWasClicked = false;
            eval('TheForm.'+Fieldname+'.focus()');
            return false;
          }
        }
      }

    //Make all checkboxes checked, temporarily, so that they submit a value
    //(checkboxes are only sent in the query string if they are checked) 
      var CheckboxNames  = new Array();
      var CheckboxStates = new Array();
      var NumCheckboxes = 0;
      for (var i=1;i<=TheForm.elements.length;i++) {
        var tp = TheForm.elements[i-1].type;
        if (tp == "checkbox") {
          var FieldName = TheForm.elements[i-1].name;
          var IsChecked = TheForm.elements[i-1].checked;
          NumCheckboxes += 1;
          CheckboxNames[NumCheckboxes]  = FieldName;
          CheckboxStates[NumCheckboxes] = IsChecked;
          if (IsChecked) {
            TheForm.elements[i-1].value = "ck:checked";
          }else{
            TheForm.elements[i-1].checked = true;
            TheForm.elements[i-1].value   = "ck:unchecked";
          }
        }
      }

    //Assign submission time
      var T = FORM_NowArray(); //[T_UTC, T_OffsetFromUTC, T_Local]  T as dd mmm yyyy hh:mm:ss
      if (TheForm.SubmissionTime) {TheForm.SubmissionTime.value = T[3];}
      if (TheForm.SubmissionTimeUTC) {TheForm.SubmissionTimeUTC.value = T[1];}
      if (TheForm.SubmissionTimeMinsFromUTC) {
        TheForm.SubmissionTimeMinsFromUTC.value = T[2];}


alert("about to call DoCustomValidation");
    //Do custom processing (the user must create this function)
      try {
        if (!DoCustomValidation(TheForm)) {
          MM_showHideLayers('WaitDiv','','hide');
          FORM_SubmitWasClicked = false;
          return false;
        }
      }catch(e){
      }


    //Submit Form
alert("about to submit the form");
      TheForm.submit();


    //Restore checkboxes to their original state
      for (var i=1;i<=NumCheckboxes;i++) {
        eval("TheForm."+CheckboxNames[i]+".checked="+CheckboxStates[i]);
      }

      return false;


    } else {
      MM_showHideLayers('WaitDiv','','hide');
      alert(MissingDataDescription+" is required");
      if (TheMissingElement.focus()) {TheMissingElement.focus();}
      FORM_SubmitWasClicked = false;
      return false;
    }
  }



//########################################################
//Return an array of required field names and descriptions
//########################################################
  function FORM_DefineRequiredFields() {
// ---------------------------------------------------------------------------------
//| Returns a 1-based array of FORM_RequiredFieldObj objects, whose members are
//| the properties Fieldname and FieldDescription.
//|
//| Calling example:
//|   var RequiredFields = new Array();
//|   RequiredFields = FORM_DefineRequiredFields(
//|   "Business_AdBudget", "Advertising budget",
//|   "Business_Name", "Business name")
// ---------------------------------------------------------------------------------
    var args = FORM_DefineRequiredFields.arguments;

    var RequiredFields = new Array();
    var i,n, Fieldname, Fieldvalue;
    for (i=1; i<=args.length-1; i+=2) {
      n = (i+1)/2;
      Fieldname  = args[i-1];
      Fieldvalue = args[i];
      RequiredFields[n] = new FORM_RequiredFieldObj(Fieldname, Fieldvalue);
    }
    return RequiredFields;
  }

  function FORM_RequiredFieldObj(Fieldname, FieldDescription) {
    this.Fieldname        = Fieldname;
    this.FieldDescription = FieldDescription;
  }




//###########################################################
//Trim leading and trailing blanks from the text in a textbox
//###########################################################
  function FORM_TrimValueInTextbox(Textbox) {
    while(''+Textbox.value.charAt(0)==' ')
      Textbox.value = Textbox.value.substring(1,Textbox.value.length);
    var Length   = Textbox.value.length;
    var LastChar = Textbox.value.charAt(Length - 1);
    while(''+LastChar==' ') {
      Textbox.value = Textbox.value.substring(0,Textbox.value.length-1);
      Length        = Textbox.value.length;
      LastChar      = Textbox.value.charAt(Length - 1);
    }
    FORM_RemoveNonPrintingCharactersInTextbox(Textbox);
   }



//#####################################
//Trim leading and trailing blanks text
//#####################################
  function TrimText(Text) {
    var TrimmedText = Text;
    while(''+TrimmedText.charAt(0)==' ') {TrimmedText = TrimmedText.substring(1,Text.length);}
    var Length   = TrimmedText.length;
    var LastChar = TrimmedText.charAt(Length - 1);
    while(''+LastChar==' ') {
      TrimmedText = TrimmedText.substring(0,TrimmedText.length-1);
      Length        = TrimmedText.length;
      LastChar      = TrimmedText.charAt(Length - 1);
    }
    return TrimmedText;
  }


//#############################################
//Remove non-printing characters from a Textbox
//#############################################
  function FORM_RemoveNonPrintingCharactersInTextbox(Textbox) {
    var NoPrints = new RegExp("[\n\r\t]", "g");
    Textbox.value = Textbox.value.replace(NoPrints, " ");
  }



//###################################
//HTML encode reserved XML characters
//###################################
  function FORM_EncodeXmlReservedCharacters(InpText) {
    var TheText = DecodeReservedCharacters(InpText);
    TheText = TheText.replace(/&/g, "&amp;");
    TheText = TheText.replace(/</g, "&lt;");
    TheText = TheText.replace(/>/g, "&gt;");
    TheText = TheText.replace(/'/g, "&apos;");
    TheText = TheText.replace(/"/g, "&quot;");
    return TheText;
   }



//######################################
//Decode encoded reserved XML characters
//######################################
  function FORM_DecodeXmlReservedCharacters(InpText) {
    var TheText = InpText;
    TheText = TheText.replace(/&amp;/g, "&");
    TheText = TheText.replace(/&lt;/g, "<");
    TheText = TheText.replace(/&gt;/g, ">");
    TheText = TheText.replace(/&apos;/g, "'");
    TheText = TheText.replace(/&quot;/g, '"');
    return TheText;
  }



//###########################
//Remove all blanks from text
//###########################
  function FORM_NoBlanks(InpString) {
    var Blank = new RegExp(" ", "g"); //g means replace all, i means ignore case
    var OutString;
    OutString = InpString.replace(Blank, "");
    return OutString;
   }




//####################################
//Restrict a textbox field to numerals
//####################################
  function FORM_RestrictToNumeralKey(EventObj) {

// ---------------------------------------------------------------------------------
//| To be called via onKeyDown="FORM_RestrictToNumeralKey(event);" in a textbox.
//|
//| This function cancels keys other than:
//|    0     - no key, happens when the textbox gets the focus
//|    8     - backspace
//|   46     - delete
//|   48- 57 - numerals 0-9
//|   96-105 - keypad numerals
//|
//| This will disallow pasting with ctrl-v, but not pasting from the edit menu.
//| To allow pasting with ctrl-v, allow keyCodes 17 and 86.
//|
//| This function also cancels any keys pressed while the Shift key is down.
//| Without this cancelling action, the shifted versions of the numeral keys
//| (!, @, etc) would be displayed.
// ---------------------------------------------------------------------------------

    var KeysAllowed = 
       "0,8,46,48,49,50,51,52,53,54,55,56,57,96,97,98,99,100,101,102,103,104,105";

    if (EventObj.shiftKey == true) {EventObj.returnValue = false; return;}

    var keyCode = (EventObj.keyCode) ? EventObj.keyCode : EventObj.which;
    if (KeysAllowed.indexOf(keyCode.toString()) == -1) {EventObj.returnValue = false;}
  }


  function FORM_RemoveNonNumerals(Textbox) {
// ---------------------------------------------------------------------------------------
//| To be called via onBlur="FORM_RemoveNonNumerals(this);"
// ---------------------------------------------------------------------------------------
    Textbox.value = Textbox.value.replace(/[^0-9]/g,'');
  }




//#################################################
//Restrict the range of numeric values in a textbox
//#################################################
  function FORM_RestrictToRange(TheTextbox, Minval, Maxval) {
// ---------------------------------------------------------------------------------------
//| Restrict the range of numeric values in a textbox. 
//| If the value is less than Minval then assign the Minval.
//| If the value is greater than Maxval then assign the Maxval.
// ---------------------------------------------------------------------------------------
    var Val = TheTextbox.value;
    if (Val=='' || isNaN(Val) || isNaN(Minval) || isNaN(Maxval)) {
      return;
    }else{
      if (parseFloat(Val) < parseFloat(Minval)) {
        TheTextbox.value = Minval;
      }else
      if (parseFloat(Val) > parseFloat(Maxval)) {
        TheTextbox.value = Maxval;
      }
    }
  }  





//########################################
//Determine whether a string is an integer
//########################################
  function FORM_IsNumericInt(Inp) {
    if (Inp == '') return false;
  //We want something like Inp="1.2" to return false
  //Note:Inp="1,000" will also return false
    var NumeralsOnly = Inp.replace(/[^0-9]/g,'');
    if (Inp == NumeralsOnly) {
      return true;
    }else{
      return false;
    }
  }
//NOTE: To test for a generic number use if(isNaN(Inp) == true) {}




//#######################################
//Validate a minimum length for a textbox
//#######################################
  function FORM_ValidateMinLength(TheTextbox, MinLength) {
// ---------------------------------------------------------------------------------------
//| A use of this function is to help enforce a minumum lenght of a password.
// ---------------------------------------------------------------------------------------
    if (TheTextbox.value.length < MinLength) {
      alert('Field must have\nat least '+MinLength+' characters');
      TheTextbox.focus();
     }
  } 



//#######################################
//Shadow a checkbox with a hidden element
//#######################################
  function FORM_ShadowCheckbox(FieldName, BooleanFormat) {
// ---------------------------------------------------------------------------------------
//| This function is part of a workaround to the browser design deficiency wherein it does
//| not return a name=value pair to the server for a checkbox element unless the checkbox
//| is checked. Another workaround is to temporarily mark all checkboxes as checked, then
//| submit the form, then restore all checkboxes to their original states.
//|
//| Since a checkbox doesn't return a name=value pair to the server unless it's checked, a
//| hidden field is associated with each checkbox to always return a  value. The value 
//| assigned may be in any of the forms 1/0, true/false, yes/no, or on/off depending on 
//| the optional input "BooleanFormat" value, which should be a string, one of 
//| "1/0", "true/false", etc. A naming convention must be followed for the checkbox. For a 
//| hidden field named "SomeYesNoField", the checkbox must be named "frmSomeYesNoField".
//| Example call: <input type=checkbox name="frmSomeBooleanField" 
//|                onClick="ShadowCheckbox('SomeBooleanField', 'Yes/No')">
//|               <input type=hidden   name="SomeBooleanField">
//| This function is called from the onClick event of the checkbox.
// ---------------------------------------------------------------------------------------

    var BooleanVals = new Array();
    BooleanVals[0] = "true";
    BooleanVals[1] = "false";
    if (BooleanFormat != "") {
      if (BooleanFormat.search('/') != -1) BooleanVals = BooleanFormat.split('/',2);
    }

    var TheForm = document.forms[0];
    if (eval("TheForm.frm"+FieldName+".checked")) {
      eval("TheForm."+FieldName+".value = '"+BooleanVals[0]+"'");
    }else{
      eval("TheForm."+FieldName+".value = '"+BooleanVals[1]+"'");
    }
  }


//########################################################
//Assign a value to a hidden element as part of a "combox"
//########################################################
  function FORM_AssignHiddenValue(FieldName, OptionType) {
// ---------------------------------------------------------------------------------------
//| This funcion is part of a system for implementing a "combox" form element, which a 
//| combination texbox/selectionbox element, where selectionbox may be a listbox (select
//| element or an option group (radio button group).
//|
//| This function assigns the value of a hidden field based on the item selected from a 
//| list or from a set of radio buttons and the value of a textbox labeled "Other". The 
//| hidden field represents the actual field value, while the listbox/radio-buttons and 
//| "other" textbox constitute a means to select a field value from a set of options, or 
//| to specify an alternative value if the desired value is not in the set.
//|
//| A naming convention must be followed. For a hidden field named "SomeHiddenField", the 
//| list must be named "frmSomeHiddenFieldOptions", and the textbox containing the "other"
//| value must be named "frmSomeHiddenFieldOther". This function is called from the onBlur
//| events of the listbox/radio-buttons and the textbox.
// ---------------------------------------------------------------------------------------

    if (!OptionType) {OptionType='';}
    var TheForm = document.forms[0];
    var ListValue;
    if (OptionType == '') {
      ListValue = eval("TheForm.frm"+FieldName+"Options.options[TheForm.frm"+FieldName+"Options.selectedIndex].value");
    }
    else if (OptionType == 'radio') {
      ListValue = eval("TheForm.frm"+FieldName+"Options.value");
    }

    if (ListValue == "Other") {
      eval("TheForm."+FieldName+".value = TheForm.frm"+FieldName+"Other.value");
    }else{
      eval("TheForm."+FieldName+".value = ListValue");
      if (eval("TheForm.frm"+FieldName+"Other.value != ''")) {
        eval("TheForm.frm"+FieldName+"Other.value = ''");
      }
    }
  }



//######################################################################
//Mark a radio button as selected based on the value of a hidden element
//######################################################################
  function FORM_SelectRadioBtnByHiddenValue(FieldName, TheForm) {
    var HiddenFieldValue;
    eval('HiddenFieldValue = TheForm.'+FieldName+'.value');
    var TheOptionGroup;
    eval('TheOptionGroup = TheForm.frm'+FieldName);
    for (var n=1; n<=TheOptionGroup.length; n++) {
      if (TheOptionGroup[n-1].value == HiddenFieldValue) {
        TheOptionGroup.selectedIndex = n-1;
        break;
      }
    }
  }




//####################################################
//Validate the format of an email as *@*.xx or *@*.xxx
//####################################################
  function FORM_ValidateEmail(Email) {
    var checkbeg = /^[.+]/;       //Match one or more characters, at the beginning
    var checkmid = /@[\w\-]+\./;  //Match an @ sign, followed by A-Z, a-z, 0-9, _, or - repeated any number of times
    var checkend = /\..{2,3}$/;   //Match a dot followed by 2 or three characters, at the end
    if( (Email.search(checkbeg) != -1) || (Email.search(checkmid) == -1) || (Email.search(checkend) == -1) ) {
      return false;
    }else{
      return true;
    }
  }



//########################################
//Verify the format of a textbox as a date
//########################################
  function FORM_ValidateDateInTextbox(Textbox) {
    if (Textbox.value == '') return;
    if (!IsADate(Textbox.value)) {
      alert(Textbox.value+' is not a valid date');
      Textbox.focus();
    }
  }

  function FORM_IsADate(InpToTest) {
    var aDate = new Date(InpToTest);
    if (aDate.getDay()) {
      return true;
    }else{
      return false;
    }
  }




//###############
//Return the time
//###############
  function FORM_Now(timezone) {
// ---------------------------------------------------------------------------------------
//| Return the UTC time in dd mmm yyyy hh:mm:ss format.
//| The input "timezone" should be one of "UTC" or "local". If "timezone" = "UTC" the 
//| UTC time is return, otherwise the user's local time is returned.
// ---------------------------------------------------------------------------------------
    var T, N, MonthNames;
    MonthNames = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", 
                           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
    T = new Date();
    if (timezone == null) {timezone = "";}
    if (timezone.toLowerCase() == "utc") {
      N = T.getUTCDate() + " " + MonthNames[T.getUTCMonth()] + " " + T.getUTCFullYear() + " "
        + T.getUTCHours() + ":" + T.getUTCMinutes() + ":" + T.getUTCSeconds();
    }else{
      N = T.getDate() + " " + MonthNames[T.getMonth()] + " " + T.getFullYear() + " "
        + T.getHours() + ":" + T.getMinutes() + ":" + T.getSeconds();
    }
    return N;
  }



//###############
//Return the time
//###############
  function FORM_NowArray() {
// ---------------------------------------------------------------------------------------
//| Return an array (1-based) containing [T_UTC, T_OffsetFromUTC, T_Local] where
//| T_Local = T_UTC - T_OffsetFromUTC,  The times have the format dd mmm yyyy hh:mm:ss.
// ---------------------------------------------------------------------------------------
    var T, N, MonthNames;
    var NowArray = new Array();
    
    MonthNames = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", 
                           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");                           
    T = new Date();
    N = T.getUTCDate() + " " + MonthNames[T.getUTCMonth()] + " " + T.getUTCFullYear() + " "
      + T.getUTCHours() + ":" + T.getUTCMinutes() + ":" + T.getUTCSeconds();
    NowArray[1] = N;
    NowArray[2] = T.getTimezoneOffset();
    N = T.getDate() + " " + MonthNames[T.getMonth()] + " " + T.getFullYear() + " "
      + T.getHours() + ":" + T.getMinutes() + ":" + T.getSeconds();
    NowArray[3] = N;
    return NowArray;
  }


  function FORM_GetHoursFromUTC() {
    var TheDate = new Date();
    return TheDate.getTimezoneOffset()/60;
  }

  function FORM_GetMinutesFromUTC() {
    var TheDate = new Date();
    return TheDate.getTimezoneOffset();
  }



//###########################
//Convert true/false to '1/0'
//###########################
  function FORM_OneZero(IsTrue) {
   if (IsTrue) return "1";
   else return "0";
  }

//###########################
//Convert '1/0' to true/false
//###########################
  function FORM_TF(IsOne) {
   if (IsOne==1) return true;
   else return false;
  }


//#####################################################################
//Return a single value representing the selection from an option group
//#####################################################################
  function FORM_OptionGroupValue(OptionGroup) {
// ---------------------------------------------------------------------------------------
//| Option groups (radio button groups) lack a "value" property, which is logically the
//| "value" of the selected option. This function supplies the missing "value" property.
//| (Side note: The <select> element has a "selectedIndex" property which can be used
//| to get at the "value" of the <select> element, but a radio button group lacks even
//| this.)
// ---------------------------------------------------------------------------------------
    var NumItems = OptionGroup.length;
    for (var n=1; n<=NumItems; n++) {
      if (OptionGroup[n-1].checked) {
        return OptionGroup[n-1].value;
      }
    }
  }


//#######################################################
//Return the index (0-based) corresponding to the "value"
//of an item in a listbox (<select> element)
//#######################################################
  function FORM_IndexOfListValue(List, Val) {
    var NumItems = List.length;
    for (var n=1; n<=NumItems; n++) {
      if (List[n-1].value == Val) return n-1;
    }
    return -1;
  }




//###########################################################
//Automatically tab to the next textbox in a set of textboxes
//###########################################################
  function FORM_AutoTab(TheTextbox, Action) {
// ---------------------------------------------------------------------------------------
//| To be called via onFocus="FORM_AutoTab(this,'check_previous');" in each textbox but 
//| the first in a set of textboxes.
//|
//| To be called via onKeyUp="FORM_AutoTab(this,'check_current');" and 
//| onBlur="FORM_AutoTab(this,'check_current');" in each textbox but the last in a set of
//| textboxes. The onBlur call is to handle the case when the user pastes text into the
//| textbox rather than type it in.
//|
//| The textboxes must have the maxLength property set.
//| The textboxes must appear in sequence in the html code.
//| 
//| Some information datums are conventionally organized in subparts. For example
//| SSN = xxx-xx-xxxx and phone = (xxx)xxx-xxxx. One input interface for this kind of data
//| is to provide separate textboxes for each subpart. This function controls the automatic 
//| tabbing to the next textbox when the information in one textbox is completed. Consider
//| the phone number example. After the user enters the area code in the area code textbox, 
//| this function will automatically tab to the exchange textbox. Also, if the user
//| attempts to edit the exchange textbox before the area code is entered, this function 
//| will automatically tab back to the area code textbox.
//|
// ---------------------------------------------------------------------------------------

    switch (Action){

    //Verify completion of the previous textbox
      case "check_previous":
        var PreviousTextbox = TheTextbox.form[FORM_GetFormElementIndex(TheTextbox)-1];
        if (PreviousTextbox.value.length < PreviousTextbox.maxLength) {
          PreviousTextbox.focus();
        //Move the cursor to the end of the text in the previous textbox
          if (PreviousTextbox.value.length > 0) {
            if (PreviousTextbox.createTextRange()) {
              var TextRangeObj = PreviousTextbox.createTextRange();
              TextRangeObj.findText(PreviousTextbox.value);
              TextRangeObj.move("character", PreviousTextbox.value.length);
              TextRangeObj.select();
            }
          }            
          return;
        }
      break;

    //Check for completion of the current textbox
      case "check_current":
        if (TheTextbox.value.length == TheTextbox.maxLength) {
          var NextTextbox = TheTextbox.form[FORM_GetFormElementIndex(TheTextbox)+1];
          NextTextbox.focus();
          return;
        }
      break;

      default:
        var Msg = "Invalid Action argument ("+Action+") in FORM_AutoTab(TheTextbox, Action)\n"
                + "Must be one of 'check_previous' and 'check_current'";
        alert(Msg);
      break;

    }
  }



//###########################################################
//Return the index of a Form element in the form[] collection
//###########################################################
  function FORM_GetFormElementIndex(FormElement) {
    var index = -1, i = 0, found = false;
    while (i < FormElement.form.length && index == -1) {
      if (FormElement.form[i] == FormElement) {
        index = i;
      }else{
        i++;
      }
    }
    return index;
  }

