// LAFcommon -- a library of miscellaneous code and objects for C++ and ASP.
// Copyright (C) 2001 lookandfeel new media, LLC
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the lookandfeel Lesser General Public License as published by
// lookandfeel new media.
//
// This program 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 lookandfeel Lesser General Public License
// for more details.
//
// You should have received a copy of the lookandfeel Lesser General Public
// License along with this program; if not, write to lookandfeel new media, LLC;
// 106 W 14th St., Ste. 1400; Kansas City, MO; 64105
//
// http://freesoftware.lookandfeel.com/
// http://www.lookandfeel.com/
// ======================================================================
// Use, modification or distribution of this file, in whole or in part, via
// any medium, is expressly prohibited without the consent of Look and Feel
// New Media.
//
// Copyright 1999, 2000 Look and Feel New Media
// ======================================================================
// 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
// form_validations_docs.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)
  {
  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);
        }
      else if (!validate_isFormat(validate_elements[element_index]))
        {
        if (noisy_flag)
          validate_elementFail(validate_elements[element_index], validate_elements[element_index].format_fail);
        }
      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);
        }
      else
        tmp_return = true;

  return(tmp_return);
  }
function validate_checkall(noisy_flag, form_object)
  {
  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);
          tmp_return = false;
          }
        else if (!validate_isFormat(validate_elements[i]))
          {
          if (noisy_flag)
            validate_elementFail(validate_elements[i], validate_elements[i].format_fail);
          tmp_return = false;
          }
        }
      else
        if (!validate_isFormat(validate_elements[i]))
          {
          if (noisy_flag)
            validate_elementFail(validate_elements[i], validate_elements[i].format_fail);
          tmp_return = false;
          }

  return(tmp_return);
  }
function validate_elementFail(validate_object, fail_text)
  {
  alert(fail_text);
  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 "mssqldate":
      case "mssqldatetime":
      case "number":
      case "phone":
      case "text":
      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 "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);
      }
  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?[1-9]|[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_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]*)|([0-9]{1,3}(\,[0-9]{3})*))\.[0-9]+([eE][-+]?(([0-9]+)|([0-9]{1,3}(\,[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]+)|([0-9]{1,3}(\,[0-9]{3})*))([eE]?(([0-9]+)|([0-9]{1,3}(\,[0-9]{3})*)))?$/, "").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;

  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 "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)
  }
