// JavaScript Document

(function($) {
 
   $.fn.validate = function(settings,gv_effects_addon) {

      //add trim to strings
		String.prototype.trim = function() {
			return this.replace(/^\s+|\s+$/g,"");
		}
		String.prototype.ltrim = function() {
			return this.replace(/^\s+/,"");
		}
		String.prototype.rtrim = function() {
			return this.replace(/\s+$/,"");
		}
    
	//the allowed validation types
	var allowed_type=new Array("empty","integer","digit","email","retype_email","float","password","retype_password","checked","radio","zip","url"),
	
	//this is the default configurations, this can be extended (validators firs parameter)
	default_config = {
            type:"drop_error[style=color:#F00;]|highlight_field"
		   ,configure: {"": { test:"", error:""}} 
		   ,default_errors: {"email": "Va rugam introduceti o adresa de e-mail valida (ex: myemail@site.com).",
		                     "empty": "Va rugam completati acest camp",
							 "integer": "Va rugam introduceti numai numere (ex: 123)",
							 "digit": "Va rugam introduceti numai numere (ex: 0..9)",
							 "float":  "Va rugam introduceti numai numere (ex: 1.23)",
							 "checked": "Va rugam sa alegeti unu sau mai multe optiuni",
							 "radio" : "Va rugam sa alegeti o optiune.",
							 "zip" : "Va rugam sa introduceti un cod postal existent (ex: 901238).",
							 "url" : "Va rugam sa introduceti a adresa de web corecta (ex: http://www.site.com).",
							 "password" : "Va rugam sa introduceti a parola corecta (min 5 caractere).",
							 "retype_password" : "Campurile Parola si Confirma parola nu sunt identice!"} 
		   ,errors: "single"    //stack = all errors, single= stops at first error
		  , custom_error:""    //a custom function, created by the user
		  , trigger: { node: $(this), event: "click", callback:function(e){return true;}}
		  ,stop_submit:0
		},
		
	  stored_errors=new Array(),	
	  kill_validation=0	
	 ,validation_result,	
	  obj=$(this), 
	  
	  /* this object containes all validation methods */
	  validators={
	
					//checks wheter a number is interger
					isInteger:function(s)
				   {
					  var i,c;
				
					  if (this.isEmpty(s)) return false;

					  for (i = 0; i < s.length; i++)
					  {
						   c = s.charAt(i);
				
						 if (!this.isDigit(c)) return false;
					  }
				
					  return true;
				   },
				   
					/*  checks wheter a given value is empty */   
					 isEmpty:function(s)
					   { 
						  return ((s == null) || (s == "") || (s.length == 0))
					   }
					 ,
					 /*  checks wheter a given value is a digit */    
					isDigit:function (c)
					   {
						   if(this.isEmpty(c)) return false; 
						   
						  return ((c >= "0") && (c <= "9"))
					   }
					,
					 /*  checks wheter a given value is an email */     
					isEmail:function (c)
					   {  
					     if(this.isEmpty(c) ) return false; 
						 
							/*var objRegExp  = /(^[a-z0-9]([a-z0-9_\.-]*)@([a-z0-9_\.-]*)([.][a-z0-9]{3})$)|(^[a-z0-9]([a-z0-9_\.-]*)@([a-z0-9_\.-]*)(\.[a-z0-9]{2})(\.[a-z0-9]{3})*$)/i;
						
						if(objRegExp.test(c)) return true;
						    return false;*/ 
							if(c.indexOf("@")==-1) return false; 
							
							return true;
									 
					   },
					   
					 //checks wheter an input  is valid zip (USA)  
					 isZip : function (z)
					   {
						   if(this.isEmpty(z)) return false; 
						   
						   if(/(^\d{5}$)|(^\d{5}-\d{4}$)/i.test(z)) return true;
						    
							return false;
						   },
					
					 //chechks if a radio or checkbox field is checked
					 isChecked : function (z)
					   {
						  
						   
						   if(z.attr("checked")==true) return true;
						    
							return false;
						   },
					  
					  // checks if a password/retyped is valid and equal
					  checkPassword : function (z)
					   {   
					      var pass=new Array();
						  
					      obj.find("input:password").each(function(){
																  pass[pass.length]=$(this);
																  }); 
						   if(this.isEmpty(z)) return false; 
						   
						   if(z.attr("value").length<5) return false;
						   
						   if(z.attr("id")==pass[0].attr("id")) return true; 
							
						   if(z.attr("id")==pass[1].attr("id") && pass[0].attr("value")==pass[1].attr("value")) return true; 
						    
							return false;
						   }
						 ,
						 isUrl: function(u)
						  {
							  
							   if(this.isEmpty(u)) return false; 
							   
							  var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
                                 
								 if(regexp.test(u)) return true; 
								 
								 return false; 
								 
							  }
   };
   
     /* the garbage effect collectr */
     this.destroy_effect={"error_box" : function(){
	               $("#gv_error_box").remove();
	   }};
   
   
     /* this object containes all error effects that are applicable.
	    It is extandable. (the second parameter of the validator)
	*/	
    this.error_effects={
	           
			   
			   /* This effect creates a red error box above the container */
	           "error_box" : function (stored_errors,extra)
			          {     
							var style_class="";
							var style="";
						    var errors=""
							var error_wrapper="div";
							var errror_separator="br";

							
							$("#gv_error_box").remove();
							

							if(extra['wrapper']!=null) error_wrapper=extra['wrapper'];
							if(extra['separator']!=null) errror_separator=extra['separator'];
							if(extra['style']!=null) style=extra['style'];
							else    style="display:none;color:#F00; border-color=#F00;";
							   
							if(extra['class']!=null) { style_class=extra['class']; style="";}
							
						    if(extra['box']!=null)  box=$("#"+extra['box']);
							
							  else var box=$("<"+error_wrapper+" style='"+style+"' class='"+style_class+"' id='gv_error_box'></"+error_wrapper+">").insertBefore(obj);
							  
							 for(var i=0;i<=stored_errors.length-1;i++){
								 errors+=stored_errors[i].error+"<"+errror_separator+">";
											}
											
							  box.html(errors);				
							  box.show();
							 
							  validator.destroy_effect['error_box']=function($field) { $("#gv_error_box").remove();  }
						  }
	            , 
					
					/* this validation method, attaches an error div under each field that containes an error.
					    The error dissapears when a key is pressed on the field.
				    */	
			   "drop_error": function(stored_errors,extra) 
			         {
						  var max_width=10; 

						  var style="";
						  var style_class="";
					  
						  if(extra['class']==null){
							  if(extra['style']!=null) style=extra['style'];
						      else   style="color:#F00;border-color:#F00;border:solid; border-width:1px;";
						  }
						  else	     style_class=extra['class'];
							
						  for(var i=0;i<=stored_errors.length-1;i++){  
						   if($("#"+stored_errors[i].victim.attr("id")+"_err").attr("id")==null){
										
											   var el_width=parseInt(stored_errors[i].victim.css("padding-right"))+parseInt(stored_errors[i].victim.css("padding-left"))+parseInt(stored_errors[i].victim.css("width"));                                      
											   if(el_width>max_width) max_width=el_width;
											   
											   if(el_width<20) el_width=max_width;
											   
											   if(el_width<20) el_width=200;
											   
											   $("<div style='display:none;"+style+" width:"+el_width+"px' class='"+style_class+"' id='"+stored_errors[i].victim.attr("id")+"_err'>"+stored_errors[i].error+"</div>")
												 .insertAfter(stored_errors[i].victim)
												 .show("slow");
						   }
						 }
						 
						    validator.destroy_effect['drop_error']=function($field) { $("#"+$field.attr("id")+"_err").remove();  }
					 }
			   ,
			   
			   /* this function removes all added effects on a specific event.
			      After the effect is created, you assign a destroyer function to the destroy_effect object.
			   */
			   "remove_effects": function(stored_errors)
			     {   
					  for(var i=0;i<=stored_errors.length-1;i++){
						   
						              switch( stored_errors[i].victim.attr("nodeName"))
												 {   
												     case "INPUT" :  if(stored_errors[i].victim.attr("type")=="checkbox") var event_name="click";
													                  else if(stored_errors[i].victim.attr("type")=="radio") var event_name="click";
																	  else var event_name="keypress";
																	  break;
													case "SELECT" :   var event_name="click";
																	  break;				  
													 default: var event_name='keypress'; break;

													 } 

					  stored_errors[i].victim.bind(event_name,function(e) {
								
								    var types=settings.type.split("|"); 
                                      
									  for(var i=0;i<=types.length-1;i++){
									   
									   var opt=types[i].split("[");
										   types[i]=opt[0]; 

										   if(typeof validator.destroy_effect[types[i].trim()]=="function"){ 
										      validator.destroy_effect[types[i].trim()]($(this));
										   }
										    
											//if it's in a group, apply to all
										      if(getValidationGroup($(this))!="") {
												    
													  var allg=getGrouped($(this))
													  
													     for(var j=0;j<=allg.length-1;j++)
														  {
															   validator.destroy_effect[types[i].trim()](allg[j]);
															  }
												  }
											}
											
								   });
									
					           }
					 },
			   
			   /* this effect, ads a color to the field border */
	           "highlight_field": function(stored_errors,extra) {
				   
				     var border_color="#F00";

					 if(extra['border-color']!=null) border_color=extra['border-color'];
							 
				   for(var i=0;i<=stored_errors.length-1;i++){
 						  
						  if(extra['class']==null)
					             stored_errors[i].victim.css({"border-color":border_color,
												    "border-width":"1px"});
						  else 	stored_errors[i].victim.addClass(extra['class']);
											  
										//stored_errors[i].victim.focus();
											  
				            }
							
							validator.destroy_effect['highlight_field']=function($victim) { $victim.css({"border-color":"#000000","border-width":"1px"}) };
				   },
				
				/* this validation method is the most basic possible. It shows all errors in a 
                        default alert window
				    */
			   "alert": function(stored_errors,extra){
				                           var errors=""
	                                        for(var i=0;i<=stored_errors.length-1;i++){
												 errors+=stored_errors[i].error+"\n";
											}
											alert(errors);
				   },
			
			/* this effect, attaches a finger that is pointing at the victim field.
			   The finger is moving  left to right, continuously 
			*/
			   "finger": function (stored_errors,extra) {
				   
			   }
			   }
	    
               var validator=this; //global referece (in $(this) namespace)
   

                var   settings=$.extend(default_config, settings);  // extend the genral setting
                
				// extends the effects through an addon
				if(gv_effects_addon!=null)
				  error_effects=$.extend(error_effects, gv_effects_addon );
			  
			  //stop on submit_event
               if(obj.attr("nodeName")=="FORM")   var obj_form=obj;
			   else  if($(this).parent("form").attr("nodeName")=="FORM")   var obj_form=$(this).parent("form");
			   else  var obj_form=null;
			  
			  //if there is a form that wrapps the container
			  //disable it's submit event
			  if(obj_form!=null)
			     obj_form.bind("submit",function(){  return false; })  
			  
			  //create the trigger object
			  if(typeof(settings.trigger.node)=="string") {
				  if(settings.trigger.node.trim().substr(0,1)!="#" && settings.trigger.node.trim().substr(0,1)!=".")
				     var type_operator="#";
				  else 
				    var type_operator="";
					
				  settings.trigger.node=$(type_operator+settings.trigger.node);
			  }
			  

              //based on the node type , select a validator and  a trigger
			  //and attaches the selected event, in settings.trigger.event
				switch(obj.attr("nodeName"))
                    {
						case "INPUT" : 
						               settings.trigger.node.bind(settings.trigger.event, function(e){ 
										kill_validation=0;														   
									   if(!fieldValidator(obj))
									   { 
										  handleError(obj);

										  }
																				  
										  if(kill_validation==0)
										    showError();
											
										}); 
										break;
						case "TEXTAREA" :
						              settings.trigger.node.bind(settings.trigger.event, function(e){
										kill_validation=0;														  
									   if(!fieldValidator(obj))
									   {
										  handleError(obj);

										  }
										  									
									   if(kill_validation==0)
										   showError();
										});  break;
						case "FORM" :     	
						             
									//rewrite the default trigger
									if(settings.trigger.node.attr("id")==obj.attr("id"))
									  {
										    settings.trigger.node=obj.find("input:[type=submit],input:[type=image],input:[type=button],button");
											
											settings.trigger.node.each(function(){
																				found_trigger=$(this);
																				})
											settings.trigger.node=found_trigger;
										  }
					
						              settings.trigger.node.bind(settings.trigger.event,function (e){  
															kill_validation=0;
															formValidator();
															
															 if(kill_validation==0)
										                         showError();
															});  break;
						default: return false; 
						}
	

   
   function error_show(stored_errors){
	   
		                     var types=settings.type.split("|"); 
                                 for(var i=0;i<=types.length-1;i++){
									  var opt=types[i].split("[");
										  types[i]=opt[0]; 
										  if(opt[1]!=null)
										     opt=opt[1].replace("]","");
										  else opt=null;
										  
									  if(typeof validator.error_effects[types[i]]=="function")
                                           validator.error_effects[types[i]](stored_errors,objectize(opt));
							 }
								 validator.error_effects['remove_effects'](stored_errors);	
	                        }				   
				       
	function objectize(wannabe)
	{  
	    if(wannabe==null) return new Object();
	
		wannabe=wannabe.split(",");
		
		var the_object=new Object();
		
		for(var i=0;i<=wannabe.length-1;i++)
		 {    
		     var chunks=wannabe[i].split("=");
			 
			   the_object[chunks[0]]=chunks[1];
			 }
		
		return the_object;
		}
     
	//this metod executes the submit operation, unbinds other events attached to submit
	this.submitForm=function()
	{
		              obj_form.unbind();
				      obj_form.bind("submit",function(){ return true; });
					  obj_form.submit();
		}
	 
    function showError()
    {    
	   //if there is no errors. trigger callback
	    if(stored_errors.length==0) 
		 {        
		        if( settings.trigger.callback!=null && typeof settings.trigger.callback=="function")
			       {
					   if(!settings.trigger.callback(validator)) settings.stop_submit=1;
							  		                            else settings.stop_submit=0;										    
				   }
				   
				kill_validation=1;
				

                if(settings.stop_submit!=null && settings.stop_submit==0 || settings.stop_submit==false )
				  {    
				     validator.submitForm();
				  };
				  
				  return;
			 }
	  
	   // verify that all  fields have errors attached, if not, put default error 
		for(var i=0;i<=stored_errors.length-1;i++){ 
					 if(stored_errors[i].error=="")  stored_errors[i].error=settings.default_errors[getValidationType(stored_errors[i].victim)];
									}
						
					    if(settings.custom_error!=""){
						   settings.custom_error(stored_errors);
						}

						else   error_show(stored_errors);

		       		
						
		   kill_validation=1;
		
		    stored_errors=new Array();
			
		
		}

		 
	function handleError(field)
	 {  
		     var the_text=getErrorText(field);
			 
			     if(settings.errors=="single")  { 
				      stored_errors[stored_errors.length]={ victim: field, error:the_text};
					  showError();
				 }
				
				if(settings.errors=="stack")  stored_errors[stored_errors.length]={ victim: field, error:the_text}; 
		 }
		 
		 
	function formValidator()
	{
       	obj.find("*").each(function(index){
                             
							   if(kill_validation==1) return;
							   
							    if($(this).attr("name")==null) return;
								
							     if(!fieldValidator($(this)))
								  {
									  handleError($(this));
									  }
						  });
		
				
		}
	 
	 function validate(validation_type,field)
	{
		  var allowempty=getAllowEmpty(field); 
		       
			  if(allowempty && field.val().trim()=="") return true; 
		
		switch(validation_type.trim())
				  {
					     case "empty" : return !validators.isEmpty(field.val().trim()); break;
						 case "integer" : return validators.isInteger(field.val().trim()); break;
						 case "digit" : return validators.isDigit(field.val().trim()); break;
						 case "url" : return validators.isUrl(field.val().trim()); break;
						 case "checked" : return validators.isChecked(field); break;
						 case "email" : return validators.isEmail(field.val().trim()); break;
						 case "retype_email" : return validators.isEmail(field.val()); break;
						 case "zip" : return validators.isZip(field.val().trim()); break;
						 case "checked" : return validators.isChecked(field.val().trim()); break;
						 case "password" : return validators.checkPassword(field); break;
						 case "retype_password" : return validators.checkPassword(field); break;
						 default: return true;
					  }
		}
	
    function fieldValidator(field)
	{ 
	      var validation_type=getValidationType(field);
		
		  
		  if(!isValidValidationType(validation_type)) { return true;}
		  
		  if(getValidationGroup(field)=="") {
				return validate(validation_type,field);
		  }
		  else
		  {
			    var grouped_fields=getGrouped(field);
                var flags=0;
				  
				    for(var i=0;i<=grouped_fields.length-1;i++)
					  {      
					         validation_type=getValidationType(grouped_fields[i]);
							
						     if(validate(validation_type,grouped_fields[i])) flags++;
						  }
					
					if(flags>=1) return true;
					
					return false;
			  }
		}
	
  function getValidationType($field)
    {  
		    if($field.attr("validate:type")!=null) return $field.attr("validate:type") ;
				
			if($field.attr("id")!=null && settings.configure[$field.attr("id")]!=null && settings.configure[$field.attr("id")].test!=null)  return settings.configure[$field.attr("id")].test; 
			
			return "";
		}

function getAllowEmpty($field)
    { 
		    if($field.attr("validate:allowempty")!=null) return $field.attr("validate:allowempty") ;
				
			if($field.attr("id")!=null && settings.configure[$field.attr("id")]!=null && settings.configure[$field.attr("id")].test!=null)  return settings.configure[$field.attr("id")].allowempty; 
			
			return "";
		}
	
	  function getValidationGroup($field)
    {  
		    if($field.attr("validate:group")!=null) return $field.attr("validate:group") ;
				
			if($field.attr("id")!=null && settings.configure[$field.attr("id")]!=null && settings.configure[$field.attr("id")].group!=null)  return settings.configure[$field.attr("id")].group; 
			
			return "";
		}
	
	function getGrouped(field)
    {  
	    var group=getValidationGroup(field);
		var stack=new Array();
		
		    if(field.attr("validate:group")!=null) 
			  {  
				  obj.find("*").each(function(index){
											    if($(this).attr("validate:group")!=null && $(this).attr("validate:group")==group )
												  {
													  stack[stack.length]=$(this);
													  }
											  });
				  }
		     else if($field.attr("id")!=null && settings.configure[$field.attr("id")]!=null && settings.configure[$field.attr("id")].group!=null)  
			 {
				  obj.find("*").each(function(index){
            
			if($(this).attr("id")!=null && settings.configure[$(this).attr("id")]!=null && settings.configure[$(this).attr("id")].group!=null &&  settings.configure[$(this).attr("id")].group==group)  
												  {
													  stack[stack.length]=$(this);
													  }
											  });
				 }
			
			return  stack;
		}
	
    function getErrorText($field)
    { 
		    if($field.attr("validate:error")!=null)
			  { 
          	      return $field.attr("validate:error") ;
			  }
			  
			if($field.attr("id")!=null && settings.configure[$field.attr("id")]!=null && settings.configure[$field.attr("id")].error!=null)  return settings.configure[$field.attr("id")].error;
			
			return "";
		}
		
   function isValidValidationType(validation_type)
   {
	   
	   for(var i=0;i<=allowed_type.length-1;i++)
	          if(allowed_type[i]==validation_type)    return true;
			  
			  return false;
	   }
	    
 
		 return this;
 
   };
 
 })(jQuery);
