//
// Constants
//

// flags to use in validation checks.
//
// for methods that take a flags argument, simply add together the flags
// below that you want to use and pass that sum as the flags value.
//
FLAG_REQUIRED         = 1;  // field must be filled in
FLAG_STRICT           = 2;  // all characters in field must make up a number (otherwise characters up to first nonnumber character are interpreted as a number)
FLAG_IS_INT           = 4;  // number must be an integer (otherwise floating point numbers allowed)
FLAG_IS_CURRENCY      = 8;  // number is a currency figure (floating point number but no scientific notation allowed)
FLAG_IS_PHONE_NUMBER  = 16; // phone number characters (parens and dashes) are allowed

// regular expressions used in validating user input
// (requires javascript 1.2, meaning netscape 4+ and I.E. 4+)
//
var RE_NUMBER_STR =       "^\\s*([+-]?(\\d+[\\d,]*)?\\d+\\.?\\d*[eE]-?\\d+|[+-]?\\.?\\d+[eE]-?\\d+|[+-]?(\\d+[\\d,]*)?\\d+\\.?\\d*|[+-]?\\.?\\d+)";
var RE_INT_STR =          "^\\s*[+-]?[\\d,]+";
var RE_CURRENCY_STR =     "^\\s*[$€ŁĄ]([+-]?(\\d+[\\d,]*)?\\d+\\.?\\d*|[+-]?\\.?\\d+)";
var RE_PHONE_NUMBER_STR = "^\\s*\\+?\\s*\\d*\\s*(\\(\\d+\\)[\\s-]*)?(\\d+[- ]+)*\\d+";
var RE_URL_STR =          "^\\s*(ftp|http)://([\\w\\-]{2,}\\.)+[\\w\\-]{2,3}(/[\\w-+%.]*)*(\\?[\\w-+%]+=[\\w-+%]+(&[\\w-+%]+=[\\w-+%]+)*)?$";
var RE_EMAIL_STR =        "^\\s*[\\w\\-\\.]+@([\\w\\-]{2,}\\.)+[\\w\\-]{2,3}$";

//
// Constraint methods
//

// guarantees that a textfield's value is not null.
//
// Note: passing only the field is a simple way to check if a field is null
// without raising an alert.
//
function isNull (
  field,          // form field to check
  fieldName,      // the name or short description of the field in question
  flags,          // constraining flags (see flags above)
  def             // default value to set if the value fails test
) {
  var flagRequired = ((flags & FLAG_REQUIRED) > 0);

  var value = field.value;
  if (value == null || value == "") {
    if (flagRequired) {
      if (def != null && def != "") {
        field.value = def;
        return false;
      } else {
        field.focus();
        alert (fieldName + " is a required field.");
        return true;
      }
    } else {
      return true;
    }
  } else {
    return false;
  }
}

// guarantees that a textfield's value is greater than a given minimum.
//
function constraintMin (
  field,          // form field to check
  fieldName,      // field name or short description
  min,            // minimum value
  flags,          // constraining flags (see flags above)
  def             // default value to set if field value fails test
) {
  
  var flagRequired = ((flags & FLAG_REQUIRED) > 0);

  if (isNull (field, fieldName, flags))
    return (! flagRequired);

  // make sure we're really dealing with a number here.
  //
  if (! validateNumber (field, fieldName, flags, def)) return false;
    
  var value = field.value;

  if (value < min) {
    field.focus();
    alert (fieldName + " must be greater than or equal to " + min);
    if (def != null && def != "")
      field.value = def;
    return false;
  } else {
    field.value = value;
    return true;
  }
}

// guarantees that a textfield's value is less than a given maximum.
//
function constraintMax (
  field,          // form field to check
  fieldName,      // field name or short description
  max,            // maximum value
  flags,          // constraining flags (see flags above)
  def             // default value to set if field value fails test
) {
  
  var flagRequired = ((flags & FLAG_REQUIRED) > 0);

  if (isNull (field, fieldName, flags))
    return (! flagRequired);

  // make sure we're really dealing with a number here.
  //
  if (! validateNumber (field, fieldName, flags, def)) return false;
    
  var value = field.value;

  if (value > max) {
    field.focus();
    alert (fieldName + " must be less than or equal to " + max);
    if (def != null && def != "")
      field.value = def;
    return false;
  } else {
    field.value = value;
    return true;
  }
}

// this bit of code makes sure that a value entered is actually a number.
// it returns as much of the string that looks like a number as possible.
//
function validateNumber (
  field,          // form field to check
  fieldName,      // field name or short description
  flags,          // constraining flags (see flags above)
  def             // default value to set if field value fails test.
) {
  var value = field.value;
  var retVal = "";
  
  var flagRequired =      ((flags & FLAG_REQUIRED) > 0);
  var flagStrict =        ((flags & FLAG_STRICT) > 0);
  var flagIsInt =         ((flags & FLAG_IS_INT) > 0);
  var flagIsCurrency =    ((flags & FLAG_IS_CURRENCY) > 0);
  var flagIsPhoneNumber = ((flags & FLAG_IS_PHONE_NUMBER) > 0);

  var inv_char = false;
  var currency_found = false;
  var sign_found = false;
  var decimal_found = false;
  
  if (isNull (field, fieldName, flags))
    return (! flagRequired);
  
  reStr = RE_NUMBER_STR;
  reErrorStr = fieldName + " must be a number.";
  
  if (flagIsInt) {
    reStr = RE_INT_STR;
    reErrorStr = fieldName + " must be an integer.";
  }
  if (flagIsCurrency) {
    reStr = RE_CURRENCY_STR;
    reErrorStr = fieldName + " must be an number.";
  }
  if (flagIsPhoneNumber) {
    reStr = RE_PHONE_NUMBER_STR;
    reErrorStr = fieldName + " must be a phone number.";
  }
  if (flagStrict)
    reStr += "$";

  var myRE = new RegExp (reStr);
  var reArray = myRE.exec (value);
  if (! reArray) {
    field.focus();
    alert (reErrorStr);
    return false;
  }
  
  if (! flagIsPhoneNumber) {
alert ("got here");
    var convertRE = new RegExp ("[\\s+-,$€ŁĄ]+", "g");
    retVal = reArray[0].replace (convertRE, "");
    field.value = retVal;
  }
  
  return true;
}

// guarantees that a textfield's value looks like a URL (i.e. http://somedomain.com).
//
function constraintURL (
  field,
  fieldName,
  flags
) {

  var flagRequired = ((flags & FLAG_REQUIRED) > 0);

  if (isNull (field, fieldName, flags))
    return (! flagRequired);
    
  var value = field.value;

  var myRE = new RegExp (RE_URL_STR);
  var reArray = myRE.exec (value);
  if (! reArray) {
    field.focus();
    alert (fieldName + " must be a valid URL.");
    return false;
  }
  
  return true;
}

// guarantees that a textfield's value looks like an email address (i.e. user@somedomain.com).
//
function constraintEmail (
  field,
  fieldName,
  flags
) {

  var flagRequired = ((flags & FLAG_REQUIRED) > 0);

  if (isNull (field, fieldName, flags))
    return (! flagRequired);
    
  var value = field.value;

  var myRE = new RegExp (RE_EMAIL_STR);
  var reArray = myRE.exec (value);
  if (! reArray) {
    field.focus();
    alert (fieldName + " must be a valid EMail address.");
    return false;
  }
  
  return true;
}

// returns the index of the radio button checked (-1 if no radio checked)
//
function radioChecked (
  field,
  fieldName,
  flags
) {
  var checkedIndex = -1;

  var flagRequired = ((flags & FLAG_REQUIRED) > 0);
  
  for (var i = 0; i < field.length; i++) {
    if (field[i].checked)
      checkedIndex = i;
  }
  
  if (flagRequired && checkedIndex == -1) {
    field[0].focus();
    alert (fieldName + " must be selected.");
  }
  
  return checkedIndex;
}

//
// Utility methods
//

// the javascript escape() function converts spaces to '+'s for some reason.
// this can be a pain because the unescape() function does not convert '+'s
// back to spaces. this function is used to convert '+'s to '%20's (the
// REAL code for an escaped space character.)
//
function unplus (str) {
  var newstr = '';

  for (var l = 0; l < str.length; l++) {
    var c = str.charAt (l);
    if (c == '+') {
      newstr += '%20';
    } else {
      newstr += c;
    }
  }
  return newstr;
}

// Decodes form data (typically used on document.location.search)
//
// Returns an associative array containing form key/value pairs.
//
function formDecode (str) {
  if (str.charAt (0) == '?')
    str = str.substr (1);
  var a = str.split ('&');
  var myform = new Object();
  for (var l = 0; l < a.length; l++) {
    var apos = a[l].indexOf ('=');
    var n = unescape (unplus (a[l].substring (0,apos)));
    var v = unescape (unplus (a[l].substring (apos + 1)));
    myform[n] = v;
  }
  return myform;
}

