/* base path to this app*/
var base;

  /**
   * checks if ccnum is valid, if not, provides an error next to errorDivId
   */
  function validateCC(ccnum, errorDivId) {
    var isValid = jcv_luhnCheck(ccnum);
    if (errorDivId) {
      document.getElementById(errorDivId).innerHTML = isValid ?
      "" : "That credit card is invalid";
    }
    return isValid;
  }

  /**
   * Checks whether a given credit card number has a valid Luhn checksum.
   * This allows you to spot most randomly made-up or garbled credit card
   * numbers immediately.
   * Reference: http://www.speech.cs.cmu.edu/~sburke/pub/luhn_lib.html
   */
  function jcv_luhnCheck(cardNumber) {
      if (jcv_isLuhnNum(cardNumber)) {
          var no_digit = cardNumber.length;
          var oddoeven = no_digit & 1;
          var sum = 0;
          for (var count = 0; count < no_digit; count++) {
              var digit = parseInt(cardNumber.charAt(count));
              if (!((count & 1) ^ oddoeven)) {
                  digit *= 2;
                  if (digit > 9) digit -= 9;
              };
              sum += digit;
          };
          if (sum == 0) return false;
          if (sum % 10 == 0) return true;
      };
      return false;
  }

  function jcv_isLuhnNum(argvalue) {
      argvalue = argvalue.toString();
      if (argvalue.length == 0) {
          return false;
      }
      for (var n = 0; n < argvalue.length; n++) {
          if ((argvalue.substring(n, n+1) < "0") ||
              (argvalue.substring(n,n+1) > "9")) {
              return false;
          }
      }
      return true;
  }
  /*
  Checks two password fields to make sure they match and are of the proper
  format.  Assumes that divs with ids passwd, passwd2, and pass1error exist.
  Accepts the app's "base" as a parameter or else uses ""
  */
  function checkPass() {
    var p1 = $('passwd').value;
    var p2 = $('passwd2').value
    if (p1 != p2 && p1 != '' && p2 != '') {
      $('pass1error').innerHTML =
          '<img src="' + base + '/static/img/incorrect.gif" />';
      $('pass2error').innerHTML =
          '<img src="' + base + '/static/img/incorrect.gif" />' +
          '<span>Passwords do not match</span>';
    } else if (!p1.match(/[a-z]/i) || !p1.match(/[0-9]/) || p1.length<6) {
      $('pass1error').innerHTML =
        '<img src= "' + base + '/static/img/incorrect.gif" />' +
        '<span>Must be 6 characters and contain numbers AND letters</span>';
      $('pass2error').innerHTML =
        '';
    } else {
      $('pass1error').innerHTML = '<img src="' + base + '/static/img/correct.gif" />';
      $('pass2error').innerHTML = '';
    }

  }
  /*
  Ensures that a tax id number only contains numbers (0-9). assumes that fields
  named "btin" and tinerror exist.
  */
  function checkTIN() {
    var tin = $('btin').value;
    if (isNaN(Number(tin))) {
      $('tinerror').innerHTML =
        '<img src="' + base + '/static/img/incorrect.gif" />';
    } else {
      $('tinerror').innerHTML =
        '<img src="' + base + '/static/img/correct.gif" />';
    }
  }

  /*
  validateFields(form, fields, shortCircuit);

  Performs simple field validations for a form prior to submission.

  form:   the form object being validated (not the name)
  fields: multi-dimensional associative array containing field names and
          validation rules. See below for the appropriate format.
  shortCircuit: specifies whether validation should stop with the first
      encountered error. If true, the first error is displayed to the user.
      If false, a list of all errors is built up and displayed in a single
      alert after validation completes.

  example usage:
      var fields = {
        'cc_act_type' : ['notnull',  'Please provide a Credit Card Type'],
        'cc_num'      : ['invokejs', 'That credit card number is invalid',
                         'jcv_luhnCheck(form.cc_num.value)'],
        'cc_num'      : ['creditcard',
                         'That credit card number is invalid'],
        'cc_cvv'      : ['regexp',
                         'Please provide a valid CVV',
                         "^[0-9]{3,4}$"],
        'cc_exp'      : ['regexp',
                         'Please provide a valid Expiration Date',
                         '[0-9]{2}\/[0-9]{4}'],
        'fname'       : ['notnull',
                         'Please the first name of the Credit Card holder'],
     }
     validateFields(myForm, fields, true);


  The "fields" parameter accepts an associative array of the form:

    [ formEltName : validationRules ]

  where formEltName is a string and validationRules is a list of the form:

    [validationType, errorMsg, optionalParam1, optionalParam2, ...]

  validationType is one of:
    "notnull" -- validation fails if formEltName is null.
    "invokejs" -- can be used to execute arbitrary JS code/functions,
        which are assumed to be validationTypes[2]. This code is eval()'d with
        no prior checking. If the result of this eval() is false,
        validation for this field fails.  Note that all code inside quotes
        is not evaluated until validateFields is INVOKED (not when the
        array is created. eg, if a string value provided is:
        'jcv_luhnCheck(somevalue)', the value of "somevalue" must exist in
        some scope when validateFields is called.
    "regex" -- validation succeeds if the value of the form element matches
        the regexp specified by validationTypes[2].
  */
  function validateFields(form, fields, shortCircuit) {
    var msg = '';
    var success = true;
    for (var i in fields) {
      var isValid = false;
      var eltVal = form.elements[i].value;

      if (fields[i][0] == 'notnull') {
        isValid = (null != eltVal && '' != eltVal);

      } else if (fields[i][0] == 'regexp') {
        var regex = new RegExp(fields[i][2]);
        isValid = (eltVal.match(regex) != null);

      } else if (fields[i][0] == 'creditcard') {
        isValid = jcv_luhnCheck(eltVal);

      } else if (fields[i][0] == 'invokejs') {
        isValid = eval(fields[i][2]);
      } else {
        alert('cannot validate type'  + fields[i][0]);
      }
      if (!isValid) {
        msg += fields[i][1] +  "\n";
        success = false;
        if (shortCircuit) {
          break;
        }
      }
    }
    if (!success) {
      alert(msg);
    }
    return success;
  }

  /** valExpDat:
  Validates an expiration date in any of the following formats:
    MM/YYYY, M/YYYY, MM/YY, M/YY
  Returns true if the provided value is in one of these formats, false
  otherwise
  */
  function valExpDate(val) {
    var regex = new RegExp("[0-9]{1,2}\/[0-9]{2,4}");
    var matchedString = val.match(regex);
    if (!matchedString) {
      return false;
    }
    var today=new Date();
    var monthYear = ("" + matchedString).split("/");
    if (monthYear.length != 2) {
      return false;
    }

    var month = monthYear[0];
    var expYear = monthYear[1];
    if (month.length == 1) {
      month = "0" + month;
    } else {
      if (eval(month + '> 12')) {
        return false;
      }
    }

    if (parseInt(expYear) < 100) {
      /* radix of 10 necessary because otherwise leading zeros (eg "07"
      for 2007) get parsed in octal. See spec for parseInt(). */
      expYear = 2000 + parseInt(expYear, 10);
    }

    var thisYear = today.getYear();
    /*
      IE and FF handle dates differently. IE uses 4 year date, FF uses date
      minus 1900 (eg, 2007 becomes 107).
     */
    if (thisYear < 2000) {
      thisYear += 1900;
    }

    if ( thisYear < expYear ||
         (thisYear == expYear && (today.getMonth() + 1) <= month)
         ) {
       return true;
    }
    /* date is in the past */
    return false;
  }
