//this is the default only define it if we didn't already define this.


	function getParentLabelDefaut(ele){					
		if(ele.parentNode.parentNode.childNodes[0].nodeType==3){
			return ele.parentNode.parentNode.childNodes[1].childNodes[0].nodeValue;
		}
		return ele.parentNode.parentNode.childNodes[0].childNodes[0].nodeValue;
	}
if(typeof(getParentLabel)!="function"){	
	getParentLabel=getParentLabelDefaut;
}

function selectAll(frm){
   	for(var x=0;x<frm.elements.length;x++){
		var t=frm.elements[x];
		if(frm.elements[x].tagName=="SELECT" && frm.elements[x].multiple){  
  			for(var y=0;y<frm.elements[x].options.length;y++){
				frm.elements[x].options[y].selected=true;
  			}
		}
   	}
}

function isnull(ele){   
   value=getValue(ele);
   if(value===false){ return false;}
   if(value=="" || value==null){
		return true;
   }
   return false; 
}

function getValue(ele){	
	
	if(typeof(ele)=="string") return ele;
	
   	switch(ele.type){
		case "hidden":
		case "text":
		case "password":
   			return ele.value;
		case "radio":
  			return ele.checked;
		case "checkbox":
  			return ele.checked;
		case "select-one":
  			return ele.options[ele.options.selectedIndex].value;

		default:
  			return false; 
   	}
}

function checkPercision(ele,per){
	
   var val = getValue(ele);  
   var param=per.split(','); 	
   if(isNaN(val)){ return false;}
   var p=val.indexOf(".");   
   var inc=0;
   //remove decimal place from str length
   if(p!=-1){
   	inc=1;
   }

   if(val.length-inc>param[0]){
   		alert(getParentLabel(ele)+" exceed max number of digits ["+param[0]+"].");
   	 	return false;   
   }
   
   if(p==-1){ return true;}
   
   if((val.length-p-1) >param[1]){
   		alert(getParentLabel(ele)+" exceed max number of decimal places ["+param[1]+"]");
   	 	return false;
   }
   return true;
}

function correctValueForType(ele,p){
	var days=[0,30,28,31,30,31,30,31,31,30,31,30,31];
	var regex;
  	val=getValue(ele);
  	if(val=="" || val==null){ return true;}
  	var yrcheck=false;
  	var m=null,d=null;
  	switch(p){
   		case "integer":
   		    var nVal=Number(val);
   		    if(nVal!=val){return false;}
			if (isNaN(val)){return false;}
			if(val.indexOf(".")!=-1){ return false;}
			return true;
   		case "number":
			if (isNaN(val)){ return false;}
		break;
   		case "date":
			regex=new RegExp("(d{4})-(\d{2})-(\d{2})");
			
			var match=regex.exc(val);
			if(match==null){
    			return false;
			}else{
    			if(match.length!=3){ return false;}
    			m=parseInt(match[1],10);
    			if( m<1 || m>12){ return false;}
    			d=match[2];
    			if(d>31){ return false;}
    			if(m==2){   
  					if(d>29){
    					return false;
  					}else if(d==29){
						if(match[0]%4==0){
   							if(match[0]%400==0){ }//aight it a leap year
   							else if(match[0]%100==0){ return false;}//it's not a leap year
 						}else{
   							return false;
 						}
  					}
    			}
			}
		break;
   		case "timestamp": //only dates after 1970
    		  yrcheck=true;    		
   		case "timestamp2"://any date
  			regex=new RegExp("(d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})");  			
  			match=regex.exc(cal);
  			if(match==null){
				return false;
  			}else{
				if(match.length!=5){ return false;}
				if(yrcheck && match[0]<1970){return false;}
				m=parseInt(match[1],10);
				if( m<1 || m>12){ return false;}
				d=match[2];
				if(d>31){ return false;}
				if(m==2){   
   					if(d>29){
						return false;
   					}else if(d==29){
  						if(match[0]%4==0){
    						if(match[0]%400==0){}//aight it a leap year
    						else if(match[0]%100==0){ return false;}//it's not a leap year
  						}else{
    						return false;
  						}
   					}
				}
				if(parseInt(match[3],10)>=24){ return false;}
				if(parseInt(match[4],10)>=60){ return false;}
  			}   
		break;
  	}
  return true;
}



function validateRange(ele,range){
	var val=Number(getValue(ele));
	var start=range.charAt(0);
	if(start!='[' && start!='('){
		alert("Invalid range check for "+getParentLabel(ele));
		return false;
	}
	
	var end=range.charAt(range.length-1);
	if(end!=']' && end!=')'){
		alert("Invalid range check for "+getParentLabel(ele));
		return false;
	}


	var str=range.substring(1,range.length-1);
	var r=str.split(',');
		
	if(isNaN(r[0]) && r[0]!="-inifinity"){
		alert("Invalid range check for "+getParentLabel(ele));
		return false;
	}
	if(isNaN(r[1]) && r[1]!="inifinity"){
		alert("Invalid range check for "+getParentLabel(ele));
		return false;
	}
    
	switch(start){
		case '[': 
			if(!isNaN(r[1])){
				if(val < Number(r[0])){
					return false;
				}
			}
			break;
		case '(': 
			if(!isNaN(r[1])){
				if(val <= Number(r[0])){
					return false;
				}
			}		
			break;
	}
	
	switch(end){
		case ']': 
			if(!isNaN(r[1])){
				if(val > Number(r[1])){
					return false;
				}
			}
			break;
		case ')': 
			if(!isNaN(r[1])){
				if(val >= Number(r[1])){
					return false;
				}
			}		
			break;
	}
    	
	return true;
}


function validateYearRange(ele,range){
	var val=getValue(ele);
	if(isNaN(val) || parseInt(val)!=val){
		return false;
	}
	var start=range.charAt(0);
	if(start!='[' && start!='('){
		alert("Invalid range check for "+getParentLabel(ele));
		return false;
	}
	
	var end=range.charAt(range.length-1);
	if(end!=']' && end!=')'){
		alert("Invalid range check for "+getParentLabel(ele));
		return false;
	}


	var str=range.substring(1,range.length-1);
	var r=str.split(',');

	for(var x=0;x<r.length;x++){
		if(r[x]=="current"){
			var d = new Date();			
			r[x]=d.getYear();
		}
	
		if(isNaN(r[x]) && (r[x].charAt(0)=="+" || r[x].charAt(0)=="-")){				
			var intVal=parseInt(r[x].substring(1),10);			
			var idx=(x==1)?0:1;			
			if(r[x].charAt(0)=="+")
				r[x]=r[idx]+intVal;
			else
				r[x]=r[idx]-intVal;				
		}
	}
	
    
	switch(start){
		case '[': 
			if(!isNaN(r[1])){
				if(val < r[0]){
					return false;
				}
			}
			break;
		case '(': 
			if(!isNaN(r[0])){
				if(val <= r[0]){
					return false;
				}
			}		
			break;
	}
	
	switch(end){
		case '[': 
			if(!isNaN(r[1])){
				if(val > r[1]){
					return false;
				}
			}
			break;
		case '(': 
			if(!isNaN(r[1])){
				if(val >= r[1]){
					return false;
				}
			}		
			break;
	}
    	
	return true;
}


function validateEmail(ele){
	var val=getValue(ele);	
	var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(2([0-4]\d|5[0-5])|1?\d{1,2})(\.(2([0-4]\d|5[0-5])|1?\d{1,2})){3} \])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;	
    return re.test(val);
}

function validatePhone(ele){
	var val=getValue(ele);
	var re = /^(\+\d)*\s*(\(\d{3}\)\s*)*\d{3}(-{0,1}|\s{0,1})\d{2}(-{0,1}|\s{0,1})\d{2}$/; 
	return re.test(val);
}

function validateZipcode(ele){
	var val=getValue(ele);
	//validates US or canadian zipcodes	
    var re = /(^\d{5}(-\d{4})?$)|(^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$)/;    
    return re.test(val);
}


function validateCCInfo(str,card,cvn,month,year){
	var d = new Date();			
	var cyear=d.getYear();
	
	if(cyear>year){
 		 alert("The credit card has expired.");
		 return false;
	}else if(cyear==year){
		month=parseInt(month,10);
		cmonth=parseInt(d.getMonth());
		if(month<cmonth){
 		 	alert("The credit card has expired.");
		 	return false;			
		}
	}

	var cmonth=d.getMonth()+1;
	
	var result = false;
    var validNums;
    
    var cardLen = str.length;
    var firstdig = str.charAt(0);
    var seconddig = str.charAt(1);    
   
    card=card.toUpperCase();    
    switch (card){
    	case "VISA"://visa    	
    		result = (firstdig=="4") && ((cardLen == 16) || (cardLen == 13));    
    		if(!result) alert("Invalid Card Number for Visa.");		
    		if(!/^\d{3}$/.test(cvn)){ 
    			result=false;
    			alert("Invalid Card Verification Number for Visa.");		
    		}
    	break;
    	
    	case "AMEX":    	
    	case "AMERICAN EXPRESS":    	    	
   			validNums = "47";
   			result = (firstdig=="3") && (cardLen == 15) && (validNums.indexOf(seconddig)>=0);
   			if(!result) alert("Invalid Card Number for American Express.");		
			if(!/^\d{4}$/.test(cvn)){ 
    			result=false;
    			alert("Invalid Card Verification Number for American Express.");		
    		}
    	break;
    	
    	case "DINERS":    	
    	case "DINERS CLUB":    	
    	case "DINERS CLUB INT":    	
    	case "DINERS CLUB INTERNATIONAL":    	    		
    		validNums = "068";
    		result =  (firstdig=="3") && (cardLen == 14) && (validNums.indexOf(seconddig)>=0);
    		if(!result) alert("Invalid Card Number for Diners Club.");		
    		if(!/^\d{3}$/.test(cvn)){ 
    			result=false;
    			alert("Invalid Card Verification Number for Diners Club.");		
    		}
    	break;
    	
    	case "MASTERCARD"://masterCard
    		validNums = "12345";
    		result = (firstdig=="5") && (cardLen == 16) && (validNums.indexOf(seconddig)>=0);
    		if(!result) alert("Invalid Card Number for MasterCard.");		
    		if(!/^\d{3}$/.test(cvn)){ 
    			result=false;
    			alert("Invalid Card Verification Number for MasterCard.");		
    		}
    	break;
    
    	case "DISCOVER"://Discover
    		result = (cardLen == 16) && (str.substring(0,4) == "6011");
    		if(!result) alert("Invalid Card Number for Discover.");		
    		if(!/^\d{3}$/.test(cvn)){ 
    			result=false;
    			alert("Invalid Card Verification Number for Discover.");		
    		}
    	break;
    }
    if(result) return validateLUN(str);
    return false;
}

function validateLUN(str){
    var result = true;
   
    var sum = 0;
    var mul = 1;
    var strLen = str.length;
   
    for (i = 0; i < strLen; i++){
    	var digit = str.substring(strLen-i-1,strLen-i);
    	var tproduct = parseInt(digit ,10)*mul;
    	if (tproduct >= 10){sum += (tproduct % 10) + 1;}
    	else{sum += tproduct;}
    	if (mul == 1){mul++;}
    	else{mul--;}
    }
    if ((sum % 10) != 0){result = false;}   
    return result;
}
      
function validate(frm, selectAllMulti){	
   	var ele=frm.elements;
   	process_next_form_field:
   	for(var x=0;x<ele.length;x++){   
		var validateArg=ele[x].getAttribute("validate");
		if(validateArg){
    		var c=validateArg.split(" ");
    		for(var z=0;z<c.length;z++){
 				var y=c[z].split("=");     				
 				if(y[0]=="") continue;
 				switch(y[0]){
 					case "cc_check":
 						otherEle=y[1].split(","); 				
  					   //call to validateCCInfo(str,card,cvn,month,year)
 					   //let's remove extranious white space and dashes from curent element (card num) and cvn
 					    var myRegExp = new RegExp("[^0-9]","g"); 
 					    ele[x].value=ele[x].value.replace(myRegExp,"");
 					    frm[otherEle[1]].value=frm[otherEle[1]].value.replace(myRegExp,"");
						if(!validateCCInfo(getValue(ele[x]),getValue(frm[otherEle[0]]),getValue(frm[otherEle[1]]),getValue(frm[otherEle[2]]),getValue(frm[otherEle[3]]))){							
							return false;
						}
 					break;
 					
					case "match": //are null values allowed
						var matchEle=frm.elements[y[1]];						
						matchEleV=getValue(matchEle);
						eleV=getValue(ele[x]);
						if(matchEleV!=eleV){
							alert(getParentLabel(ele[x])+" and "+getParentLabel(matchEle)+" must have the same values."); 
							return false;
						}
					break;
					
   					case "nullable": //are null values allowed same as required=false
   					   var nullVal=isnull(ele[x]);
						if (y[1]==1 || y[1]=="true"){ //
							if(nullVal) continue process_next_form_field;
						}
						else if(y[1]==0 || y[1]=="false"){ //
							if(nullVal){
    							alert(getParentLabel(ele[x])+" can not be empty."); 
    							return false;
							}
						}else{
							alert("Invalid value for nullbale check");
							return false;
						}
   					break;
   					case "password":
						if(isnull(ele[x])){
    						alert(getParentLabel(ele[x])+" can not be empty."); 
    						return false;
						}						
						if(ele[x].value.length<parseInt(y[1])){
							alert(getParentLabel(ele[x])+" must be at least "+y[1]+" characters long"); 
							return false;
						}	
						break;	
   					case "precision":
						if(y[1]==-1){ continue;}
						if(isNaN(getValue(ele[x]))){
							 alert(getParentLabel(ele[x])+" must be a number.");
							 return false;
						}
						if(!checkPercision(ele[x],y[1])){
    						return false;
						}
					break;
					case "required": //are null values dissallowed					
					    nullVal=isnull(ele[x]);					    
					    if(ele[x].type=="checkbox"){
					    	nullVal=(ele[x].checked==true)?false:true;
					    }
						if (y[1]==1 || y[1]=="true"){							
							if(nullVal){//dis allowed
    							alert(getParentLabel(ele[x])+" is a required field and  can not be empty."); 
    							return false;
							}
						}else if (y[1]==0 || y[1]=="false"){//allowed
							if(nullVal) continue process_next_form_field;//have a null skip testing
						}else{
							alert("Invalid value for required check.");
							return false;
						}						
   					break;

					case "range":
						if(!validateRange(ele[x],y[1])){
							alert("Value for "+getParentLabel(ele[x])+" is not in the range "+y[1]);
							return false;
						}
					break;
					case "regex":						
						var myregexp = new RegExp(y[1], "gims");
						var value=getValue(ele[x]);
						if(!value.match(myregexp)){
							alert(getParentLabel(ele[x])+" did not match regular expression "+y[1]);
							return false;
						}						
					break;
					case "pattern":					
						var v=false;
						switch(y[1]){
							case "email": v=validateEmail(ele[x]); break;
							case "zipcode": v=validateZipcode(ele[x]); break;
							case "phone": v=validatePhone(ele[x]); break;
						}
						if(!v){							
							alert(getParentLabel(ele[x])+" is  not a valid "+y[1]);
							return false;
						}
					break;
   				case "type":
					if(!correctValueForType(ele[x],y[1])){
    					alert(getParentLabel(ele[x])+" must be of type "+y[1]);
    					return false;
					}
					break;
				case "year_range":
						if(!validateYearRange(ele[x],y[1])){
							alert("Value for "+getParentLabel(ele[x])+" is not in the range "+y[1]);
							return false;
						}
					break;	
 				case "enum":		
 						eleV=getValue(ele[x]);			
						var v=false;
						var en=y[1].split("|");
						for(var z=0;z<en.length;z++){
							if(en[z]==eleV) continue process_next_form_field;//we matched so we are good
						}												
						alert(getParentLabel(ele[x])+" is  not a valid "+y[1]);
						return false;
						
					break;				
					
				default: alert("Unknown validation "+y[0]+ " for "+getParentLabel(ele[x])); break;
 				} 
    		}
    		
		}
   }      
   return true;
}