/*
	Form Validation
	
	Method

   		// objForm - reference to form object
   		// 'formResultDiv' - div id to present the error mesages
   		// show_alert - shows error mesages in alert message instead of div mode
   		validateFormTemplate( objForm, divErrorId, show_alert )

	
	Attribute Description:

	validate =  "not_empty" 	- field cannot be empty. stips spaces before validation 
				"integer"   	- integer allowed
				"number" 		- decimal allowed
				"email"     	- validates email syntax
				"phone" 		- includes international phone numbers
				"positive" 		- positive integer ou decimal value
				"username"		- username with 4 to 20 chars a-z A-Z and 0-9 or _ -
				"password"		- password with 4 to 20 chars A-Z a-z 0-9 and !@#$%^&*()_
				"name"			- string with 3 or more letters
				"name_surname"	- at least two names with 3 or more letters each 
				"phone_PT" 		- positive integer with 9 digits starting with 2, 91, 93, 92, 96
				"mobile_PT" 	- positive integer with 9 digits starting with 91, 93, 92, 96
				"phone_ES" 		- positive integer with 9 digits
				"nif" 			- nif PT
				"cc_visa"		- validate visa credit card 
				"cc_mastercard"	- validate mastercard credit card 
				"cc_amex"		- validate amex credit card 
				"cc_discover"	- validate discover credit card 
				"cc_dinersclub"	- validate dinersclub credit card
				"zip_PT"		- validate portuguese zip code with format xxxx-xxx
				"zip4_PT"		- validate portuguese zip code first 4 digits xxxx
				"date_PT"		- validate dates with portuguese format dd-mm-yyyy or dd/mm/yyyy
				"date_EN"		- validate dates with international format yyyy-mm-dd or yyyy-mm-dd
				"carPlate_PT"	- validate car plate for portugal with format XX-00-00 or 00-XX-00
				"url"  			- validate url address 
				
	multiple attributs validation 
		validate="integer|positive"
		title="error message to show"
	
	
	return listener
		you can define a function with name formValidation_listener that is called on validation success
		
	
	Examples:
	
		<form onsubmit="return validateFormTemplate( this, 'formResultDiv', false );" method="post">
		
			Field with username validation:
			<input type="Text" id="username" name="username" validate="username" title="Please insert a valid username" />
		
			Field with multiple validation (not_empty and integer):
			<input type="Text" id="age" name="age" validate="not_empty|integer|positive" title="Age is mandatory and as to be a valid integer" />
			
		</form>

*/


	function validateFormTemplate( objForm, divErrorId, show_alert ) {
		
		for( var i=0; i< objForm.elements.length; ++i ){
			
			var elem = objForm.elements[i];
			
			if( !elem.id || elem.length == 0 || !elem.getAttribute("validate") || elem.getAttribute("validate").length == 0 ) continue;
			
			var elemType			= elem.type;
			var elemValue 			= formValidation_getFieldValue( objForm, elem, elemType );
			var validationType 		= elem.getAttribute("validate");
			var errorMessage 		= elem.getAttribute("title");
			var arrValidationTypes 	= validationType.split("|");
			
			for (var j=0; j < arrValidationTypes.length; j++) {
				
				var blnValid = true;

				switch( arrValidationTypes[j] ){
				
					case "not_empty":
						if( elemType == "select-one" && elemValue == 0 ) blnValid = false;
						else{
							if( elemType == "checkbox" && !elem.checked ) blnValid = false;
							else{
								if( elemType != "select-one" && formValidation_allTrim(elemValue) == "" ) blnValid = false;
							}
						}
					break;

					case "integer":
						if( elemValue != "" ){
							var filter = /^-?\d+$/;						
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;

					case "number":
						if( elemValue != "" ){
							var filter = /^[-+]?\d+(\.\d+)?$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "positive":
						if( elemValue != "" ){
							var filter = /^\d+$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;

					case "email":
						if( elemValue != "" ){
							var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "phone":
						if( elemValue != "" ){
							var filter = /^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "phone_PT":
					
						if( elemValue != "" ){
							var filter = /^[0-9]{9}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
							if( blnValid ){
								if( elemValue.charAt(0) != 2 && elemValue.charAt(0) != 9 ) blnValid = false;
								if( elemValue.charAt(1) != 6 && elemValue.charAt(1) != 1 && elemValue.charAt(1) != 3 && elemValue.charAt(1) != 2 ) blnValid = false;
								if( blnValid ){
									if( formValidation_isInvalidPhoneNumbers( elemValue ) ) blnValid = false;
								}
							}
						}
					break;
					
					case "mobile_PT":
						if( elemValue != "" ){
							var filter = /^[0-9]{9}$/;
							if( ! filter.test( elemValue ) )  blnValid = false;
							
							if( blnValid ){
								if( elemValue.charAt(0) != 9 ) blnValid = false;
								if( elemValue.charAt(1) != 6 && elemValue.charAt(1) != 1 && elemValue.charAt(1) != 3 && elemValue.charAt(1) != 2 ) blnValid = false;
								if( blnValid ){
									if( formValidation_isInvalidPhoneNumbers( elemValue ) ) blnValid = false;
								}
							}
						}
					break;
					
					case "phone_ES":
						if( elemValue != "" ){
							var filter = /^[0-9]{9}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
							if( blnValid ){
								if( elemValue.charAt(0) != 6 && elemValue.charAt(0) != 9 ) blnValid = false;
								if( formValidation_isInvalidPhoneNumbers( elemValue ) ) blnValid = false;
							}
						}
					break;
					
					case "username":
						if( elemValue != "" ){
							var filter = /^[A-Za-z0-9_-]{4,20}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "password":
						if( elemValue != "" ){
							var filter = /^[A-Za-z0-9!@#$%^&*()_]{4,20}$/
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "name":
						
						if( elemValue != "" ){
							var filter = /^[A-Za-z áéíóúàèìòùÁÉÍÓÚÀÈÌÒÙÇçüöäÃÕÑãõñ]{3,120}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "name_surname":
						if( elemValue != "" ){
							var names = elemValue.split(' ');
							if( names.length <= 1 ) blnValid = false;
							else{
								for( var k=0; k< names.length; ++k ){
									var filter = /^[A-Za-z áéíóúàèìòùÁÉÍÓÚÀÈÌÒÙÇçüöäÃÕÑãõñ]{3,200}$/;
									if( ! filter.test( names[k] ) ){ 
										blnValid = false;
										break;
									}
								}
							}
						}
					break;
					
					
					case "nif":
						if( elemValue != "" ){
							if( !formValidation_isValidNIF( elemValue ) || elemValue == "123456789"  ) blnValid = false;
						}
					break;
					
					case "cc_visa":
						if( elemValue != "" ){
							var filter = /^4(?:[0-9]{12}|[0-9]{15})$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "cc_mastercard":
						if( elemValue != "" ){
							var filter = /^5[1-5]{1}[0-9]{14}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "cc_amex":
						if( elemValue != "" ){
							var filter = /^3(4|7){1}[0-9]{13}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "cc_discover":
						if( elemValue != "" ){
							var filter = /^6011[0-9]{12}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "cc_dinersclub":
						if( elemValue != "" ){
							var filter = /^3(?:(0[0-5]{1}[0-9]{11})|(6[0-9]{12})|(8[0-9]{12}))$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
						}
					break;
					
					case "zip_PT":
						if( elemValue != "" ){
							var filter = /^[0-9]{4}[-]{1}[0-9]{3}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
							if( blnValid ) blnValid = formValidation_validateZip_PT( elemValue );
						}
					break;
					
					case "zip4_PT":
						if( elemValue != "" ){
							var filter = /^[0-9]{4}$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
							if( blnValid ) blnValid = formValidation_validateZip_PT( elemValue );
						}
					break;
					
					case "date_PT":
						if( elemValue != "" )
							blnValid = formValidation_validateDate( elemValue, 'PT' );
					break;
					
					case "date_EN":
						if( elemValue != "" )
							blnValid = formValidation_validateDate( elemValue, 'EN' );
					break;
					
					case "carPlate_PT":
						if( elemValue != "" )
							blnValid = formValidation_validateCarPlate_PT( elemValue );
					break;
					
					case "url":
						if( elemValue != "" ){
							var filter = /(ftp|http|https):\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+$/;
							if( ! filter.test( elemValue ) ) blnValid = false;
							
						}
					break;
					
					default:
						try{
							blnValid = eval(arrValidationTypes[j])( elemValue );
						}
						catch( err ){
							alert( "ERRO FORM_TEMPLATE: funÃ§Ã£o nÃ£o definida" );
							blnValid = true;
						}
					break;
				}
				
				if( !show_alert ){
					if( blnValid == false ){
						document.getElementById(divErrorId).innerHTML = errorMessage;   
						//elem.style.backgroundColor = "#cccccc";
						elem.focus();
						return false;
					}
					else{
						document.getElementById(divErrorId).innerHTML = "";
						//elem.style.backgroundColor = "#FFFFFF";
					}
				}
				else{
					if( blnValid == false ){
						alert( errorMessage );
						elem.focus();
						return false;
					}
				}
			}
		}
		
		// verifies if listener is defined and calls it.
        var listener_defined = false;
		if(typeof formValidation_listener == 'function') listener_defined = true;
		if( listener_defined ) formValidation_listener();
		
		return true;
	}
	
	
	
	function formValidation_getFieldValue( formObj, elem, elemType ){
		
		switch( elemType ){
			case "text": 
				return elem.value;
			break;
			case "select":
				return elem.selectedIndex;
			break;
			case "select-one": 
				return elem.selectedIndex;
			break;
			case "radio":
				var radioObj = formObj.elements[ elem.name ];
				return formValidation_getCheckedRadio( radioObj )
			break;
			default: 
				return elem.value;
			break;
		}
		return "";
	}
	
	
	
	function formValidation_getCheckedRadio( radioObj ){
		if(!radioObj)
			return "";
		var radioLength = radioObj.length;
		if(radioLength == undefined){
			if(radioObj.checked)
				return radioObj.value;
			else
				return "";
		}
		for(var i = 0; i < radioLength; i++) {
			if(radioObj[i].checked) {
				return radioObj[i].value;
			}
		}
		return "";
	}
	
	
	
	function formValidation_allTrim(cValue){
		var lDone=false;

		while (lDone==false){
			if (cValue.length==0) {return cValue;}
			if (cValue.indexOf(' ')==0){cValue=cValue.substring(1);lDone=false; continue;}
			else {lDone=true;}
			if (cValue.lastIndexOf(' ')==cValue.length-1){cValue=cValue.substring(0, cValue.length-1);lDone=false;continue;}
			else {lDone=true;}
		}
		return cValue;
	}
	
	
	function formValidation_isValidNIF(nif){
		var c;
		var checkDigit = 0;
		//Check if is not null, is numeric and if has 9 numbers
		if( nif != null && nif == parseInt(nif) && nif.length == 9 ){
			//Get the first number of NIF
			var c = nif.charAt(0);
			//Check firt number is (1, 2, 5, 6, 8 or 9)
			if(c == '1' || c == '2' || c == '5' || c == '6' || c == '8' || c == '9')
			{
				//Perform CheckDigit calculations
				checkDigit = c * 9;
				var i = 0;
				for(i = 2; i <= 8; i++)
				{
					checkDigit += nif.charAt(i-1) * (10-i);

				}
				checkDigit = 11 - (checkDigit % 11);
				//if checkDigit is higher than ten set it to zero
				if(checkDigit >= 10)
					checkDigit = 0;
				//Compare checkDigit with the last number of NIF
				//If equal the NIF is Valid.           
				if(checkDigit == nif.charAt(8))
					return true;           
			}       
		}
		return false;
	} 
	
	
	// returns true if recived phone is in invalid phones list
	function formValidation_isInvalidPhoneNumbers( phone ){		
		var invalidPhones = ['211234567','961234567','911234567','931234567','921234567','960000000','961111111','962222222','963333333','964444444','965555555','966666666','967777777','968888888','969999999','910000000','911111111','912222222','913333333','914444444','915555555','916666666','917777777','918888888','919999999','930000000','931111111','932222222','933333333','934444444','935555555','936666666','937777777','938888888','939999999','920000000','921111111','922222222','923333333','924444444','925555555','926666666','927777777','928888888','929999999','210000000','211111111','212222222','213333333','214444444','215555555','216666666','217777777','218888888','219999999'];
		
		for( var i=0; i < invalidPhones.length; ++i ){
			if( phone == invalidPhones[i] ) return true;
		}
		return false;
	}
	
	
	// valid date types => dd/mm/YYYY dd-mm-YYYY
	function formValidation_validateDate( strValue, format ) {
		if( format == 'EN' ){
			var objRegExp = /^\d{4}(\-|\/|\.)\d{2}\1\d{2}$/
			if( !objRegExp.test(strValue) )
				return false;
				
			var strSeparator = strValue.substring(4,5);
			var arrayDate = strValue.split(strSeparator);
			return formValidation_validateDateDays( arrayDate[2], arrayDate[1], arrayDate[0] );
		}
		if( format == 'PT' ){
			var objRegExp = /^\d{2}(\-|\/|)\d{2}\1\d{4}$/
			 
			//check to see if in correct format
			if(!objRegExp.test(strValue))
				return false; //doesn't match pattern, bad date
			
			var strSeparator = strValue.substring(2,3);
			var arrayDate = strValue.split(strSeparator);
			return formValidation_validateDateDays( arrayDate[0], arrayDate[1], arrayDate[2] );
		}
		return false; //any other values, bad date
	}
	
	
	function formValidation_validateDateDays( day_val, month_val, year_val ){
		
		//create a lookup for months not equal to Feb.
		var arrayLookup = { '01' : 31,'03' : 31, 
							'04' : 30,'05' : 31,
							'06' : 30,'07' : 31,
							'08' : 31,'09' : 30,
							'10' : 31,'11' : 30,
							'12' : 31 }
							
		var intDay = parseInt( day_val, 10 ); 
			
		//check if month value and day value agree
		if(arrayLookup[month_val] != null) {
		  if(intDay <= arrayLookup[month_val] && intDay != 0)
			return true; //found in lookup table, good date
		}
			
		// verify biss year
		var intMonth = parseInt(month_val,10);
		if (intMonth == 2) { 
			var intYear = parseInt(year_val);
		 	if (intDay > 0 && intDay < 29) {
				return true;
			}
			else if (intDay == 29) {
				 if ((intYear % 4 == 0) && (intYear % 100 != 0) || (intYear % 400 == 0)) {
					// year div by 4 and ((not div by 100) or div by 400) ->ok
				 	return true;
				 }   
			}
		}
		return false;
	}
	
	
	// validate portuguese car plates formats
	function formValidation_validateCarPlate_PT( elemValue ){
		var filter1 = /^[A-Za-z]{2}[-][0-9]{2}[-][0-9]{2}$/;
		var filter2 = /^[0-9]{2}[-][A-Za-z]{2}[-][0-9]{2}$/;
		var filter3 = /^[0-9]{2}[-][0-9]{2}[-][A-Za-z]{2}$/;
		if( ! filter1.test( elemValue ) && ! filter2.test( elemValue ) && ! filter3.test( elemValue ) ) return false;
		return true;
	}
	
	
	function formValidation_validateZip_PT( elemValue ){
							
		var postalCodesArray = ['1000','1048','1049','1050','1066','1067','1068','1069','1070','1092','1098','1099','1100','1149','1150','1166','1167','1169','1170','1199','1200','1208','1209','1249','1250','1269','1300','1349','1350','1399','1400','1449','1495','1499','1500','1549','1600','1649','1675','1679','1685','1689','1700','1748','1749','1750','1769','1800','1849','1885','1886','1900','1949','1950','1959','1990','1998','2000','2004','2005','2009','2025','2040','2050','2054','2065','2070','2080','2090','2100','2120','2125','2130','2135','2139','2140','2150','2200','2205','2230','2240','2250','2260','2300','2305','2330','2350','2380','2384','2395','2400','2404','2405','2410','2414','2415','2419','2420','2424','2425','2430','2435','2440','2445','2450','2460','2461','2475','2480','2485','2490','2495','2499','2500','2504','2510','2520','2525','2530','2540','2550','2560','2565','2580','2581','2590','2594','2600','2601','2605','2609','2610','2614','2615','2616','2619','2620','2621','2625','2626','2630','2634','2635','2639','2640','2644','2645','2649','2650','2654','2655','2659','2660','2664','2665','2669','2670','2674','2675','2680','2681','2685','2689','2690','2691','2694','2695','2699','2700','2704','2705','2706','2709','2710','2714','2715','2719','2720','2724','2725','2729','2730','2734','2735','2739','2740','2744','2745','2749','2750','2754','2755','2756','2760','2761','2765','2769','2770','2774','2775','2779','2780','2784','2785','2789','2790','2794','2795','2799','2800','2804','2805','2809','2810','2814','2815','2819','2820','2821','2825','2829','2830','2834','2835','2839','2840','2844','2845','2855','2860','2864','2865','2870','2890','2894','2900','2904','2910','2914','2925','2929','2950','2951','2954','2955','2959','2965','2970','2975','2985','3000','3004','3020','3025','3030','3034','3040','3044','3045','3049','3050','3054','3060','3070','3080','3084','3090','3094','3100','3105','3130','3140','3150','3200','3220','3230','3240','3250','3260','3270','3280','3300','3305','3320','3330','3350','3360','3400','3405','3420','3430','3440','3450','3460','3464','3465','3475','3500','3504','3505','3510','3514','3515','3519','3520','3525','3530','3534','3550','3560','3570','3600','3610','3620','3624','3630','3640','3650','3660','3670','3680','3684','3700','3701','3720','3730','3740','3744','3750','3754','3770','3780','3800','3804','3810','3814','3830','3840','3850','3860','3864','3865','3870','3880','3884','3885','4000','4049','4050','4099','4100','4149','4150','4169','4199','4200','4249','4250','4269','4300','4349','4350','4369','4400','4404','4405','4409','4410','4414','4415','4420','4425','4430','4434','4435','4440','4445','4450','4454','4455','4460','4464','4465','4470','4471','4474','4475','4479','4480','4484','4485','4486','4490','4495','4500','4504','4505','4510','4515','4520','4525','4535','4540','4550','4560','4564','4570','4575','4580','4585','4590','4595','4599','4600','4605','4610','4615','4620','4625','4630','4635','4640','4650','4660','4690','4700','4704','4705','4709','4710','4714','4715','4719','4720','4730','4740','4745','4750','4755','4760','4764','4765','4770','4775','4780','4785','4795','4800','4804','4805','4809','4810','4814','4815','4820','4824','4825','4830','4835','4839','4840','4845','4850','4860','4870','4880','4890','4900','4904','4905','4910','4920','4925','4930','4935','4939','4940','4950','4960','4970','4974','4980','4990','5000','5004','5030','5040','5050','5054','5060','5070','5085','5090','5100','5110','5114','5120','5130','5140','5150','5155','5160','5180','5200','5210','5225','5230','5300','5301','5320','5335','5340','5350','5360','5370','5385','5400','5425','5430','5445','5450','5460','5470','6000','6004','6005','6030','6040','6050','6060','6090','6100','6110','6120','6150','6160','6185','6200','6201','6215','6225','6230','6250','6260','6270','6285','6290','6300','6301','6320','6324','6350','6355','6360','6370','6400','6420','6430','6440','7000','7004','7005','7009','7040','7050','7080','7090','7100','7150','7160','7170','7200','7220','7230','7240','7250','7300','7301','7320','7330','7340','7350','7354','7370','7374','7400','7425','7430','7440','7450','7460','7470','7480','7490','7500','7520','7540','7555','7565','7570','7580','7595','7600','7630','7645','7665','7670','7700','7750','7780','7800','7801','7830','7860','7875','7885','7900','7920','7940','7960','8000','8004','8005','8009','8100','8104','8125','8135','8136','8150','8200','8201','8300','8365','8375','8400','8401','8500','8501','8550','8600','8601','8650','8670','8700','8800','8801','8900','8950','8970','9000','9004','9020','9024','9030','9050','9054','9060','9064','9100','9125','9135','9200','9225','9230','9240','9270','9300','9304','9325','9350','9360','9370','9385','9400','9500','9504','9545','9555','9560','9580','9600','9625','9630','9650','9675','9680','9700','9701','9760','9800','9850','9875','9880','9900','9901','9904','9930','9940','9950','9960','9970','9980'];
							
		var zip4 = elemValue.substring(0,4);
		for ( var i=0; i < postalCodesArray.length; ++i ){
			if( zip4 == postalCodesArray[i] )
				return true;
		}
		return false;	
	}
	
	
