// JavaScript Document
/* jQuery Form Validator v0.0
   Written by Luis A. Camilo (developer@lacdesign.net)  

   Copyright (c) 2008 Luis Camilo (http://www.lacdesign.net/code/jquery-formvalidator)
   Dual licensed under the GPL (http://www.gnu.org/licenses/gpl-3.0.txt) and 
   CC (http://creativecommons.org/licenses/by/3.0/) licenses. "Share or Remix it but please Attribute the authors."
   Date: 10-13-2008  */
 
(function($){
		
	function formValidator(oForm, oMessages, ErrorBox){
		 this.debug = true; //Debug Validator
		 this.Form =  oForm; //Message Validation Format
		 this.Messages = oMessages;
		 this.ErrorBox = ErrorBox;
		 $.fn.CurrentForm = function(){return this};
		 
		 
	}
	 
 
	$.extend(formValidator.prototype, {
		dMessages: {
			empty: "This field cannot be empty.",			
			email: "Please enter a valid email.",			
			date: "Please enter a valid date. {mm/dd/yyyy}",	
			zipCode: "Please enter a valid zipcode.",
			number: "Please enter a valid number.",	 
			equalTo: "Please enter the same value again. {nodeName}", //DOESN'T WORK BY DEFAULT YET
			FileType: "Please enter a valid file. {pdf | doc}", 
			dateDiff: "Date Range Must be 10 days or less {nodeName | 10}", //DOESN'T WORK BY DEFAULT YET
	 		checkBox : "Please Select At least One"
		 
		},
		
		
		formErrors:{},
		
		//Validation Functions
		empty:function(nodeName, nodeValue, vMessage){			
			
			 if(!(nodeValue).length ){
				this.formErrors[nodeName] = vMessage;
			 }
		   
		},
		
		
		checkBox :function(nodeName, nodeValue, vMessage){			
			 
			var CB = this.Form[nodeName];
			var isChecked = 0;
			 for(i =0; i < CB.length; i++){
				 isChecked = (CB[i].checked)?1:0;				
     			 if(isChecked) break; 
			 }
			 
			 
			 if(!isChecked) this.formErrors[nodeName] = vMessage;
		   
		},
		 
		email:function(nodeName, nodeValue, vMessage){			 
			var regex = new RegExp(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/);
			if(!regex.test(nodeValue)){
				this.formErrors[nodeName] = vMessage;
			 }
		   
		},
		
		zipCode:function(nodeName, nodeValue, vMessage){				
			var zipregex = new RegExp(/(^\d{5}$)|(^\d{5}-\d{4}$)/);
			if(!zipregex.test(nodeValue)){				
				this.formErrors[nodeName] = vMessage;
			}

		},
		
		
		number:function(nodeName, nodeValue, vMessage){
	 
			 if(!(nodeValue).length || !nodeValue.isNumeric() ){
				this.formErrors[nodeName] = vMessage;
			 }
			
		},				
		
		
		equalTo:function(nodeName, nodeValue, vMessage){
			 
			var otherNodeValue = this.Form[vMessage[1]].value;
			if(otherNodeValue != nodeValue){
				this.formErrors[nodeName] = vMessage[0];
			}
			
			
		},
		dateDiff:function(nodeName, nodeValue, vMessage){
			  
		
			var diffValue = $.trim(vMessage[1][0]);
			var maxVal = parseInt($.trim(vMessage[1][1]));

			if(!this.formErrors[this[vMessage[1]]]){
		
				//VALIDATE DATE 
				
				this.date(nodeName, nodeValue, Array(this.Form[diffValue].message[0] , this.Form[diffValue].message[1]  ));
				//CHECK FIRST IF DATE IS VALID
				if(!this.formErrors[nodeName]){
					
					//CREATE DATE DIFF
					if(this[diffValue].dateDiff(this[nodeName]) > maxVal)this.formErrors[nodeName] = vMessage;
				}
				
				
			}
			
			
			
			
		},
		
		date:function(nodeName, nodeValue, vMessage){
	 
	 	 
			
		/***GET SEPARATORS AND VALIDATE INPUTS ***/
			
			//GET SEPARATORS
			var separator = [];
			cMsg = new String(vMessage[1]);
			
			var nSCounter = 0;
			var LastPos = 0;
			var error = false;
			while(cMsg.length > 0){ 
				nSCounter++; 
				if(cMsg.charAt(0).search(/\w/) <0 ){
					separator.push({delimiter: cMsg.charAt(0) , charPos:nSCounter, LastPos: LastPos});
					
					LastPos += nSCounter;
					nSCounter = 0;					 
				}else{
					if(String(nodeValue).charAt(LastPos).search(/\d/g) < 0){
					error = true;
					break;	
					}
				}
				cMsg = cMsg.slice(1);
				
				 
				 
			
			}
		 
			
			
			//VALIDATE INPUT		 
			 if(!error){
			 cMsg = new String(vMessage[1]);
				 for(i in separator){		
					if(nodeValue.indexOf(separator[i].delimiter)  != separator[i].charPos-1 || (nodeValue.substr(LastPos, nodeValue.length).length != cMsg.substr(LastPos, cMsg.length).length)){
					error = true;
					}
					if(error) break;
				 }
			 }
			 
			
			
		 	var today = new Date();
			
			 
		 
		 	if(error){this.formErrors[nodeName] = vMessage[0] + ' ('+ vMessage[1] + ')' + ' ie: Today  (' + today.dateFormat(''+vMessage[1]) + ')'
			}else{
			 today.dateFormat('mm/dd/yyyy', nodeValue);
			 this[nodeName] = today;
			} 
			  
			
		},		
						
		
		FileType:function(nodeName, nodeValue, vMessage){
			
			//CREATE REGEXP FOR FILE EXT. 
		 
			validExt = '^.*\\';			
			for(i = 0; i <  vMessage[1].length; i++){//Starting on 1 BECAUSE OF THE EMBEDED VALUES
				validExt += '.' +  vMessage[1][i] + '?$' + ((i<vMessage[1].length-1)? '|': '') ;
				
			}
			
			var FileReg = new RegExp(eval('/'+validExt+'/i'));			
			if(!FileReg.test(nodeValue)){				
				this.formErrors[nodeName] = vMessage;
			}

		
		},
		
		
		//SHOW ERROR MESSAGE 
		
		ShowError: function(){
				
			 var ErrorMessage = '';
			 var ErrorBox = this.ErrorBox;
			 
			 
			 $.each(this.formErrors,function(name,value){	
				
				if($.fn.isArray(value)){ //IF VALUE IS AN ARRAY, CONVERT IT INTO A STRING
					var result =  '';
					for(i in value){
						result += value[i];
					}
					value = result;
				}
				 
				$('#'+name).parent().append('<b id="'+name+'Indc" class="errorIndc">*</b>');
				 
				if(ErrorBox.id){
					ErrorMessage += '<li>'+value+'</li>';	
				}else{
					ErrorMessage += value+'\n';	
				}
			 }
			);
			 
			if(ErrorBox.id){
			 $(this.ErrorBox).html('<h3>You have The Following Errors</h3>')
			 $(this.ErrorBox).append($('<ul></ul>').html(ErrorMessage) );
			
			 $(this.ErrorBox).show('normal');
			 
			}else{
				alert(ErrorMessage);
			}
		},
		
		validateMe: function(){
			var CurrentForm =  this.Form; 
			var Messages = this.Messages;
			var formError = false;
			this.formErrors = {}; //CLEAR ANY ERROR
			if(this.ErrorBox.id)$(this.ErrorBox).hide('normal');
			
	 		for(i in Messages){
				 
				nodeName = i;
				//PULL VALIDATE MODE AND MESSAGE FROM CURRENT NODE 
				cMessage = Messages[i].split(',')		
				vMode = cMessage[0];
				//REMOVE ERROR MESSAGES
				if($('#'+i+'Indc'))$('#'+i+'Indc').remove(); 		
				
				vMessage = (cMessage[1])?this.getMessage(cMessage[1]): this.dMessages[cMessage[0]];
			    nodeValue = $.trim(this.Form[nodeName].value);
				
				this.Form[nodeName].message = vMessage;		
				
				this[vMode](nodeName,nodeValue, vMessage); // VALIDATE CURRENT NODE SEND MESSAGE AND NODENAME TO VALIDATION SECTION
				
				
			}
			
			formError = $.getObjLength(this.formErrors);
			 

			
			if(formError)this.ShowError();
			return !formError;
		} ,
		
		
		 
		
		
		getMessage: function(vMessage){
			//Check if There is an Embeded Message inside the Message
			 
			var sPoint = vMessage.indexOf('{' );
			if(sPoint >= 0){
			 var fPoint = vMessage.indexOf('}' );
			 var EmbededMessage = vMessage.slice(sPoint+1,fPoint);
			 
			 msgArray = new Array(vMessage.slice(0, sPoint));
			 msgArray.push(EmbededMessage.split('|'));			 
			 vMessage = msgArray;
			  
			}
		    
			
			return vMessage;
		}
		
		

	 });
	
	
	
	
	Date.prototype.dateDiff = function (edDate, ret) {
		
		ret = (ret)?ret:'d'; //SET IT DEFAULT TO DAYS
		
		var start = this;
		var end = edDate;
		ret = ret.toLowerCase();
		if(ret=='d') {
		return Math.ceil((end.getTime() - start.getTime()) / (24*60*60*1000));
		}
		else if(ret=='h') {
		return Math.ceil((end.getTime() - start.getTime()) / (60*60*1000));
		}
		else if(ret=='n') {
		return Math.ceil((end.getTime() - start.getTime()) / (60*1000));
		} else if(ret=='s') {
		return Math.ceil((end.getTime() - start.getTime()) / 1000);
		} else {
		return Math.ceil(end.getTime() - start.getTime());
		}
	};
	
	
	Date.prototype.MonthNames = [
		'January','February','March','April','May','June','July',
		'August','September','October','November','December'
	];
	
	Date.prototype.DayNames = [
		'Sunday','Monday','Tuesday','Wednesday','Thursday','Friday',
		'Saturday'
	];
	
	Date.prototype.dateFormat = function (pattern, cDate) {
		var Patterns = {
			yy: function(date, pDate) {
				
			return  date.getYear();
			},
			yyyy: function(date, pDate) {
				if(pDate)date.setFullYear(pDate);
			return date.getFullYear().toString();
			},
			mmmm: function(date, pDate) {
				if(pDate)date.month(pDate);
			return date.MonthNames[date.getMonth()];
			},
			mmm: function(date, pDate) {
				if(pDate)date.setMonth(pDate);
			return date.MonthNames[date.getMonth()].substr(0,3);
			},
			mm: function(date, pDate) {
				if(pDate)date.setMonth(pDate);
			return (date.getMonth()<10)?'0'+date.getMonth():date.getMonth();
			},
			m: function(date, pDate) {
				if(pDate)date.setMonth(pDate);
			return date.getMonth()+1;
			} ,
			dddd: function(date, pDate) {
				if(pDate)date.setMonth(date.getMonth(),pDate);
			return date.DayNames[date.getDay()];
			},
			ddd: function(date, pDate) {
				if(pDate)date.setMonth(date.getMonth(),pDate);
			return date.DayNames[date.getDay()].substr(0,3);
			},
			dd: function(date, pDate) {
				if(pDate)date.setMonth(date.getMonth(),pDate);
			return date.getDate();
			}
		}
		
	 
		var patternParts = /^(m{1,4}|y{4}|y{2}|d{2,4})/;
		
	 	 
		var result = new String();
		var tPattern = pattern;
		var pMatch = new String();
		var nPatternCount = 0;
		var pDate = 0;
	 	while(pattern.length > 0){
		
			if(patternParts.exec(pattern)){
				
				var matched = patternParts.exec(pattern)[0];
				
				if(matched){	 
					if(cDate){ 
					pDate = parseFloat(cDate.substr(nPatternCount, matched.length ) +'\n' + cDate +'\n'+  pattern +'\n'+ nPatternCount);
					}
				//LETS TRY TO BREAK THE PATTERN APPART 
				patternIndex = tPattern.indexOf(pMatch)+pMatch.length;	
				result += tPattern.substr(patternIndex,   tPattern.indexOf(matched)-patternIndex ) + Patterns[matched](this, pDate);
				
				pattern = pattern.slice(matched.length);
				pMatch = matched;
				 	
				nPatternCount++;
				}
				
			}else{
			pattern = pattern.slice(1);		
			}
			
		nPatternCount++;
		}
		
		
		return result;		
		
		
	}
	
	$.fn.isArray = function isArray(obj) {		 
		   if (obj.constructor.toString().indexOf("Array") == -1)
			  return false;
		   else
			  return true;
	}
	
	String.prototype.isNumeric = function(){
	   sText = this;
	   var ValidChars = "0123456789.,";
	   var IsNumber=true;
	   var Char;
	
	 
	   for (i = 0; i < sText.length && IsNumber == true; i++) 
		  { 
		  Char = sText.charAt(i); 
		  if (ValidChars.indexOf(Char) == -1) 
			 {
			 IsNumber = false;
			 }
		  }
		  
	   return IsNumber;   
   }; 

	
	$.getObjLength = function(object){
		 
		var length = 0;
		for(i in object){
			length++;
		};
		return length;
	};

	
	
	$.fn.Validator = function(oMessage, ErrorID) {
		  
		ErrorBox = 0;
		 
		if($('#'+ErrorID)){
			ErrorBox = $('#'+ErrorID);
			ErrorBox.id = ErrorID;
			
		}
		
		return	this.each(function(){
				if(this.nodeName.toLowerCase() == 'form'){			
				
				//CREATE AN INSTANCE OF THE VALIDATOR WITH THE VALUE PASSED TO THE FUNCTION				 
				var validate = new formValidator(this, oMessage, ErrorBox);
				//The Name and ID of the Submit Button Must be Submit
				$.validateInstance = validate;								
				$(this.nodeName).bind('submit', function(){return false});			
				$(this['Submit']).bind('click',function(){
					if($.validateInstance.validateMe())	{
						node = this;
						while(node.parentNode){
							if(node.nodeName.toLowerCase() == 'form'){node.submit(); break;}
							node = node.parentNode;
						}
					
					}						   
																						   
				});				 
				 
				 
				 
				 
				}			  
			})
		
	}
	
 
})(jQuery);

