function $(s){return document.getElementById(s);}

/* generic validation routine */
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
	var filter = /validation-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 = /validation-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 = /validation-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 = /validation-date/;
	if (filter.test(field.className))
	{
	  if (field.value!=='' && !field.value.isDate(true))
	  {
		out += 'Please enter a valid date (mm/dd/yyyy) for ' + field.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!=='' && !field.value.isValidCreditCard())
	  {
		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 = /validation-match/;
	if (filter.test(field.className))
	{
	  var otherField = field.className.replace(/.*validation-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;
  // indicate errors
  for (i = 0; i < errorFields.length; i++)
	errorFields[i].className += " error";
  window.scroll(0,0);
  return ret;
}