function $(s)
{
	if (document.getElementById)
		return document.getElementById(s);
	else
		return false;
}

/*
* @Date: Feb 21, 2005
* @Description: This function strips defined chars from a string
* useful in validation routines
* example: stripChars(str, "()-") returns the string with any
* brackets and dashes removed
**/
function stripChars(str, chars) {
  var i;
  var newstring = "";
  for (i = 0; i < str.length; i++) {
    mychar = str.charAt(i);
    if (chars.indexOf(mychar) == -1)
      newstring += mychar;
  }
  return newstring;
}

/**
* @Date: Feb 21, 2005
* @Description: This function extracts defined chars from a string
* useful in validation routines
* it is 'sort of' the reverse of stripChars
* example: extractChars(str, "0123456789") returns all digits from the string
**/
function extractChars(str, chars) {
  var i;
  var newstring = "";
  for (i = 0; i < str.length; i++) {
    mychar = str.charAt(i);
    if (chars.indexOf(mychar) != -1)
      newstring += mychar;
  }
  return newstring;
}

/**
* @Date: Dec 1, 2004
* @Description: This function tests a credit card using the Luhn validation
* The sum of digits must be divisible by 10
* digits in odd positions are doubled, then sum of left+right digit is taken
**/
function isValidCreditCard(sCreditCardNumber)
{
  var nTotal      = 0;
  var nPosition     = 0;
  var bValid      = true; // innocent until proven guilty
  sCreditCardNumber = extractChars(sCreditCardNumber, "0123456789");
  if (sCreditCardNumber.length < 13)
    bValid = false;
  else
  {
    for ( i = sCreditCardNumber.length; i > 0 ;  i--)
    {
      var nDigit      = 0;
      // advance
      nPosition++;
      // get digit
      nDigit= parseInt(sCreditCardNumber.charAt(i-1));
      // odd position: add to total
      if ((nPosition % 2) !== 0)
         nTotal += parseInt(nDigit);
      else
      // even position: add sum of digits to total
      {
        // calc sum of left and right digit (use parseInt to cut off fractional parts
        var nDoubled = nDigit * 2;
        var nLeftDigit  = parseInt(nDoubled / 10);
        var nRightDigit = nDoubled % 10;
        // get sum of left and right
        nTotal += nLeftDigit + nRightDigit;
      }
    }
    // if divisible by 10 it is valid
    bValid = (nTotal % 10) === 0;
  }
  return (bValid);
}

/**
* @Date: Dec 1, 2004
* @Description: check if d is a date value
* @param d					The date value, can be a string
* @param formatted 	Means it is in fact a string, formatted as mm/dd/yyyy
*/
function isDate(d, formatted)
{
  var ret = false;

  var date = new Date(d);

  // it's at least a number
  if (!isNaN(date))
  {
    if (formatted)
    {
      var day = date.getDate();
      var month = date.getMonth()+1;
      var year = date.getFullYear();
      var dateString = '' + month + '/' + day + '/' + year;
      var pattern = new RegExp('' + month + '.' + day + '.' + year);
      ret = pattern.test(dateString);
    }
    else
      ret = true;
  }
  return ret;
}

/**
* @Date: Dec 1, 2004
* @Description: generic validation routine, based on css class names
* @param frm					the form to be validated
* @param target				an element in the page where errors need to be shown
*/
function validateForm(frm, target)
{
  var i;
  var ret = true;
  var field;
  var out='';
  var errorFields = [];

  if (!target)
    target = "errors";

  if (!$(target))
  {
    if (window.console) console.log('setup element ' + target + ' to make errors visible');
    return false;
  }

  // loop through all fields
  // check if they have validation class name
  // and do appropriate validation
  // @return true, if all validation passes
  for (i=0; i<frm.elements.length; i++)
  {
    field = frm.elements[i];
    // skip disabled fields
    if (field.disabled)
      continue;
    // skip field without a name
    if (field.name==undefined)
      continue;

    // validate required fields
    filter = /validate-required/;
    if (filter.test(field.className))
    {
      if (field.type=='checkbox')
      {
				if (!field.checked)
				{
					out += 'Please check the ' + field.name + ' box<br />';
					errorFields.push(field);
					ret = false;
				}
      }
      else
        if (field.value==='')
        {
          out += 'Please enter a value for ' + field.name + '<br />';
          errorFields.push(field);
          ret = false;
        }
    }
    // validate numeric fields
    filter = /validate-number/;
    if (filter.test(field.className))
    {
      if (field.value!=='' && isNaN(field.value))
      {
        out += 'Please enter a number for ' + field.name + '<br />';
        errorFields.push(field);
        ret = false;
      }
    }
    // validate digit only fields
    filter = /validate-digits/;
    if (filter.test(field.className))
    {
      var filter  = /^[0-9]+$/;
      if (field.value!=='' && !filter.test(field.value))
      {
        out += 'Please enter a number for ' + field.name + '<br />';
        errorFields.push(field);
        ret = false;
      }
    }
    // validate date fields
    filter = /validate-date/;
    if (filter.test(field.className))
    {
      if (field.value!=='' && !isDate(field.value, true))
      {
        out += 'Please enter a date value for ' + field.name + '<br />';
        errorFields.push(field);
        ret = false;
      }
    }
    // validate this date later than other field's date
    filter = /validate-date-after/;
    if (filter.test(field.className))
    {
      var otherFieldName = field.className.replace(/.*validate-date-after-/,'').replace(/ .*/,'');
      if (field.value!=='' && $(otherFieldName))
      {
				var otherField = $(otherFieldName);
				if (isDate(field.value) && isDate(otherField.value))
				{
					var date1	= new Date(field.value);
					var date2 = new Date(otherField.value);
				}
				if (+date1 <= +date2) // + converts to number
				{
	        out += 'The value in ' + field.name + ' is not later than ' + otherField.name  + '<br />';
	        errorFields.push(field);
	        ret = false;
				}
      }
    }
    // validate email addresses
    filter = /format-email/;
    if (filter.test(field.className))
    {
      filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
      if (field.value!=='' && !filter.test(field.value))
      {
        out += 'Please enter a valid email address in ' + field.name + '<br />';
        errorFields.push(field);
        ret = false;
      }
    }
    // validate credit cards
    // this uses Luhn validation
    // which is a numeric algorithm
    filter = /format-creditcard/;
    if (filter.test(field.className))
    {
      filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
      if (field.value!=='' && !isValidCreditCard(field.value))
      {
        out += 'Please enter a valid credit card number'  + '<br />';
        errorFields.push(field);
        ret = false;
      }
    }
    // validate urls
    filter = /format-url/;
    if (filter.test(field.className))
    {
      filter  = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/i;
      if (field.value!=='' && !filter.test(field.value))
      {
        out += 'Please enter a valid url'  + '<br />';
        errorFields.push(field);
        ret = false;
      }
    }
    // validate verification fields
    filter = /validate-match/;
    if (filter.test(field.className))
    {
      var otherField = field.className.replace(/.*validate-match-/,'').replace(/ .*/,'');
      if (field.value!=='' && field.value!=$(otherField).value)
      {
        out += 'The value in ' + field.name + ' does not match ' + otherField  + '<br />';
        errorFields.push(field);
        ret = false;
      }
    }
    field.className = field.className.replace(" error","");
  }
  $(target).innerHTML = out;
	$(target).className = $(target).className.replace('hide','');
  // indicate errors
  for (i = 0; i < errorFields.length; i++)
    errorFields[i].className += " error";
  window.scroll(0,0);
  return ret;
}

