/* documented in formValidation.txt */

	var customErrorSuffix = '';				// can override in code: shown at the end of any error message
	var customErrorDiv = 'customErrMsg';	// can override in code: which DIV to pop open for errors
	
	/* support routines */
	function xGetElementById(e) {
	  if(typeof(e)!="string") return e;
	  if(document.getElementById) e=document.getElementById(e);
	  else if(document.all) e=document.all[e];
	  else if(document.layers) e=xLayer(e);
	  else e=null;
	  return e;
	}
	function xCollapse(e) {
		if(!(e=xGetElementById(e))) return;
		e.style.display = "none";
		return e;
	}
	function xExpand(e) {
		if(!(e=xGetElementById(e))) return;
		e.style.display = "block";
		return e;
	}

	// returns NULL if none are selected
	function getRadioValue(f,fldName)
	{
		var i = 0, ct = eval('f.'+fldName+'.length');
		for (i = 0; i < ct; ++i) {
			if (eval('f.'+fldName+'[i].checked'))
				return eval('f.'+fldName+'[i].value');
		}
		return null;
	}

	// set focusObj or lblObj to ZERO (0) to suppress the behavior on that element.
	//	FOCUSOBJ: gets the focus, and its class is set to "err"
	//	LBLOBJ: class is set to "lblErr"
	// also, the custom error message div is shown, and the required field div is hidden
	function showCustomError(msg,focusObj,lblObj)
	{
		// show the main error message
		var obj = xGetElementById(customErrorDiv);
		obj.innerHTML = msg + customErrorSuffix;
		if ( !obj.errorShowing) {
			xExpand(obj);
			obj.errorShowing = true;
		}
		// hilite the error field
		if ( focusObj != 0) {
			focusObj.focus();
			focusObj.className = 'err';
		}
		// and the label
		if ( lblObj) lblObj.className = 'lblErr';
	}

// at this point, the 2 pw's must not be empty. pass in
// the field names (strings). the associated labels are 
// assumed to be the same, with "_lbl" at the end
function validatePasswords(f,passField1,passField2)
{
	var p1 = eval('f.' + passField1 + '.value'),
		p2 = eval('f.' + passField2 + '.value');
	
	if ( p1 != p2 ) {
		var msg = "Your passwords don't match. Please make sure you have entered exactly the same password in both fields.";
		showCustomError(msg,eval('f.' + passField1),xGetElementById(passField1+'_lbl'));
		return false;
	}
	return true;
}

	// ensure the number doesn't have invalid chars
	function checkOnePhoneNumber(num)
	{
		var i = 0, ct = num.length, c;
		for ( ; i < ct; ++i) {
			c = num.charAt(i);
			if (!( c == '(' || c == ')' || c == ' ' || c == '-' || c == '+' || (c >= '0' && c <= '9')))
				return false;
		}
		return true;
	}
	
// pass in 2 phones, as field names (strings).
// the associated labels are assumed to be the same, with "_lbl" at the end
function validatePhones(f,phoneField,faxField)
{
	var ph = eval('f.'+phoneField+'.value'),
		fax = faxField ? eval('f.'+faxField+'.value') : 0,
		errObj = 0;
	
	if ( !checkOnePhoneNumber(ph))
		errObj = 1;
	else if ( faxField && !checkOnePhoneNumber(fax))
		errObj = 2;
	
	if ( errObj != 0)
	{
		var msg = 'Please ensure that your ' + (errObj == 1 ? 'phone' : 'fax') +' number is formatted correctly.',
			focusObj = (errObj == 1 ? eval('f.'+phoneField) : eval('f.'+faxField)),
			lblObj = xGetElementById( (errObj == 1 ? phoneField : faxField) + '_lbl');
		showCustomError(msg,focusObj,lblObj)
		return false;
	}
	return true;
}


// ensure that the field looks like a person's name (according to iSubscribe)
function validateName(f,nameField)
{
	var nm = eval('f.' + nameField + '.value'),
		re = /^[a-zA-Z ''-]+$/;		// letters, spc, apostr, hyph
	
	if ( !re.test(nm) ) {
		var msg = "Your name has unusual characters in it. Please use only letters.";
		showCustomError(msg,eval('f.' + nameField),xGetElementById(nameField+'_lbl'));
		return false;
	}
	return true;
}


// see [http://www.breakingpar.com/] in the tips/regExp section
function checkOneEmail(emailAddress)
{
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
    return re.test(emailAddress);
}

// pass in up to 2 email addresses, as field names (strings).
// the associated labels are assumed to be the same, with "_lbl" at the end
function validateEmails(f,emailField1,emailField2)
{
	var msg,errObj = 0;
	
	var e1 = eval('f.' + emailField1 + '.value'),
		e2 = emailField2 ? eval('f.' + emailField2 + '.value') : -1;
	if (e1=='') {
		msg = "Please enter your email address.";
		errObj = 1;
	}
	else if ( !checkOneEmail(e1)) {
		msg = "It looks like your email address is not formatted correctly. Please double-check it and resubmit the form.";
		errObj = 1;
	}
	else if ( e2 != -1 && e1 != e2) {
		msg = "Please make sure you have entered your email address in both fields.";
		errObj = 2;
	}
	
	if ( errObj != 0) {
		var focusObj = (errObj == 1 ? eval('f.' + emailField1) : eval('f.' + emailField2)),
			lblObj = xGetElementById( (errObj == 1 ? emailField1 : emailField2) + '_lbl');
		showCustomError(msg,focusObj,lblObj)
		return false;
	}
	return true;
}

function checkLicenseAgreement(f) {
	if ( !f.agree.checked) {
		var msg = 'Please read the terms and conditions below, and check the box to indicate that you agree to them.';
		showCustomError(msg,0,xGetElementById('agree_lbl'));
		return false;
	}
	return true;
}

	function checkVisa(ccnum) {
		var re = /^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/;
		return re.test(ccnum)
	}
	function checkMC(ccnum) {
		var re = /^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/;
		return re.test(ccnum)
	}
	function checkAMEX(ccnum) {
		var re = /^3[4,7]\d{13}$/;
		return re.test(ccnum)
	}
		
// see [http://www.breakingpar.com/] in the tips/regExp section
function checkCreditCard(type, ccnum) {
	var re = 0, checksum = 0, i;
	if (type == "visa")
		if ( !checkVisa(ccnum)) return false;
	else if (type == "mastercard")
		if ( !checkMC(ccnum)) return false;
	else if (type == "discover")
		re = /^6011-?\d{4}-?\d{4}-?\d{4}$/;
	else if (type == "amex")
		if ( !checkAMEX(ccnum)) return false;
	else if (type == "diners")
		re = /^3[0,6,8]\d{12}$/;
	else if (type == "all") {		// allows MC/Visa/Amex
		if ( !( checkVisa(ccnum) || checkMC(ccnum) || checkAMEX(ccnum) )) return false;
	}
	else
		return false;
	if (re != 0 && !re.test(ccnum)) return false;
	// Checksum ("Mod 10"): Add even digits in even length strings or odd digits in odd length strings.
	for (i=(2-(ccnum.length % 2)); i<=ccnum.length; i+=2)
		checksum += parseInt(ccnum.charAt(i-1));
	// Analyze odd digits in even length strings or even digits in odd length strings.
	for (i=(ccnum.length % 2) + 1; i<ccnum.length; i+=2) {
		var digit = parseInt(ccnum.charAt(i-1)) * 2;
		if (digit < 10) { checksum += digit; } else { checksum += (digit-9); }
	}
	return ((checksum % 10) == 0);
}

// this version takes the field name of the cc type
function validateCreditCard(f,typeField,valueField) {
	return validateCreditCard2(f,eval('f.'+typeField+'.value'),valueField);
}

// this version takes the type directly
function validateCreditCard2(f,ccType,valueField)
{
	var reNoSpaces = / /g,	// rmv spcs
		val = (eval('f.'+valueField+'.value')).replace(reNoSpaces,'');

	if ( checkCreditCard(ccType,val))
		return true;
	else {
		var msg = 'Please check your credit card number.';
		showCustomError(msg,eval('f.'+valueField),xGetElementById(valueField+'_lbl'));
		return false;
	}
}

// pass in an array of which fields are required: e.g., Array("x_name", "x_passwd")
function validateRequiredFields(f,fieldsRequired){
	var errCt = 0, fld, isErr, obj, lblObj, i, ct, j;
	
	// first stop: check required fields
	for (i = 0, ct = fieldsRequired.length; i < ct; ++i) {
		isErr = false;
		obj = f.elements[fld=fieldsRequired[i]];
		lblObj = xGetElementById(fld+'_lbl');
		
		if (obj){
			if (obj.type == null){
				var blnchecked = false;
				for (j = 0; j < obj.length; ++j){
					if (obj[j].checked)
						blnchecked = true;
				}
				if (!blnchecked) isErr = true;
				continue;
			}

			switch(obj.type){
			case "select-one":
				if (obj.selectedIndex == 0 || obj.options[obj.selectedIndex].text == "")
					isErr = true;
				break;
			case "select-multiple":
				if (obj.selectedIndex == -1)
					isErr = true;
				break;
			case "text":
			case "textarea":
			case "password":
				if (obj.value == "" || obj.value == null)
					isErr = true;
				break;
			default:
			}
		}
		
		if ( isErr) {
			obj.className = 'err';
			if ( lblObj) lblObj.className = 'lblErr';
			++errCt;
		}
		else {
			obj.className = 'noErr';
			if ( lblObj) lblObj.className = 'lbl';
		}
	}

	if ( errCt == 0)
		return true;
	else{
		var msg = 'Please fill in the highlighted fields; they are required information.';
		showCustomError(msg,0,lblObj);
		return false;
	}
}

