//Copyright pi-squared 2008
//Date 21102008

//Declare globals
var glDivArray = new Array();
var glSubFormArray = new Array();
var myCheckArray = new Array();
var errorMessages = new Array();
var minReqArray = new Array();
var confirmArray = new Array();

//monitor for key press events
document.onkeypress = processKey;

//------------------------------------------------------------------------------
// Description	: Global enter key form submit handler
// Parameters	: e
// Returns		: nothing
//------------------------------------------------------------------------------

function processKey(e){
		var elementTrigger;
		var frmButton;
		var status;
		if (null == e){
			e = window.event ;
		}
		if (e.keyCode == 13){
			elementTrigger = getEventTrigger(e);
			if(elementTrigger.type!='textarea'){//preserve default form behaviour for textareas
				frmButton = findFormButton(elementTrigger);
				if(frmButton != 0){//only if it finds a legitimate form button	
					frmButton.click();
					return false;
				}
			}
		}
}

//------------------------------------------------------------------------------
// Description	: Event target determiner
// Parameters	: e
// Returns		: targ
//------------------------------------------------------------------------------
function getEventTrigger(e){ 
	if (e.target){ //Opera , Mozilla
		targ=e.target;
	}else{
		if (e.srcElement){ //IE
			targ=e.srcElement;
	  	}
  	}
	if (targ.nodeType == 3){ // defeat Safari bug
  		targ = targ.parentNode;
	}
	return targ;
}

//------------------------------------------------------------------------------
// Description	: Form element determiner
// Parameters	: elementTrigger
// Returns		: form frmButton or 0;
//------------------------------------------------------------------------------

function findFormButton(elementTrigger){
	var myForm = document.forms[0];
	for (var i=0; i < myForm.length; i++){
		if (myForm[i] == elementTrigger){
			eIndex = i;
			break;
		}
	}
	for (i=eIndex; i < myForm.length; i++){
		if(myForm[i].type == 'submit'){
			return myForm[i];
		}
	}
	return 0;
}

//------------------------------------------------------------------------------
// Description	: Clears the target element's values
// Parameters	: objIn
// Returns		: nothing
//------------------------------------------------------------------------------
function clrChild(objIn){
	var myType=chkType(objIn);
	switch (myType)
	{
	case 'select-one':
	case 'select-multiple':
		clrList(objIn);
		break;
	case 'radio':
	case 'checkbox':
		clrArray(objIn);
		break;
	case 'text': 
	case 'textarea': 
	case 'password': 
	case 'file': 
		clrText(objIn);
	    break;
	default:
		break;
	}
}

//------------------------------------------------------------------------------
// Description	: Checkbox and radio button array clearer
// Parameters	: parent object
// Returns		: nothing
//------------------------------------------------------------------------------
function clrArray(objIn){
	if(objIn.length>1){
	    //for an array of check boxes or radio buttons
		for(var a=0; a<objIn.length; a++){
			objIn[a].checked=false;
		}
	}
	else{
	    //for a single check box or radio button
		objIn.checked=false;
	}
}

//------------------------------------------------------------------------------
// Description	: Drop down & multiple clearer
// Parameters	: parent object
// Returns		: nothing
//------------------------------------------------------------------------------
function clrList(objIn){
	objIn.selectedIndex='';
}

//------------------------------------------------------------------------------
// Description	: Text input clearer
// Parameters	: parent object
// Returns		: nothing
//------------------------------------------------------------------------------
function clrText(objIn){
	objIn.value='';
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Description	: Reverses a String
// Parameters	: str
// Returns		: Reversed String 

//------------------------------------------------------------------------------
function revString(str) { 
   var retStr = ""; 
   for (i=str.length - 1 ; i > - 1 ; i--){ 
      retStr += str.substr(i,1); 
   } 
   return retStr; 
}
//------------------------------------------------------------------------------
// Description	: Run assignCheckArrays if myCheckArray.length>0
// 				  Create array of block elements that will contain required form elements if triggered by checkReqEvents. 
// 				  Optionally hides targeted form elements onLoad, based on form element, plus target value
// Parameters	: hide
// Returns		: nothing
//------------------------------------------------------------------------------
function frmLoad(display){
	//Search for ","
	var re=/,/gi;
	var newStr;
	for (var i=0; i<myCheckArray.length; i++){
		newStr=myCheckArray[i].split(re);
		newStr[1]+='_'+newStr[2];
		
		//only if there is a hidden div
		if (document.getElementById(newStr[1])){
			glDivArray.push(document.getElementById(newStr[1]));
			if(display=='hide'){
				glDivArray[i].style.display='none';
			}
		}
	}
	assignSubFormArrays();
	
	if(myCheckArray.length>0){
		assignCheckArrays();
	}
}

//------------------------------------------------------------------------------
// Description	: Hider/un-hider of HTML elements containing targeted form elements
// Parameters	: parentObj,show
// Returns		: nothing
//------------------------------------------------------------------------------
function OtherBox(parentObj,trigger,show){
	var myObj=getObj(parentObj);
	newStr=myObj.name+'_'+trigger;	
	if (document.getElementById(newStr)){
	    myObj=document.getElementById(newStr);
		//only if there is a hidden element
		if(show==true){
			if (myObj.nodeName=="TR"){//got to treat TR's differently
				if (navigator.appVersion.indexOf("MSIE")!=-1){//for IE..could expand to test for container element type...
					myObj.style.display='block';
				}
				else{//for other browsers, so we can show/hide TR's as a block level element normally...
					myObj.style.display='table-row';
				}
			}
			else{
				myObj.style.display='block';
			}
		}
		else{
			//don't bother if it's already done, and send back status, to prevent traversenodes from running!
			if(myObj.style.display != 'none'){
				myObj.style.display='none';
				return false;
			}
			else{
				return true;			
			}
		}
	}
	else{
		return;
	}
}

//------------------------------------------------------------------------------
// Description	: Event handler for dynamically setting form elements to required 
// status, set in onLoad event handler for body tag
// Parameters	: myCheckArray (global)
// Returns		: Nothing
//------------------------------------------------------------------------------
function assignCheckArrays()
{
	var re=/,/gi;
	var myTempArray=myCheckArray;
	var combCheckArray=new Array();
	for (var i=0; i<myTempArray.length; i++){//for multiple required assignments on different targets of same form element array
		outerTest=myTempArray[i].split(re);
		combCheckArray.push(outerTest);
		for (var j=i+1; j<myTempArray.length; j++){
			innerTest=myTempArray[j].split(re);	
						
			if (outerTest[0]==innerTest[0] && outerTest[1]==innerTest[1]){
			
				myTempArray.splice(j,1);
				j--;
				combCheckArray[i][2]+='&'+innerTest[2];
				combCheckArray[i][3]+='&'+innerTest[3];
			}
		}
	}
	for (var i=0; i<combCheckArray.length; i++){

		checkReqEvents(combCheckArray[i]);
	}
}

//------------------------------------------------------------------------------
// Description	: Event handler for dynamically setting form elements to required status
// Parameters	: uses combCheckArray 
// Returns		: Nothing
//------------------------------------------------------------------------------
function checkReqEvents(combCheckArray){
	//might need to be adapted for diff. browsers...
	frmIn=eval ('document.forms.'+combCheckArray[0]);
	objIn=eval ('frmIn.'+combCheckArray[1]);
	
	var myType=chkType(objIn);
	if((objIn.length>1 && myType=='radio')||(objIn.length>1&&myType=='checkbox')){
	    //if a form element array
		for (var y=0; y<objIn.length; y++){	
			objIn[y].onclick=function () {setChildReq(combCheckArray,myType)/*;chkElementSelected(this) <- can add additional functions after setChildReq with reference to the specific array element that was clicked*/}
		}
	}
	else	{
		if(myType=='radio' || myType=='checkbox'){
		    //for single radio or check box
			objIn.onclick=function () {setChildReq(combCheckArray,myType)/*;chkElementSelected(this) <- can add additional functions after setChildReq with reference to the specific array element that was clicked*/}
		}
		else{//all other form objects
			objIn.onchange=function () {setChildReq(combCheckArray,myType)/*;chkElementSelected(this) <- can add additional functions after setChildReq with reference to the specific array element that was clicked*/}
		}
	}
}

//------------------------------------------------------------------------------
// Description	: Sets the additional form elements to be required/un-required
// Parameters	: combCheckArray, myType
// Returns		: nothing
//------------------------------------------------------------------------------
function setChildReq(combCheckArray,myType)
{
	var re=/&/gi;
	var frmIn,objIn,trigger,toChk;	
	frmIn=eval ('document.forms.'+combCheckArray[0]);
	objIn=eval ('frmIn.'+combCheckArray[1]);
	trigger=combCheckArray[2].split(re);
	toChk=combCheckArray[3].split(re);
	var query, newstr;
	var status=false;
	var lastReqArray='';
	for (var i=0; i<trigger.length; i++){
		switch (myType){
		case 'select-one':
		case 'select-multiple':
			status=chkList(objIn,trigger[i]);
			break;
		case 'radio':
		case 'checkbox':
			status=chkArray(objIn,trigger[i]);
			break;
		case 'text': 
		case 'textarea': 
		case 'password': 
		case 'file': 
			status=checkText(objIn,trigger[i]);
			break;
		default:
			break;
		}
		classAssign(frmIn,objIn,trigger[i],toChk[i],status);
	}
}

//------------------------------------------------------------------------------
// Description	: visible style setter and 'req' class assigner/de-assigner for 
//                target form elements.
// Parameters	: parent form, target, status, lastReqArray
// Returns		: lastReqArray
//------------------------------------------------------------------------------
function classAssign(frmIn,objIn,trigger,toChk,status){
	var myStr='';
	//Search for "-".
	var re=/-/gi;
	var toChkArray=toChk.split(re);
	var alreadyDone=false;
	//compare each element in lastReqArray to toChkArray, and remove any duplicated elements
	var done=false;
	if(toChkArray[0]!='null'){
		for (var i=0; i<toChkArray.length; i++){
				var myQuery=eval('frmIn.'+ toChkArray[i]);
				myType=chkType(myQuery);
				if ((myType=='checkbox' && myQuery.length>1) || (myType=='radio' && myQuery.length>1)){
					query=myQuery[0];	
				}
				else{
					query=myQuery;
				}
				if (status==true){/*assign "req" class*/
					if(query.className.indexOf('req') == -1){//only if not already set to "req"
						myStr='req ' + query.className;
						query.className=myStr;
						OtherBox(objIn,trigger,status);
					}
				}
				else{
					alreadyDone = OtherBox(objIn,trigger,status);
					if (done==false){//hack to only do it once...
						if(alreadyDone == false){
							traverseNodes(objIn,toChkArray,trigger);
							done=true;
						}
					}
				}
			}	
		}
	else{
		alreadyDone = OtherBox(objIn,trigger,status);
		if(alreadyDone == false){
			traverseNodes(objIn,toChkArray,trigger);
		}
	}
}

//------------------------------------------------------------------------------
// Description	: function to clear contents of all form elments within parent element
//                that was made visible by a parent form element selection specified in myCheckArray, 
//                also clears "req" class assignments from myCheckArray & finds children elements
// Parameters	: objIn,frmIn,toChkArray,trigger
// Returns		: nothing
//------------------------------------------------------------------------------

function traverseNodes(objIn,toChkArray,trigger){
	//get local reference of body object
	var myBody=document.getElementsByTagName('body').item(0);
	//only one form in a .net2 page
	var frmIn=document.forms[0];
	//string variable to test for
	var re=/ /gi;
	//determine id of parent element
	objIn=getObj(objIn);
	var targetStr=objIn.name+'_'+trigger;
	//set array to contain all divs contained within parent div that will also have to be hidden
	var myChldArray=new Array();
	
	//if triggered within a hidden container then
	if(document.getElementById(targetStr)){
		
		var subFormElementArray=new Array();
		var mySubForm=document.getElementById(targetStr);
		
		//initialise form array index variables
		var index=detFormIndex(frmIn,objIn);//determines form index of parent form element
		var myObj=frmIn[index];//assumes the child form elementswill ALWAYS be declared after its parent form element in the DOM, this is an approximation
		var searchFormArea=false;
		var endOfDom=10000;
		
		//find all elements in form array within parent element
		for (var i=0; i<endOfDom; i++){
			if(myObj.parentNode==mySubForm){
				searchFormArea=true;
				subFormElementArray.push(frmIn[index]);
				index++;
				if(frmIn[index]){
					myObj=frmIn[index];
				}
				else{
					break;
				}
			}
			else{
				myObj=myObj.parentNode;
				if(myObj==myBody){
					if(searchFormArea==false){
						index++;
						if(frmIn[index]){
							myObj=frmIn[index];
						}else{
							break;	
						}
					}else{
						break;
					}
				}
			}
		}
	}
	
	//get array of which containers to be also hidden are inside parent container
	for (var i=0; i<glDivArray.length; i++){
	myObj=glDivArray[i];
		for (var j=0; j<endOfDom; j++){
			if(myObj.parentNode.id){
				if(myObj.parentNode.id==targetStr){
					myChldArray.push(glDivArray[i]);
					break;
				}
				else{
					myObj=myObj.parentNode;
					if (myObj==myBody){
						break;
					}
				}
			}else{
				myObj=myObj.parentNode;
				if (myObj==myBody){
					break;
				}
			}
		}
	}
	
	//clear all form elements' values inside parent element and unset any req class assignments
	for (var i=0; i<subFormElementArray.length; i++){
		clrChild(subFormElementArray[i]);
		myStr=subFormElementArray[i].className.split(re);
		if(myStr[0]=='req'){
			myStr.shift();
			var tmpStr='';
			for (var s=0; s<myStr.length; s++){
				tmpStr+=myStr[s]+' ';
			}
		subFormElementArray[i].className=tmpStr;
		}
	}
	
	//hides myChldArray elements
	for (var i=0; i<myChldArray.length; i++){
		myChldArray[i].style.display='none';
	}
}

//------------------------------------------------------------------------------
// Description	: Returns index in parent form array of object
// Parameters	: parent form, object
// Returns		: index
//------------------------------------------------------------------------------

function detFormIndex(frmIn,objIn){
	var index=0;
	for (var i=0; i<frmIn.length; i++){
		if(frmIn[i]==objIn){
			index=i;	
		}
	}
	return index;
}

//------------------------------------------------------------------------------
// Description	: Determines first form element in a subContaining div, and returns it for traverseNodes function, admittedly a hack...
// Parameters	: parent form, object
// Returns		: index
//------------------------------------------------------------------------------

function traverseDivForm(objIn,trigger){
	
	var myObj=getObj(objIn);
	newStr=myObj.name+'_'+trigger;	
	if (document.getElementById(newStr)){
		myDiv=document.getElementById(newStr);
	}
	//get local reference of body object
	var myBody=document.getElementsByTagName('body').item(0);
	var frmIn=document.forms[0];//only one form in any .net page, would have to pass the form through for non .net version
	var myObj=frmIn[0]; 
	
	//initialise form array index variables
	var index=0;
	var searchFormArea=false;
	var endOfDom=10000;
	
	//find all elements in form array within parent element
	for (var i=0; i<endOfDom; i++){
		if(myObj.parentNode==myDiv){
			searchFormArea=true;
			return frmIn[index];
		}
		else{
			myObj=myObj.parentNode;
			if(myObj==myBody){
				if(searchFormArea==false){
					index++;
					if(frmIn[index]){
						myObj=frmIn[index];
					}else{
						break;	
					}
				}else{
					break;
				}
			}
		}
	}
}

//------------------------------------------------------------------------------
// Description	: Creates array of sub-form containing html elements within parent form
// Parameters	: none
// Returns		: myFormAreaArray
//------------------------------------------------------------------------------

function assignSubFormArrays(){
	var myFormAreaArray=new Array();
	var myStr='frmArea';
	var i=0;
	var maxSkip=15;
	var skip=0;
	var myStop=false;
	while(myStop==false){
		toChkEl=myStr+i;
		if(document.getElementById(toChkEl)){
			myFormAreaArray.push(document.getElementById(toChkEl));
			skip=0;
		}else{
			if(skip<maxSkip){
				myFormAreaArray.push('null');
				skip++;
			}else{
				myStop=true;	
			}
		}
		i++;
	}
	if(myFormAreaArray.length>0){
		traverseSubFormArray(myFormAreaArray);
	}
}

//------------------------------------------------------------------------------
// Description	: Creates global array of subFormArrays, containing all their respective contained form elements
// Parameters	: parent form, object
// Returns		: index
//------------------------------------------------------------------------------

function traverseSubFormArray(myFormAreaArray){
	//get local reference of body object
	var myBody=document.getElementsByTagName('body').item(0);
	var frmIn=document.forms[0];//only one form in any .net page
	for(j=0; j<myFormAreaArray.length; j++){
		if (myFormAreaArray[j].id){//some might be blanks if certain form containers are removed
			var subFormElementArray=new Array();
			var myObj=frmIn[0]; 
			var mySubForm=myFormAreaArray[j];
			
			//initialise form array index variables
			var index=0;
			var searchFormArea=false;
			var endOfDom=10000;
			
			//find all elements in form array within parent element
			for (var i=0; i<endOfDom; i++){
				if(myObj.parentNode==mySubForm){
					searchFormArea=true;
					subFormElementArray.push(frmIn[index]);
					index++;
					if(frmIn[index]){
						myObj=frmIn[index];
					}
					else{
						break;
					}
				}
				else{
					myObj=myObj.parentNode;
					if(myObj==myBody){
						if(searchFormArea==false){
							index++;
							if(frmIn[index]){
								myObj=frmIn[index];
							}else{
								break;	
							}
						}else{
							break;
						}
					}
				}
			}
			glSubFormArray.push(subFormElementArray);
		}else{
			glSubFormArray.push(myFormAreaArray[j]);//fill with a blank
		}
	}
	/*for (var x=0; x<glSubFormArray.length; x++){
		alert(glSubFormArray[x][0].name);	
	}*/
}

//------------------------------------------------------------------------------
// Description	: Sub-form validator function, passes a sub-set of the form through to fnValidateForm
// Parameters	: calling object
// Returns		: nothing
//------------------------------------------------------------------------------
function fnSubValidate(frmButton){
	var integerReg=/\d{1,}$/; //looks for 1 integer number... maybe to be extended for any size inteteger
	var myIndex=frmButton.id.match(integerReg);
	completeStatus=fnValidateForm(glSubFormArray[myIndex],myIndex);
	return completeStatus;
}

//------------------------------------------------------------------------------
// Description	: Form validator function, gives the user an error list, and puts focus on 1st incorrect field
// Parameters	: parent object
// Returns		: nothing
//------------------------------------------------------------------------------
function fnValidateForm(frmIn,myIndex){
	//for if only a single form to be checked
	var myForm=document.forms[0];
	var errorStack=new Array();
	//looks for blank gap in class assignments for form elements
	var re=/ /gi;
	var check='';
	var deDupeChk = false;
	var deDupeArray = new Array;
	var test, query, myStr;
		for (var i=0; i<frmIn.length; i++){	
			//makes sure sibling radio & check box elements don't all get processed, only collection, assumes they're declared in sequence
			deDupeChk = false;
			for (var j=0; j < deDupeArray.length; j++){
				//alert('current element is ' + frmIn[i].name + ' and deDupArray is '+deDupeArray[j]);
				if(frmIn[i].name == deDupeArray[j]){
					deDupeChk = true;
				}
				
			}
			if (deDupeChk == false){
				deDupeArray.push(frmIn[i].name);
				myStr=frmIn[i].className.split(re);
				if(myStr[0]=='req'){//checks to see if a form element is required
					//ensures that array of radio or check box elements get checked, not individual element of array
					query=eval('myForm.'+frmIn[i].name);
					//checks to see whether a required form element has been selected/filled in or correctly formatted
					test=assignChk(query,myStr);
					if (test != true){
						setBorder(frmIn[i].id, false);
						errorStack.push(test);	
					}
					else{
						setBorder(frmIn[i].id, true);
					}
				}
				else{
					if (myStr[0]=='validate'){//checks to see if form element is not required, but needs format validation
						query=eval('myForm.'+frmIn[i].name);
						if (query.value!=""){//if it's not filled in, no need to validate
							test=assignFormatValidator(query,myStr);
							if (test != true){
								setBorder(frmIn[i].id, false);
								errorStack.push(test);	
							}
							else
							{
								setBorder(frmIn[i].id, true);
							}
						}
					}
				}
			}
			//check=myForm.elements[i].name;
		}
		
	errorStack=cleanErrorStack(errorStack);
	
	//check for matches
	errorStack=chkMatches(errorStack,myIndex);
	
	//check for minimum filled in
	errorStack=chkMinReq(errorStack,myIndex);

    //Search for ","
	re=/,/gi;
	//var errorMessageArray=errorMessages.split(re);
	
	var errorMessageArray=errorMessages;
	
	//Error Message Displayed on page.
	var bldErrorMessage='Please complete or attend to the following details:\n.......................................................................\n\n';
	for (var i=0; i<errorStack.length; i++){
		bldErrorMessage += prcssErrorArray(errorMessageArray,errorStack[i])+'\n\n';
	}
	if (bldErrorMessage != 'Please complete or attend to the following details:\n.......................................................................\n\n'){
		alert(bldErrorMessage);
		if(errorStack[0][0]){
			errorStack[0][0].focus();
		}else{
			errorStack[0].focus();
		}
		return false;
	}
	else{
	  return true;
	}
}

//------------------------------------------------------------------------------
// Description	: removes duplicate elements of checkbox or radio arrays
// Parameters	: str
// Returns		: str
//------------------------------------------------------------------------------

function cleanErrorStack(errorStack){
	var myTest;
	var type='';
	for (var i=0; i<errorStack.length; i++){
		type=chkType(errorStack[i]);
		if (type=='radio'|| type=='checkbox'){
			myTest=errorStack[i];
			for (var j=i+1; j<errorStack.length; j++){
				if (myTest.name==errorStack[j].name){
					errorStack.splice(j,1);
				}
			}
		}
	}
	return errorStack;
}

//------------------------------------------------------------------------------
// Description	: determines whether the form element in the error stack has a description in errorMessages
// Parameters	: errorMessageArray, element
// Returns		: element name/
//------------------------------------------------------------------------------
function prcssErrorArray(errorMessageArray,myError){
	//Search for "-".
	var re1=/,/gi;
	var re2=/-/gi;
	var re3=/\$/;
	var test=false;
	var errorMsg='';
	
	if (!myError.type){
        //if an array with a message at the end. ie. incorrectly formatted input, or non matching inputs
		for (var k=0; k<myError.length-1; k++){
			for (var x=0; x<errorMessageArray.length; x++){
				var tempArray1=errorMessageArray[x].split(re1);
				var tempArray2=tempArray1[1].split(re2);
				if (myError[k].name==tempArray2[0] && myError[k].form.name==tempArray1[0]){
					errorMsg+='\''+tempArray2[1]+'\'';
					if(k != myError.length-2){
						errorMsg+=' & ';
					}
					test=true;
					break;
				}	
			}
			if(test==false){
				errorMsg+='\''+myError[k].title+'\'';
				if(k != myError.length-2){
					errorMsg+=' & ';
				}
			}
		}
		errorMsg+=' '+myError[myError.length-1];
		return errorMsg;
	}
	else{
		 //just a normal form element in the array
		for (var x=0; x<errorMessageArray.length; x++){
			var tempArray1=errorMessageArray[x].split(re1);
			var tempArray2=tempArray1[1].split(re2);
			if (myError.name==tempArray2[0] && myError.form.name==tempArray1[0]){
				return '\''+tempArray2[1]+'\' needs to be completed.';
			}	
		}
		return '\''+myError.title+'\' needs to be completed.';
	}
}

//------------------------------------------------------------------------------
// Description	: converts a concatenated string to distinct words
// Parameters	: str
// Returns		: str
//------------------------------------------------------------------------------

function cnvrt2Words(str) {
	return str.replace(/[A-Z]/g, cnvrt);
	function cnvrt() {
		return arguments[0]=' '+arguments[0];
	}

}
//------------------------------------------------------------------------------
// Description	: determines whether the form element is a single element or array
// Parameters	: parent object
// Returns		: myType
//------------------------------------------------------------------------------

function chkType(objIn){

	if (!objIn.type){//for radio button and check box arrays 
		//make sure it's not a fieldset or legend or anything that's not important to the formvalidator
		if (objIn[0]){
			return objIn[0].type;
		}
		else{
			return 'unknown';	
		}
		
	}
	else{
		return objIn.type;
	}
}
//------------------------------------------------------------------------------
// Description	: determines whether the form element is a single element or array
// Parameters	: parent object
// Returns		: myType
//------------------------------------------------------------------------------

function getObj(objIn){
	if (!objIn.type){//for radio button and check box arrays 
		return objIn[0];
	}
	else{
		return objIn;
	}
}

//------------------------------------------------------------------------------
// Description	: Determines input type, assigns correct check function
// Parameters	: parent object, class string array
// Returns		: parent object, false
//------------------------------------------------------------------------------

function assignChk(objIn,myStr){
	var myType=chkType(objIn);
	switch (myType){
    	case 'select-one': 
		case 'select-multiple': 
			return chkList(objIn);
		case 'radio': 
		case 'checkbox': 
			return chkArray(objIn); 
		case 'text': 
		case 'textarea': 
		case 'password': 
		case 'file': 
			return checkText(objIn,myStr); 
    	default: 
			return 'unknown';
	}
}

//------------------------------------------------------------------------------
// Description	: Checkbox and radio button array checker
// Parameters	: parent object
// Returns		: parent object, checked
//------------------------------------------------------------------------------
function chkArray(objIn,target){
	var checked=false;
	var toReturn;
	if(objIn.length>1){
	    //for an array of check boxes or radio buttons
		for(var a=0; a<objIn.length; a++)		{
			if (objIn[a].checked){
				if(!target){
					if(objIn[a].value != ''){//make sure selected option has a value, ie. not 'please select'
						checked=true;
					}
				}
				else{
					if(objIn[a].value==target){//tests if radio or check button selected matches the target
						checked=true;
					}
				}
			}
		}
		toReturn=objIn[0];//id tag is set on 1st element of radio or check array

	}
	else{//for a single check box or radio button
		if (objIn.checked){
			if(!target){
				if(objIn.value != ''){//make sure selected option has a value, ie. not 'please select'
					checked=true;
				}
			}
			else{
				if(objIn.value==target){//tests if radio or check button selected matches the target
					checked=true;
				}
			}
		}
		toReturn=objIn;
	}
	if (checked==false){
		if (target){
			return checked;
		}
		else{
			return toReturn;
		}
	}
	else{
		return checked;
	}
}

//------------------------------------------------------------------------------
// Description	: Drop down & multiple select checker
// Parameters	: parent object, target
// Returns		: parent object, checked
//------------------------------------------------------------------------------

function chkList(objIn,target){
	var checked=false;
	for(var a=0; a<objIn.length; a++){
		if (objIn[a].selected){
			if(!target){//checks to see if target has beeen selected
				if (objIn[a].value != ''){//make sure selected option has a value, ie. not 'please select' or something like that...'
					checked=true;
				}
			}
			else{
				if (objIn[a].value==target){//checks to see if the target value was selected
					checked=true;
				}
			}
		}
	}
	if (checked==false){
		if (target){
			return checked;
		}
		else{
			return objIn;
		}
	}
	else{
		return checked;
	}
}

//------------------------------------------------------------------------------
// Description	: Text input checker
// Parameters	: parent object
// Returns		: parent object, false
//------------------------------------------------------------------------------

function checkText(objIn,myStr,target){
	if(!target){
		if (objIn.value==''){
			return objIn;
		}
		else{
			return assignFormatValidator(objIn,myStr);
		}
	}
	else{
		if (objIn.value != ''){
			return true;
		}
		else{
			return false;
		}
	}
}

//------------------------------------------------------------------------------
// Description	: Assigns correct text field format validator
// Parameters	: objIn
// Returns		: parent object, false
//------------------------------------------------------------------------------

function assignFormatValidator(objIn,myStr){
	switch (myStr[1]){
	    //to grow list with date, telephone etc. functions...
		case 'email': 
			return verifyEmail(objIn);
		case 'ccnumber': 
			return verifyCC(objIn);
		case 'integer': 
			return verifyInteger(objIn);
		case 'float': 
			return verifyFloat(objIn);
		case 'number': 
			return verifyNumber(objIn);
		default: 
			return true;
	}
}

//------------------------------------------------------------------------------
// Description	: Email validator
// Parameters	: FormFieldName
// Returns		: parent object, false
//------------------------------------------------------------------------------
function verifyEmail(FormFieldName)
{
    var emailReg = "^[\\w-! # $ % * / ? | ^ { } ` ~ & ' + - = _\.]*[\\w-! # $ % * / ? | ^ { } ` ~ & ' + - = _\.]\@[\\w]\.+[\\w]+[A-Za-z0-9]$"; // credit: madcow@olg.com (slightly adapted)
	var emailExp=new RegExp(emailReg);
	if (emailExp.test(FormFieldName.value)){
		return true;
	}
	else{
		return [FormFieldName,'needs to be formatted correctly.'];
	}
}

//------------------------------------------------------------------------------
// Description	: CCnumber validator
// Parameters	: FormFieldName
// Returns		: parent object, false
//------------------------------------------------------------------------------

function verifyCcNumber(FormFieldName)

{
	var ccReg=/^\d{15,}$/; //must be at least 6 numbers only
	var ccExp=new RegExp(ccReg);
	if (ccExp.test(FormFieldName.value)){
		return true;
	}
	else{
		return [FormFieldName,'needs to contain at least 15 numbers, and no spaces.'];
	}
}

//------------------------------------------------------------------------------
// Description	: CCnumber validator based on Luhn Algorithm
// Parameters	: FormFieldName
// Returns		: parent object, false
//------------------------------------------------------------------------------
function verifyCC(FormFieldName)
{

var r = revString(FormFieldName.value);

  t = "";
  for (i = 0; i < r.length; i++) {
    c = parseInt(r.charAt(i), 10);
    if (i % 2 != 0)
      c *= 2;
    t = t + c;
  }
  n = 0;
  for (i = 0; i < t.length; i++) {
    c = parseInt(t.charAt(i), 10);
    n = n + c;
  }

  if (n != 0 && n % 10 == 0)
    return true;
  else
    return [FormFieldName,'needs to conform to a valid credit card specification'];
}
//------------------------------------------------------------------------------
// Description	: integer validator
// Parameters	: FormFieldName
// Returns		: parent object, false
//------------------------------------------------------------------------------

function verifyInteger(FormFieldName)
{
	var integerReg=/^\d{1,}$/; //looks for at least 1 integer number
	var integerExp=new RegExp(integerReg);
	if (integerExp.test(FormFieldName.value)){
		return true;
	}
	else{
		return [FormFieldName,'needs to contain only whole numbers, with no spaces'];
	}
}

//------------------------------------------------------------------------------
// Description	: float validator
// Parameters	: FormFieldName
// Returns		: parent object, false
//------------------------------------------------------------------------------

function verifyFloat(FormFieldName)
{ 
	var floatReg=/^\d+\.\d+$/;
	var floatExp=new RegExp(floatReg);
	if (floatExp.test(FormFieldName.value)){
		return true;
	}
	else{
		return [FormFieldName,'needs to contain only numbers, with one \'.\' contained within the numbers'];
	}
}

//------------------------------------------------------------------------------
// Description	: number validator, either float or integer
// Parameters	: FormFieldName
// Returns		: parent object, false
//------------------------------------------------------------------------------

function verifyNumber(FormFieldName)

{ 
	var floatReg=/^\d{0,}\.?\d+$/;
	var floatExp=new RegExp(floatReg);
	if (floatExp.test(FormFieldName.value)){
		return true;
	}
	else{
		return [FormFieldName,'needs to contain only numbers, with ONE \'.\' optionally contained WITHIN the numbers'];
	}
}

//------------------------------------------------------------------------------
// Description	: determines whether elements in confirmArray are correctly matched
// Parameters	: errorStack, parent form
// Returns		: errorStack
//------------------------------------------------------------------------------
function chkMatches(errorStack,myIndex){
	var re, myStr;
	var myForm=document.forms[0];
	for (var i=0; i<confirmArray.length; i++)	{
		var mtchArray=new Array();
		re=/,/gi;
		myStr=confirmArray[i].split(re);
		var integerReg=/\d{1,}$/; //looks for 1 integer number
		var tmpStr=Number(myStr[0].match(integerReg));
		if (tmpStr==myIndex){
			re=/-/gi;
			myStr=myStr[1].split(re);
			for (var k=0; k<myStr.length; k++){
				mtchArray.push(eval('myForm.'+myStr[k]));
			}
			for (var j=0; j<myStr.length-1; j++){
				query1=mtchArray[j];
				query2=mtchArray[j+1];
				if (query1.value != query2.value){
				
					if (!(query1.className.match("outstanding")))
 				    {
		                query1.className += " outstanding";
		                //focusArray.push(query1);
		            }
		            if (!(query2.className.match("outstanding")))
 				    {
		                query2.className += " outstanding";
 		                //focusArray.push(query2);
 		            }
					
					mtchArray.push('need to match each other.');
					errorStack.push(mtchArray);
				}
			}
		}
	}
	return errorStack;
}

//------------------------------------------------------------------------------
// Description	: determines whether at least one elements in minReqArray are correctly matched
// Parameters	: errorStack, parent form
// Returns		: errorStack
//------------------------------------------------------------------------------
function chkMinReq(errorStack,myIndex){
	var re, myStr;
	var completed=false;
	var myForm=document.forms[0];
	//var currName='';
	for (var i=0; i<minReqArray.length; i++)	{
		var mtchArray=new Array();
		re=/,/gi;
		myStr=minReqArray[i].split(re);
		var integerReg=/\d{1,}$/; //looks for 1 integer number
		var tmpStr=Number(myStr[0].match(integerReg));
		if (tmpStr==myIndex){
			re=/-/gi;
			myStr=myStr[1].split(re);
			for (var k=0; k<myStr.length; k++){
				query=eval('myForm.'+myStr[k]);
				test=assignChk(query,'');
				if (test==true){
					completed=true;
					break;
				}
				myObj=getObj(eval('myForm.'+myStr[k]));
				mtchArray.push(myObj);
			}
			if(completed==false){
				mtchArray.push(': at least one of these needs to be selected or filled in.');
				errorStack.push(mtchArray);
			}
		}
	}
	return errorStack;
}

//------------------------------------------------------------------------------
// Description	: sets the class name of required elements to 'outstanding'
// Parameters	: elementID, filled
// Returns		: nothing
//------------------------------------------------------------------------------
function setBorder(elementID, filled){
var el = document.getElementById(elementID);
if (!filled){
		if (!(el.className.match("outstanding"))){
			el.className += " outstanding";
		}
	}
	else{
		el.className = el.className.replace(" outstanding","");
	}
}
