/* from static file */
function validate(theform,aParams) {

	// variables
	var oRegExp, i=0, j=0, j=0, aInputs, errCount=0, customErrMsg='';
	var errMsg = ' detected.\r\nPlease correct the areas highlighted in RED.';
	var matchType='';
	var pass=true;
	var thisElementErr=0;
	var sTmp='';
	var sMonthField,sDayField,sYearField; // Used in date validation
	var dtDate=''; // Used in date validation
	var sExpression;

	// load form elements into aInputs
	aFormElements = theform.elements;

	// loop through each form element & clear error classname
	// by setting its class to its type, this allows styling to be placed one each element based on its type
	for (j=0;j<=aFormElements.length-1;j++) aFormElements[j].className=aFormElements[j].type; 

	// loop through each form element and test
	for (j=0;j<=aFormElements.length-1;j++){

		// in the case of radio or checkboxes, only parse them if they are checked -- we'll catch overall blank ones outside of this for loop
		if((aFormElements[j].type=='checkbox'||aFormElements[j].type=='radio') && aFormElements[j].checked==false) {
			// skip
		} else {
			// loop through sets of aParam and see if any match with this element
			for (i=0;i<aParams.length;i=i+3) {
				// if the fieldname matches, run a test
				if (aParams[i]==aFormElements[j].name) {
					// fieldname matches this formelement

					// determine matchtype to perform
					if (aParams[i+1].indexOf(':')>0) { // contains a colon to separate
						matchType=aParams[i+1].substring(0,aParams[i+1].indexOf(':'));
					} else { // no expression data, just the match type (no colon)
						matchType=aParams[i+1];
					}
					// extract the expression (if there is one)
					if (aParams[i+1].indexOf(':')>0) {
						sExpression = aParams[i+1].substring(aParams[i+1].indexOf(':')+1);
					} else {
						sExpression = '';
					}
	
					// prepare regexp object if necessary
					if(matchType=='regexp') { oRegExp = new RegExp(sExpression, 'i'); }
	
					// perform match pass/fail test
					switch(matchType) {
					case 'regexp':
						pass = oRegExp.test(aFormElements[j].value);		
						//if(!pass) { alert('failed regexp test:'+sExpression+' on:\r\n'+aFormElements[j].value); }
						break;
					case 'require':
						pass = (aFormElements[sExpression].value != '' || aFormElements[j].value=='');
						// flag input error on require element as well
						if(!pass) {aFormElements[sExpression].className+=' inputError';}
						break;
					case 'match':
						pass = (aFormElements[aParams[i]].value==aFormElements[sExpression].value);
						// flag input error on match element as well
						if(!pass) {aFormElements[sExpression].className+=' inputError';}
						break;
					case 'different':	
						pass = (aFormElements[aParams[i]].value!=aFormElements[sExpression].value);
						// flag input error on different element as well
						if(!pass) {aFormElements[sExpression].className+=' inputError';}
						break;
					case 'date':
						sMonthField = aParams[i] + '_month'; sDayField   = aParams[i] + '_day';	sYearField  = aParams[i] + '_year';
						pass = isDate(aFormElements[sMonthField].value+'/'+aFormElements[sDayField].value+'/'+aFormElements[sYearField].value);
						// flag input error on all three date fields
						if(!pass) {
							aFormElements[sMonthField].className += ' inputError';
							aFormElements[sDayField].className   += ' inputError';
							aFormElements[sYearField].className  += ' inputError';
							//alert('error:'+aFormElements[sMonthField].value+'/'+aFormElements[sDayField].value+'/'+aFormElements[sYearField].value);
						}
						break;
					case 'datemin':
						sMonthField = aParams[i] + '_month'; sDayField   = aParams[i] + '_day';	sYearField  = aParams[i] + '_year';
						dtDate      = new Date(aFormElements[sYearField].value,aFormElements[sMonthField].value,aFormElements[sDayField].value);
						dtMin       = new Date(sExpression.split('/')[2],sExpression.split('/')[0],sExpression.split('/')[1]);
						// make sure it is a valid date
						if (isDate(aFormElements[sMonthField].value+'/'+aFormElements[sDayField].value+'/'+aFormElements[sYearField].value)) {
							// test to see if the date minimum is met
							pass = (dtDate>=dtMin);
						} else {
							// both must be dates in order to pass :)
							pass = false;
						}
						if(!pass) {
							alert(aFormElements[sMonthField].className);
							aFormElements[sMonthField].className += ' inputError';
							aFormElements[sDayField].className   += ' inputError';
							aFormElements[sYearField].className  += ' inputError';
						}
						break;
					case 'datemax':
						sMonthField = aParams[i] + '_month'; sDayField   = aParams[i] + '_day';	sYearField  = aParams[i] + '_year';
						dtDate      = new Date(aFormElements[sYearField].value,aFormElements[sMonthField].value,aFormElements[sDayField].value);
						dtMax       = new Date(sExpression.split('/')[2],sExpression.split('/')[0],sExpression.split('/')[1]);
						// make sure it is a valid date
						if (isDate(aFormElements[sMonthField].value+'/'+aFormElements[sDayField].value+'/'+aFormElements[sYearField].value)) {
							// test to see if the date minimum is met
							pass = (dtDate<=dtMin);
						} else {
							// both must be dates in order to pass :)
							pass = false;
						}
						if(!pass) {
							aFormElements[sMonthField].className += ' inputError';
							aFormElements[sDayField].className   += ' inputError';
							aFormElements[sYearField].className  += ' inputError';
						}
						break;
					}
					if(!pass) {
						thisElementErr++;
						aFormElements[j].className += ' inputError';
						if(aParams[i+2]!='') {customErrMsg+=aParams[i+2]+'\r\n';}
						errCount++;
					}
				}
				pass=true;
				if(thisElementErr>0) {
					// We only want to show/count one error per element.
					// Once a single error has occurred on this element,
					// break out of the aParam for loop to skip to the next
					// element.
					thisElementErr=0;			
					break;
				}
			}
		// end "skip unchecked checkboxes and radio buttons"
		}
	}

	// --------------------------------------------------------------------------------------
	// FINAL LOOP TO CATCH MISSING ITEMS (ON CLIENT SIDE, THIS COVERS CHECKBOXES & RADIO BOXES WHERE NO ITEMS WERE SELECTED, BUT THEY
	// ARE REQUIRED TO NOT BE BLANK (they would have been skipped in the above "for" loop)
	// --------------------------------------------------------------------------------------
	var bFoundBlankErrMsg=false, n;
	for(j=0;j<aParams.length-1;j+=3) {
		if(!existsInFormElements(aParams[j],aFormElements)) {
			// TRY to give the "cannot be blank" error message, if available
			bFoundBlankErrMsg=false;
			// loop through the Paramters again and try to find the NotBlank regexp for this field
			for(m=0;m<aParams.length-1;m+=3) {
				if(aParams[m]==aParams[j] && aParams[m+1]=='regexp:^.+$') {
					bFoundBlankErrMsg=true;
					customErrMsg += aParams[m+2] + '\r\n';
				}
			}
			if(bFoundBlankErrMsg=false) {
				// couldn't find a 'notblank' message in aParams, default to a 'field wasn't present but should be' error message
				customErrMsg += 'Field "' + aParams[j] + '" was not present to be tested, but is listed as a restricted field.\r\n';
			}
			// Make the missing one red, if available (this applies to checkboxes and radio boxes)
			for(n=0;n<aFormElements.length-1;n++) {
				if(aFormElements[n].name==aParams[j]) aFormElements[n].className += ' inputError';
			}
			errCount++;
		}
	}

	// DONE!  Give user error message if any occurred, and return to the form
	if(errCount>0 && customErrMsg) { alert(customErrMsg); }
	return (errCount==0);
}


/**********************************************************************/ 
/* Test to see if an element exists in the form element collection    */
/**********************************************************************/ 
function existsInFormElements(sElementName,oElementList) {
	var k;
	for(k=0;k<oElementList.length-1;k++) {
		if (oElementList[k].name==sElementName) {
			switch(oElementList[k].type) {
			case 'checkbox':
				if(oElementList[k].checked) return true;
				break;
			case 'radio':
				if(oElementList[k].checked) return true;
				break;
			default:
				return true;
				break;
			}
		}
	}
	return false; // not found, or (checkbox/radiobox) no checked items found
}


/**********************************************************************/ 
/*Function name :isDate(s,f) */ 
/*Usage of this function :To check s is a valid format */ 
/*Input parameter required:s=input string */ 
/* f=input string format */ 
/* =1,in mm/dd/yyyy format */ 
/* else in dd/mm/yyyy */ 
/*Return value :if is a valid date return 1 */ 
/* else return 0 */ 
/*Function required :isPositiveInteger() */ 
/**********************************************************************/ 
function isDate(s) 
{var a1=s.split("/"); 
var a2=s.split("-"); 
var e=true; 
if ((a1.length!=3) && (a2.length!=3)) 
{ 
e=false; 
} 
else 
{if (a1.length==3) 
var na=a1; 
if (a2.length==3)
var na=a2; 
if (isPositiveInteger(na[0]) && isPositiveInteger(na[1]) && isPositiveInteger(na[2])) 
{ 
var d=na[1],m=na[0];
var y=na[2]; 
if (((e) && (y<1000)||y.length>4)) 
e=false 
if (e) 
{ 
v=new Date(m+"/"+d+"/"+y); 
if (v.getMonth()!=m-1) 
e=false; 
} 
} 
else 
{ 
e=false; 
} 
} 
return e 
} 

/*************************************************************************/ 
/*Function name :isPositiveInteger(theString) */ 
/*Usage of this function :test for an +ve integer */ 
/*Input parameter required:thedata=string for test whether is +ve integer*/ 
/*Return value :if is +ve integer,return true */ 
/* else return false */ 
/*function require :isDigit */ 
/*************************************************************************/ 
function isPositiveInteger(theString) 
{ 
var theData = new String(theString) 
if (!isDigit(theData.charAt(0))) 
if (!(theData.charAt(0)== '+')) 
return false 
for (var i = 1; i < theData.length; i++) 
if (!isDigit(theData.charAt(i))) 
return false 
return true 
} 

/**********************************************************************/ 
/*Function name :isDigit(theDigit) */ 
/*Usage of this function :test for an digit */ 
/*Input parameter required:thedata=string for test whether is digit */ 
/*Return value :if is digit,return true */ 
/* else return false */ 
/**********************************************************************/ 
function isDigit(theDigit) 
{ 
	var digitArray = new Array('0','1','2','3','4','5','6','7','8','9'), j; 
	for (j=0; j<digitArray.length; j++) {
		if (theDigit == digitArray[j]) { return true; }
	}
	return false;
} 
