var form = new Array();
var errs = '';

/*** Main (Layer 1) ***/
/* bool */ function validate(/* HTMLFormElement */ target)
{
  for (i = 0; i < target.length; i++) {
    e = target.elements.item(i);
    form[e.name] = (e.type == "checkbox") ? e.checked : e.value;
  }

  ok = validateNotMissing('firstname', 'First Name')
    && validateNotMissing('lastname', 'Last Name')
    && validateNotMissing('address', 'Address')
    && validateNotMissing('city', 'City')
    && validateNotMissing('postal', 'Postal Code')
    && validateNotMissing('daytimephone', 'Daytime Phone Number')
    && validateNotMissing('eveningphone', 'Evening Phone Number')
    && validateEmail()
    && validateCC()
    && validateChecked('physical_disclaimer_accept', 'Physical Ability Disclaimer (in "your information" section)')
    && validateChecked('refund_policy_accept', 'Refund Policy Accept');

  if (!ok)
    return invalid();

  return true;
}

/* bool */ function invalid()
{
  alert('Invalid Data:' + errs);
  errs = '';

  return false;
}

/* bool */ function addError(/* String */ field, /* String */ error)
{
  errs += '\n' + field + ' ' + error;
  return false;
}

/*** Layer 2 ***/

/* bool */ function validateChecked(field, desc)
{
  if (form[field] != true)
    return addError(desc, 'is not checked');
  else
    return true;
}

/* bool */ function validateNotMissing(field,desc)
{
  if (!form[field])
    return addError(desc, 'is missing');
  else
    return true;
}

/* bool */ function validateEmail()
{
  if (!validateNotMissing('email1', "Email Address"))
    return false;
    
  if (form['email1'] != form['email2'])
    return addError('emails', 'don\'t match');

  return true;
}

/* bool */ function validateCC()
{
  if (!validateNotMissing('card_number', "Credit Card Number"))
    return false;

  if (!validateCCNum(form['card_type'], form['card_number']))
    return addError('Credit Card Number', 'is invalid');

  return true;
}

/*** Layer 3 ***/

/* bool */ function validateCCNum(/* String */ type, /* Integer */ num)
{
  if (type == 'visa')
    if ((num.length == 13 || num.length == 16) && num.charAt(0) == '4' && checksum(num))
      return true;
    else
      return false;
  else if (type == 'mastercard')
    if (num.length == 16 && num.charAt(0) == '5' && /[1-5]/.test(num.charAt(1)) && checksum(num))
      return true;
    else
      return false;
  else
    return false;
}

/* bool */ function validatePhoneNum(/* Integer */ n)
{
  return /^[1-9][0-9][0-9]{8,}/.test(n);
}

/*** Generic Functions ***/

/* Integer */ function multMod(/* Integer */ a, /* Integer */ b, /* Integer */ m)
{
  a *= b;
  if (a >= m)
    a -= (m - 1);

  return a;
}

/* bool */ function checksum(/* Integer */ n)
{
  sum = 0;

  t = 1; // double alternate digits
  for (i = n.length - 1; i >= 0; i--) {
    sum += multMod(n.charAt(i), t, 10); // sum result digits
    t = (t == 1) ? 2 : 1; // toggle t between 2 and 1
  }
  return (sum % 10) == 0;
}