// LAFcommon -- a library of miscellaneous code and objects for C++ and ASP.
// Copyright (C) 2001 lookandfeel new media, LLC
//
// This library is free software; you can redistribute it and/or 
// modify it under the terms of the GNU Lesser General Public 
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// http://freesoftware.lookandfeel.com/
// http://www.lookandfeel.com/
// ======================================================================
// DDDDD   OOOOO      NNN  NN  OOOOO  TTTTTTTT
// DD  DD OO   OO     NNNN NN OO   OO    TT
// DD  DD OO   OO     NN NNNN OO   OO    TT
// DD  DD OO   OO     NN  NNN OO   OO    TT    .. .. ..
// DDDDD   OOOOO      NN   NN  OOOOO     TT    .. .. ..
//
// ...copy this file into your project!  It MUST be accessed as:
//     /LAFcommon/form_validations.js
// If that URL does not work, tell the sysadmin to setup the LAFcommon
// virtual directory.  Any person(s) found in violation of this edict shall
// immediately forfeit all their accumulated Slack and shall be found by
// the Stark Fist Of Removal.  This is not a test.  You have been warned.
// ======================================================================
//
// Looking for documentation on how to use this file?  It's been moved to
// doc_form_validations.txt because its size was becoming significant (9K).
//
// ======================================================================

var validate_elements = new Array();

function validate_element(form_element, element_type, format_fail, required_flag, required_fail)
  {
  this.form_element = form_element;
  this.element_type = element_type;
  this.format_fail = format_fail;
  this.required_flag = required_flag;
  this.required_fail = required_fail;

  return(true);
  }

function validate_addelement(form_element, element_type, format_fail, required_flag, required_fail)
  {
  if (form_element)
    {
    var new_element = new validate_element(form_element, element_type, format_fail, required_flag, required_fail);

    validate_elements[validate_elements.length] = new_element;
    }

  return(true);
  }
function validate_updateelement(form_element, element_type, format_fail, required_flag, required_fail)
  {
  var i;

  for (i = 0; i < validate_elements.length; i++)
    if (validate_elements[i].form_element == form_element)
      {
      validate_elements[i].element_type = element_type;
      validate_elements[i].format_fail = format_fail;
      validate_elements[i].required_flag = required_flag;
      validate_elements[i].required_fail = required_fail;
      break;
      }

  return(true);
  }
function validate_checkone(form_element, noisy_flag, no_select_flag)
  {
  var i;
  var element_index = -1;
  var tmp_return = false;

  for (i = 0; i < validate_elements.length; i++)
    if (validate_elements[i].form_element == form_element)
      {
      element_index = i;
      break;
      }

  if (element_index != -1)
    if (validate_elements[element_index].required_flag)
      if (!validate_containsData(validate_elements[element_index]))
        {
        if (noisy_flag)
          validate_elementFail(validate_elements[element_index], validate_elements[element_index].required_fail, no_select_flag);
        }
      else if (!validate_isFormat(validate_elements[element_index]))
        {
        if (noisy_flag)
          validate_elementFail(validate_elements[element_index], validate_elements[element_index].format_fail, no_select_flag);
        }
      else
        tmp_return = true;
    else
      if (!validate_isFormat(validate_elements[element_index]))
        {
        if (noisy_flag)
          validate_elementFail(validate_elements[element_index], validate_elements[element_index].format_fail, no_select_flag);
        }
      else
        tmp_return = true;

  return(tmp_return);
  }
function validate_checkall(noisy_flag, form_object, no_select_flag)
  {
  var i;
  var tmp_return = true;

  for (i = 0; (i < validate_elements.length) && tmp_return; i++)
    if (!form_object ||
        validate_elements[i].form_element.form == form_object)
      if (validate_elements[i].required_flag)
        {
        if (!validate_containsData(validate_elements[i]))
          {
          if (noisy_flag)
            validate_elementFail(validate_elements[i], validate_elements[i].required_fail, no_select_flag);
          tmp_return = false;
          }
        else if (!validate_isFormat(validate_elements[i]))
          {
          if (noisy_flag)
            validate_elementFail(validate_elements[i], validate_elements[i].format_fail, no_select_flag);
          tmp_return = false;
          }
        }
      else
        if (!validate_isFormat(validate_elements[i]))
          {
          if (noisy_flag)
            validate_elementFail(validate_elements[i], validate_elements[i].format_fail, no_select_flag);
          tmp_return = false;
          }

  return(tmp_return);
  }
function validate_elementFail(validate_object, fail_text, no_select_flag)
  {
  alert(fail_text);
  if (!no_select_flag)
    validate_doSelect(validate_object);

  return(true);
  }

// ========================================
// containsData validation functions
// ========================================
function validate_containsData(validate_object)
  {
  var tmp_return = false;

  if (validate_object.form_element)
    switch (validate_object.element_type)
      {
      case "americanexpress":
      case "canadianzip":
      case "cdate":
      case "cdatetime":
      case "creditcard":
      case "date":
      case "datetime":
      case "dinersclub":
      case "discover":
      case "email":
      case "float":
      case "integer":
      case "jcb":
      case "mastercard":
      case "money":
      case "mssqldate":
      case "mssqldatetime":
      case "number":
      case "phone":
      case "text":
      case "time":
      case "hhmm":
      case "uszip":
      case "visa":
      case "zip":
        tmp_return = validate_textContainsData(validate_object);
        break;
      case "radio":
        tmp_return = validate_radioContainsData(validate_object);
        break;
      case "select":
        tmp_return = validate_selectContainsData(validate_object);
        break;
      case "checkbox":
        tmp_return = true;
      }
  else
    tmp_return = true;

  return(tmp_return);
  }
function validate_textContainsData(validate_object)
  {
  var tmp_return = (validate_object.form_element.value.length > 0) ? true : false;

  return(tmp_return);
  }
function validate_radioContainsData(validate_object)
  {
  var i;
  var tmp_return = false;

  for (i = 0; (i < validate_object.form_element.length) && !tmp_return; i++)
    tmp_return = validate_object.form_element[i].checked;

  return(tmp_return);
  }
function validate_selectContainsData(validate_object)
  {
  return(((validate_object.form_element.selectedIndex >= 0) && (validate_object.form_element.options[validate_object.form_element.selectedIndex].value.length > 0)) ? true : false);
  }

// ========================================
// Format validation functions
// ========================================
function validate_isFormat(validate_object)
  {
  var tmp_return;

  if (validate_object.form_element)
    switch (validate_object.element_type)
      {
      case "phone":
        tmp_return = validate_isPhone(validate_object);
        break;
      case "email":
        tmp_return = validate_isEmail(validate_object);
        break;
      case "number":
        tmp_return = validate_isNumber(validate_object);
        break;
      case "float":
        tmp_return = validate_isFloat(validate_object);
        break;
      case "integer":
        tmp_return = validate_isInteger(validate_object);
        break;
      case "datetime":
        tmp_return = validate_isDatetime(validate_object);
        break;
      case "date":
        tmp_return = validate_isDate(validate_object);
        break;
      case "money":
        tmp_return = validate_isMoney(validate_object);
        break;
      case "mssqldate":
        tmp_return = validate_isMssqldate(validate_object);
        break;
      case "mssqldatetime":
        tmp_return = validate_isMssqldatetime(validate_object);
        break;
      case "text":
      case "select":
      case "radio":
      case "checkbox":
        tmp_return = true;
        break;
      case "creditcard":
        tmp_return = validate_isCreditCard(validate_object);
        break;
      case "visa":
        tmp_return = validate_isVisa(validate_object);
        break;
      case "mastercard":
        tmp_return = validate_isMasterCard(validate_object);
        break;
      case "americanexpress":
        tmp_return = validate_isAmericanExpress(validate_object);
        break;
      case "dinersclub":
        tmp_return = validate_isDinersClub(validate_object);
        break;
      case "discover":
        tmp_return = validate_isDiscover(validate_object);
        break;
      case "jcb":
        tmp_return = validate_isJCB(validate_object);
        break;
      case "zip":
        tmp_return = validate_isUSZIP(validate_object) || validate_isCanadianZIP(validate_object);
        break;
      case "uszip":
        tmp_return = validate_isUSZIP(validate_object);
        break;
      case "canadianzip":
        tmp_return = validate_isCanadianZIP(validate_object);
        break;
      case "cdate":
        tmp_return = validate_isCDate(validate_object);
        break;
      case "cdatetime":
        tmp_return = validate_isCDateTime(validate_object);
        break;
      case "time":
        tmp_return = validate_isTime(validate_object);
        break;
      case "hhmm":
        tmp_return = validate_isHHMM(validate_object);
        break;
      }
  else
    tmp_return = true;

  return(tmp_return);
  }
function validate_isDate(validate_object)
  {
  var tmp_return = true;

  if (validate_object.form_element.value.replace(/^((0?[1-9])|(1[0-2]))[-\/]((0?[1-9])|([1-2][0-9])|(3[0-1]))[-\/](([1-9][0-9]{3})|(0[1-9][0-9]{2})|(00[1-9][0-9])|(000[1-9]))$/, "").length > 0)
    tmp_return = false;
  else
    validate_object.form_element.value = validate_object.form_element.value.replace(/-/g, "\/");

  return(tmp_return);
  }
function validate_isDatetime(validate_object)
  {
  var tmp_return = true;

  if (validate_object.form_element.value.replace(/^((0?[1-9])|(1[0-2]))[-\/]((0?[1-9])|([1-2][0-9])|(3[0-1]))[-\/](([1-9][0-9]{3})|(0[1-9][0-9]{2})|(00[1-9][0-9])|(000[1-9]))( ((0?[1-9])|(1[0-2])):[0-5][0-9] [aApP][mM])?$/, "").length > 0)
    tmp_return = false;
  else
    validate_object.form_element.value = validate_object.form_element.value.replace(/-/g, "\/");

  return(tmp_return);
  }
function validate_isTime(validate_object)
  {
  var tmp_return = true;

  if (validate_object.form_element.value.replace(/^((0?[1-9])|(1[0-2])):[0-5][0-9] [aApP][mM]$/, "").length > 0)
    tmp_return = false;
  else
    validate_object.form_element.value = validate_object.form_element.value.replace(/-/g, "\/");

  return(tmp_return);
  }
function validate_isHHMM(validate_object)
  {
  var tmp_return = true;

  if (validate_object.form_element.value.replace(/^[0-9]*:[0-5][0-9]$/, "").length > 0)
    tmp_return = false;
  else
    validate_object.form_element.value = validate_object.form_element.value.replace(/-/g, "\/");

  return(tmp_return);
  }
function validate_isMssqldate(validate_object)
  {
  var tmp_return = validate_isDate(validate_object);
  var tmp_date;

  if (tmp_return == true)
    {
    tmp_date = new Date(validate_object.form_element.value);
    if (tmp_date.getFullYear() < 1753)
      tmp_return = false;
    }

  return(tmp_return);
  }
function validate_isMssqldatetime(validate_object)
  {
  var tmp_return = validate_isDatetime(validate_object);
  var tmp_date;

  if (tmp_return == true)
    {
    tmp_date = new Date(validate_object.form_element.value);
    if (tmp_date.getFullYear() < 1753)
      tmp_return = false;
    }

  return(tmp_return);
  }
function validate_isCDate(validate_object)
  {
  var tmp_return = validate_isDate(validate_object);
  var tmp_date;

  if (tmp_return == true)
    {
    tmp_date = new Date(validate_object.form_element.value);
    if ((tmp_date < new Date("1/1/1970")) ||
        (tmp_date > new Date("1/18/2038")))
      tmp_return = false;
    }

  return(tmp_return);
  }
function validate_isCDateTime(validate_object)
  {
  var tmp_return = validate_isDatetime(validate_object);
  var tmp_date;

  if (tmp_return == true)
    {
    tmp_date = new Date(validate_object.form_element.value);
    if ((tmp_date < new Date("1/1/1970 00:00:00")) ||
        (tmp_date > new Date("1/18/2038 21:14:07")))
      tmp_return = false;
    }

  return(tmp_return);
  }
function validate_isFloat(validate_object)
  {
  var tmp_return = true;

  if (validate_object.form_element.value.replace(/^[-+]?([0-9]{1,3}([0-9]+|(\,[0-9]{3})*))?(\.[0-9]+)?([eE][-+]?[0-9]{1,3}([0-9]+|(\,[0-9]{3})*)(\.[0-9]+)?)?$/, "").length > 0)
    tmp_return = false;

  return(tmp_return);
  }
function validate_isInteger(validate_object)
  {
  var tmp_return = true;

  if (validate_object.form_element.value.replace(/^[-+]?[0-9]{1,3}([0-9]+|(\,[0-9]{3})*)([eE]?[0-9]{1,3}([0-9]+|(\,[0-9]{3})*))?$/, "").length > 0)
    tmp_return = false;

  return(tmp_return);
  }
function validate_isMoney(validate_object)
  {
  var tmp_return = true;

  if (validate_object.form_element.value.replace(/^([-+]?\$?[0-9]{1,3}([0-9]+|(\,[0-9]{3})*)(\.[0-9]{2})?)|(\(\$?[0-9]{1,3}([0-9]+|(\,[0-9]{3})*)(\.[0-9]{2})?\))$/, "").length > 0)
    tmp_return = false;

  return(tmp_return);
  }
function validate_isNumber(validate_object)
  {
  var tmp_return = validate_isFloat(validate_object) || validate_isInteger(validate_object);

  return(tmp_return);
  }
function validate_isEmail(validate_object)
  {
  var tmp_return = true;

  // NOTE: According to RFC 822, dots ('.') are NOT valid in email addresses.
  // Unfortunately, so many ISPs allow them that they must pass this filter.
  if (validate_object.form_element.value.replace(/^(([^\)\(\>\<\@\,\;\:\\\"\]\[]+\@)|(\"[^\"]+\"\@))([^\@\.]+\.)+[^\@\.]+$/, "").length > 0)
    tmp_return = false;

  return(tmp_return);
  }
function validate_isPhone(validate_object)
  {
  var tmp_return = true;

  if (validate_object.form_element.value.replace(/^(((\([0-9]{3}\))|([0-9]{3})) *(-|,|\.)? *)?[0-9]{3} *(-|,|\.)? *[0-9]{4} *(([xX-]|,|\.|([eE][xX][tT]\.?))? *[0-9]{1,6})?$/, "").length > 0)
    tmp_return = false;

  return(tmp_return);
  }
function validate_isCreditCard(validate_object, card_type)
  {
  var tmp_return;

  switch (card_type)
    {
    case "visa":
      tmp_return = validate_isVisa(validate_object);
      break;
    case "mastercard":
      tmp_return = validate_isMasterCard(validate_object);
      break;
    case "americanexpress":
      tmp_return = validate_isAmericanExpress(validate_object);
      break;
    case "dinersclub":
      tmp_return = validate_isDinersClub(validate_object);
      break;
    case "discover":
      tmp_return = validate_isDiscover(validate_object);
      break;
    case "jcb":
      tmp_return = validate_isJCB(validate_object);
      break;
    default:
      tmp_return = validate_isVisa(validate_object) ||
                   validate_isMasterCard(validate_object) ||
                   validate_isAmericanExpress(validate_object) ||
                   validate_isDinersClub(validate_object) ||
                   validate_isDiscover(validate_object) ||
                   validate_isJCB(validate_object);
    }

  return(tmp_return);
  }
// ===============================================================================
// The values for these credit card validation functions came from the NOVA EDC
// Technical Specifications Version 3.20a, part of the NOVA Script Server
// documentation.
// ===============================================================================
function validate_isVisa(validate_object)
  {
  var tmp_return = false;

  if (((validate_object.form_element.value.length == 13) ||
       (validate_object.form_element.value.length == 16)) &&
      (Number(validate_object.form_element.value.charAt(0)) == 4) &&
      validate_calculate_mod10(validate_object.form_element.value))
    tmp_return = true;

  return(tmp_return);
  }
function validate_isMasterCard(validate_object)
  {
  var tmp_return = false;

  if ((validate_object.form_element.value.length == 16) &&
      (Number(validate_object.form_element.value.substring(0, 2)) >= 50) &&
      (Number(validate_object.form_element.value.substring(0, 2)) <= 55) &&
      validate_calculate_mod10(validate_object.form_element.value))
    tmp_return = true;

  return(tmp_return);
  }
function validate_isAmericanExpress(validate_object)
  {
  var tmp_return = false;

  if ((validate_object.form_element.value.length == 15) &&
      ((Number(validate_object.form_element.value.substring(0, 2)) == 34) ||
       (Number(validate_object.form_element.value.substring(0, 2)) == 37)) &&
      validate_calculate_mod10(validate_object.form_element.value))
    tmp_return = true;

  return(tmp_return);
  }
function validate_isDinersClub(validate_object)
  {
  var tmp_return = false;

  if ((validate_object.form_element.value.length == 14) &&
      (((Number(validate_object.form_element.value.substring(0, 3)) >= 300) &&
        (Number(validate_object.form_element.value.substring(0, 3)) <= 305)) ||
       (Number(validate_object.form_element.value.substring(0, 2)) == 36)) &&
      validate_calculate_mod10(validate_object.form_element.value))
    tmp_return = true;

  return(tmp_return);
  }
function validate_isDiscover(validate_object)
  {
  var tmp_return = false;

  if ((validate_object.form_element.value.length == 16) &&
      (Number(validate_object.form_element.value.substring(0, 4)) == 6011) &&
      validate_calculate_mod10(validate_object.form_element.value))
    tmp_return = true;

  return(tmp_return);
  }
function validate_isJCB(validate_object)
  {
  var tmp_return = false;

  if ((validate_object.form_element.value.length == 16) &&
      ((Number(validate_object.form_element.value.substring(0, 4)) >= 3528) ||
       (Number(validate_object.form_element.value.substring(0, 3)) <= 358)) &&
      validate_calculate_mod10(validate_object.form_element.value))
    tmp_return = true;

  return(tmp_return);
  }
function validate_isUSZIP(validate_object)
  {
  var tmp_return = false;

  if (validate_object.form_element.value.replace(/^[0-9]{5}(-[0-9]{4})?$/, "").length == 0)
    tmp_return = true;

  return(tmp_return);
  }
function validate_isCanadianZIP(validate_object)
  {
  var tmp_return = false;

  if (validate_object.form_element.value.replace(/^[0-9a-zA-Z]{3} [0-9a-zA-Z]{3}$/, "").length == 0)
    tmp_return = true;

  return(tmp_return);
  }

// ========================================
// doSelect functions
// ========================================
function validate_doSelect(validate_object)
  {
  var tmp_return = true;
  
  switch (validate_object.element_type)
    {
    case "creditcard":
    case "visa":
    case "mastercard":
    case "americanexpress":
    case "cdate":
    case "cdatetime":
    case "dinersclub":
    case "discover":
    case "jcb":
    case "phone":
    case "email":
    case "number":
    case "float":
    case "money":
    case "integer":
    case "datetime":
    case "mssqldate":
    case "mssqldatetime":
    case "date":
    case "zip":
    case "uszip":
    case "canadianzip":
    case "text":
      validate_textSelect(validate_object);
      break;
    case "select":
    case "checkbox":
      validate_selectSelect(validate_object);
      break;
    case "radio":
      validate_radioSelect(validate_object);
    }

  return(tmp_return);
  }
function validate_textSelect(validate_object)
  {
  var tmp_return = true;

  validate_object.form_element.focus();
  validate_object.form_element.select();

  return(tmp_return);
  }
function validate_selectSelect(validate_object)
  {
  var tmp_return = true;

  validate_object.form_element.focus();

  return(tmp_return);
  }
function validate_radioSelect(validate_object)
  {
  var tmp_return = true;

  validate_object.form_element[0].focus();

  return(tmp_return);
  }

// ========================================
// Other functions
// ===============================================================================
// validate_calculate_mod10 implements the LUHN formula for verifying credit card
// numbers.  The algorithm works like this: Moving from right to left, every other
// digit in the Primary Account Number (PAN) is doubled, starting with the second-
// from-the-right digit (the rightmost digit is _not_ doubled).  If the result of
// the doubling is greater than 10, the two digits of the result are added
// together.  In other words, 6 doubled is 3:
//   6 x 2 = 12   and   1 + 2 = 3
// The sum of the doubled digits is added to the sum of the undoubled digits.  If
// the total is evenly divisible by 10, the PAN is valid.
// ===============================================================================
function validate_calculate_mod10(PAN_string)
  {
  var i;
  var double_values = new Array(0, 2, 4, 6, 8, 1, 3, 5, 7, 9);
  var double_next = false;
  var total = 0;
  
  for (i = PAN_string.length - 1; i >= 0; i--)
    {
    total += double_next ? double_values[Number(PAN_string.charAt(i))] : Number(PAN_string.charAt(i));
    double_next = !double_next;
    }

  return(((total % 10) == 0) ? true : false)
  }
function validate_convert_hhmm_to_float_hours(input_hhmm)
  {
  var tmp_return = validate_convert_hhmm_to_float_minutes(input_hhmm);

  if (tmp_return != Number.NaN)
    tmp_return /= 60;

  return(tmp_return);
  }
function validate_convert_hhmm_to_float_minutes(input_hhmm)
  {
  var tmp_time = input_hhmm.split(":");
  var hours;
  var minutes;
  var total_minutes = Number.NaN;

  if (tmp_time.length == 2)
    {
    hours = new Number(tmp_time[0]);
    minutes = new Number(tmp_time[1]);
    if ((hours != Number.NaN) &&
        (minutes != Number.NaN))
      total_minutes = (hours * 60) + minutes;
    }

  return(total_minutes);
  }
function validate_convert_float_hours_to_hhmm(input_hours)
  {
  return(validate_convert_float_minutes_to_hhmm(input_hours * 60));
  }
function validate_convert_float_minutes_to_hhmm(input_minutes)
  {
  var hours = Math.floor(Math.floor(input_minutes + 0.5) / 60);
  var minutes = Math.floor(Math.floor(input_minutes + 0.5) % 60);

  return(hours + ":" + ((minutes < 10) ? ("0" + minutes) : minutes));
  }
