// wForms - a javascript extension to web forms.
// Form Validation Component
// v2.0 beta - Feb.14th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
    
    
   if(wFORMS) {
		// Component properties 
		// wFORMS.functionName_formValidation  is defined at the bottom of this file
       	wFORMS.preventSubmissionOnEnter   		= false; 			// prevents submission when pressing the 'enter' key. Set to true if pagination behavior is used.
	   	wFORMS.showAlertOnError 			  	= true; 			// sets to false to not show the alert when a validation error occurs.
		wFORMS.className_required 			 	= "required";
		wFORMS.className_validationError_msg 	= "errMsg";		 
		wFORMS.className_validationError_fld	= "errFld";  
		wFORMS.classNamePrefix_validation 		= "validate";	
		wFORMS.idSuffix_fieldError				= "-E";
		
		// Error messages. This array may be overwritten in a separate js file for localization or customization purposes.
		wFORMS.arrErrorMsg = new Array(); 
		wFORMS.arrErrorMsg[0] = "This field is required. "; // required
		wFORMS.arrErrorMsg[1] = "The text must use alphabetic characters only (a-z, A-Z). Numbers are not allowed. "; 	// validate_alpha
		wFORMS.arrErrorMsg[2] = "This does not appear to be a valid email address.";									// validate_email
		wFORMS.arrErrorMsg[3] = "Please enter an integer.";															// validate_integer
		wFORMS.arrErrorMsg[4] = "Please enter a float (ex. 1.9).";
		wFORMS.arrErrorMsg[5] = "Unsafe password. Your password should be between 4 and 12 characters long and use a combinaison of upper-case and lower-case letters.";
		wFORMS.arrErrorMsg[6] = "Please use alpha-numeric characters only [a-z 0-9].";
		wFORMS.arrErrorMsg[7] = "This does not appear to be a valid date.";
		wFORMS.arrErrorMsg[8] = "%% error(s) detected. Your form has not been submitted yet.\nPlease check the information you provided."; // %% will be replaced by the actual number of errors.

		wFORMS.behaviors['validation'] = {

		   // ------------------------------------------------------------------------------------------
		   // evaluate: check if the behavior applies to the given node. Adds event handlers if appropriate
		   // ------------------------------------------------------------------------------------------
			evaluate: function(node) {
               if(node.tagName.toUpperCase()=="FORM") {
				   // functionName_formValidation can be a reference to a function, or a string with the name of the function.
				   // avoid using typeof
				   if(wFORMS.functionName_formValidation.toString()==wFORMS.functionName_formValidation) {
					   // this is a string, not a function
					   wFORMS.functionName_formValidation = eval(wFORMS.functionName_formValidation);
				   }
                   wFORMS.helpers.addEvent(node,'submit',wFORMS.functionName_formValidation);
				   //wFORMS.debug('validation/evaluate: FORM '+ node.id,3);
               }
           },
		   // ------------------------------------------------------------------------------------------
           // init: executed once evaluate has been applied to all elements
		   // ------------------------------------------------------------------------------------------	   
		   init: function() {
		   },
		   
		   // ------------------------------------------------------------------------------------------
           // run: executed when the behavior is activated
		   // ------------------------------------------------------------------------------------------	   		   
           run: function(e) {
				var element  = wFORMS.helpers.getSourceElement(e);
				if(!element) element = e;
				//wFORMS.debug('validation/run: ' + element.id , 5);	
				
				// on multi-page forms we need to prevent the submission when the 'enter' key is pressed
				// (doesn't work in Opera. Further tests needed in IE and Safari)
				if(wFORMS.preventSubmissionOnEnter) { 
					if(element.type && element.type.toLowerCase()=='text') 
						// source element is a text field, the form was submitted with the 'enter' key.
						return wFORMS.preventEvent(e); 
				}
				// make sure we have the form element
				while (element && element.tagName.toUpperCase() != 'FORM') {
					element = element.parentNode;
				}		
				
				var nbErrors = wFORMS.behaviors['validation'].validateElement(element, true);
				
				if (nbErrors > 0) {
					if(wFORMS.showAlertOnError){ wFORMS.behaviors['validation'].showAlert(nbErrors); }
					return wFORMS.helpers.preventEvent(e); 
				}
				return true;
			},
		   
			// ------------------------------------------------------------------------------------------
			// remove: executed if the behavior should not be applied anymore
			// ------------------------------------------------------------------------------------------
			remove: function() {
			},
		   
		   
			// ------------------------------------------------------------------------------------------
			// validation functions
			// ------------------------------------------------------------------------------------------
			validateElement: function(element /*, deep */) {
				
				var wBehavior = wFORMS.behaviors['validation'];		// shortcut
				
				// do not validate elements that are in a OFF-Switch
				// Note: what happens if an element is the target of 2+ switches, some ON and some OFF ?
				if(wFORMS.hasBehavior('switch') && wFORMS.helpers.hasClassPrefix(element,wFORMS.classNamePrefix_offState)) {
					return 0;
				}
				// do not validate elements that are not in the current page (Paging Behavior)
				if(wFORMS.hasBehavior('paging') &&  wFORMS.helpers.hasClass(element,wFORMS.className_paging)
											    && !wFORMS.helpers.hasClass(element,wFORMS.className_pagingCurrent) ) {
					return 0;
				}
				
				var nbErrors = 0;
				
				// check if required
				if(!wBehavior.checkRequired(element)) {
					wBehavior.showError(element,wFORMS.arrErrorMsg[0]);
					nbErrors++;
					//wFORMS.debug('validation/error: [required]' + element.id + '('+nbErrors+')' , 5);
				} else {
				
					// input format validation
					if (wFORMS.helpers.hasClassPrefix(element,wFORMS.classNamePrefix_validation)) {
		
						var arrClasses = element.className.split(" ");
						for (j=0;j<arrClasses.length;j++) {
							switch(arrClasses[j]) {
								case "validate-alpha":
									if(!wBehavior.isAlpha(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[1]);
										nbErrors++;
										//wFORMS.debug('validation/error: [alpha]' + element.id , 5);
									}
									break;
								case "validate-alphanum":
									if(!wBehavior.isAlphaNum(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[6]);
										nbErrors++;
										//wFORMS.debug('validation/error: [alphanum]' + element.id , 5);
									}
									break;
								case "validate-date":
									if(!wBehavior.isDate(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[7]);
										nbErrors++;
										//wFORMS.debug('validation/error: [date]' + element.id , 5);
									}
									break;
								case "validate-time":
									/* NOT IMPLEMENTED */
									break;
								case "validate-email":
									if(!wBehavior.isEmail(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[2]);
										nbErrors++;
										//wFORMS.debug('validation/error: [email]' + element.id , 5);
									}
									break;
								case "validate-integer":
									if(!wBehavior.isInteger(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[3]);
										nbErrors++;
										//wFORMS.debug('validation/error: [integer]' + element.id , 5);
									}					
									break;
								case "validate-float":
									if(!wBehavior.isFloat(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[4]);
										nbErrors++;
										//wFORMS.debug('validation/error: [float]' + element.id , 5);
									}
									break;
								case "validate-strongpassword": // NOT IMPLEMENTED
									if(!wBehavior.isPassword(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[5]);
										nbErrors++;
										//wFORMS.debug('validation/error: [password]' + element.id , 5);
									}
									break;
							} // end switch
						} // end for
					}
				} // end validation check
				
				// remove previous error flags if any.
				if(nbErrors==0) {
					var rErrClass     = new RegExp(wFORMS.className_validationError_fld,"gi");
					element.className = element.className.replace(rErrClass,"");
					var errorMessage  = document.getElementById(element.id + wFORMS.idSuffix_fieldError);
					if(errorMessage)  errorMessage.parentNode.removeChild(errorMessage);
				} 
					
				// recursive loop	
				var deep = arguments[1] ? arguments[1] : true;
				if(deep) {
					for(var i=0; i < element.childNodes.length; i++) {
						if(element.childNodes[i].nodeType==1) { // Element Nodes only
							nbErrors += wBehavior.validateElement(element.childNodes[i], deep);
						}
					}
				}
				
				return nbErrors;
			},
			
			// ------------------------------------------------------------------------------------------
			checkRequired: function(element) {
										
				if(wFORMS.helpers.hasClass(element,wFORMS.className_required)) {

					var wBehavior = wFORMS.behaviors['validation'];		// shortcut

					switch(element.tagName.toUpperCase()) {
						case "INPUT":
							switch(element.getAttribute("type").toLowerCase()) {
								case "checkbox":
									return element.checked; 
									break;
								case "radio":
									return element.checked; 
									break;
								default:
									return !wBehavior.isEmpty(element.value);
							}
							break;
						case "SELECT":
							return !wBehavior.isEmpty(element.options[element.selectedIndex].value);
							break;
						case "TEXTAREA":
							return !wBehavior.isEmpty(element.value);
							break;
						default:
							return wBehavior.checkOneRequired(element);
							break;
					} 	
				} 
				return true;
			},
			checkOneRequired: function(element) {	

				var value = false;
				if(element.nodeType != 1) return false;
				if(element.tagName.toUpperCase() == "INPUT") {
					switch(element.type.toLowerCase()) {
						case "checkbox":
							value = element.checked; 
							break;
						case "radio":
							value = element.checked; 
							break;
						default:
							value = element.value;
					}
				} else value = element.value;
				if(value && !wFORMS.behaviors['validation'].isEmpty(value)) {
					return true;
				}
				for(var i=0; i<element.childNodes.length;i++) {
					if(wFORMS.behaviors['validation'].checkOneRequired(element.childNodes[i])) return true;
				}
				return false;
			},
				
			// ------------------------------------------------------------------------------------------
			isEmpty: function(s) {
				var regexpWhitespace = /^\s+$/;
				return  ((s == null) || (s.length == 0) || regexpWhitespace.test(s));
			},
			isAlpha: function(s) {
				var regexpAlphabetic = /^[a-zA-Z]+$/; // Add ' and - ?
				return wFORMS.behaviors['validation'].isEmpty(s) || regexpAlphabetic.test(s);
			},
			isAlphaNum: function(s) {
				var illegalChars = /\W/;
				return wFORMS.behaviors['validation'].isEmpty(s) || !illegalChars.test(s);
			},
			isDate: function(s) {
				var testDate = new Date(s);
				return wFORMS.behaviors['validation'].isEmpty(s) || !isNaN(testDate);
			},
			isEmail: function(s) {
				var regexpEmail = /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/;
				return wFORMS.behaviors['validation'].isEmpty(s) || regexpEmail.test(s);
			},
			isInteger: function(s) {
				var regexp = /^[+]?\d+$/;
				return wFORMS.behaviors['validation'].isEmpty(s) || regexp.test(s);
			},
			isFloat: function(s) {		
				return wFORMS.behaviors['validation'].isEmpty(s) || !isNaN(s);
			},
			// NOT IMPLEMENTED
			isPassword: function(s) {
			// Matches strong password : at least 1 upper case latter, one lower case letter. 4 characters minimum. 12 max.
			//var regexp = /^(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{4,12}$/;  // <= breaks in IE5/Mac
				return wFORMS.behaviors['validation'].isEmpty(s);
			},
			
			// ------------------------------------------------------------------------------------------		
			// Error Alert Functions
			// ------------------------------------------------------------------------------------------		
			showError: function (element,errorMsg) {		
				if(element.className.indexOf(wFORMS.className_validationError_fld)!= -1) {
					return;
				}
				if (!element.id) element.id = wFORMS.helpers.randomId(); // we'll need an id here.		
				// Add error flag to the field
				element.className += " " + wFORMS.className_validationError_fld;
				// Prepare error message
				var msgNode = document.createTextNode(" " + errorMsg);
				// Find error message placeholder.
				var fe = document.getElementById(element.id +  wFORMS.idSuffix_fieldError);
				if(!fe) { // create placeholder.
					fe = document.createElement("div"); 
					fe.setAttribute('id', element.id +  wFORMS.idSuffix_fieldError);			
					// attach the error message after the field label if possible
					var fl = document.getElementById(element.id +  wFORMS.idSuffix_fieldLabel);
					if(fl)
						fl.parentNode.insertBefore(fe,fl.nextSibling);
					else
						// otherwise, attach it after the field tag.
						element.parentNode.insertBefore(fe,element.nextSibling);
				}
				// Finish the error message.
				fe.appendChild(msgNode);  	
				fe.className += " " + wFORMS.className_validationError_msg;
			},
			showAlert: function (nbTotalErrors) {
			   alert(wFORMS.arrErrorMsg[8].replace('%%',nbTotalErrors));
			}			
       } // End wFORMS.behaviors['validation']
	   
		wFORMS.functionName_formValidation = wFORMS.behaviors['validation'].run;
		// backward compatibility
		wFORMS.formValidation  			   = wFORMS.behaviors['validation'].run;
   }
   
   
   
