// FIELD VALIDATOR JQUERY PLUGIN

(function($) {
	$.fn.fieldValidator = function(options){
		var me = this;
		$('.fv-bubble-close').live('click', function(e){$(e.target).closest('.fv-bubble').fadeOut('slow').remove();});
		
		if($.isArray(options)){
			for(var i=0, l=options.length; i<l; i++){
				$.fv.addRule(me, options[i]);
			}
		}else{
			$.fv.addRule(me, options);
		}
	};
	
	$.fv = {
		unMarkFields:function(f,o){
			var s = f.selector+((o.compareWith) ? ',#'+o.compareWith : '')+((o.group) ? ',#'+o.group.join(',#') : '');
			$(s).removeClass('fv-'+o.rule);
			$('.'+f.attr('id')+'-'+o.rule+'-fv-invalid-icon').remove();
		},
		
		markFields:function(f,o){
			var s = f.selector+((o.compareWith) ? ',#'+o.compareWith : '')+((o.group) ? ',#'+o.group.join(',#') : '');
			$(s).addClass('fv-'+o.rule);
			$(s).each(function(i,e){
									if((typeof o.showIcon == 'undefined' ||  o.showIcon==true) && !$(e).next('SPAN').hasClass('fv-invalid-icon')){
										$(e).after('<SPAN class="fv-invalid-icon '+f.attr('id')+'-'+o.rule+'-fv-invalid-icon'+'" />');
									}						
								});
		},
		
		removeBubble:function(f,o){
			$(f.selector+'-fv-bubble .fv-mssg-'+o.rule).remove();
			if($(f.selector+'-fv-bubble .fv-mssg').length == 0)
				$(f.selector+'-fv-bubble').fadeOut('slow').remove();
		},
		               
		insertBubble:function(f,o){
			var xOffset = -10,
					fOffset = f.offset(),
					id 			= f.attr('id')+'-fv-bubble',
					w 			= $(document).width();
			
			if(o.message && o.message.length > 0){
				if($('#'+id).length > 0){
					if($('#'+id+' .fv-mssg-'+o.rule).length == 0)
						$('#'+id).append('<div class="fv-mssg fv-mssg-'+o.rule+'">'+o.message+'</div>');
				}else{
					$('body').append( '<div id="'+id+'" class="fv-bubble"><div class="fv-bubble-close" /><div class="fv-mssg fv-mssg-'+o.rule+'">'+o.message+'</div><div class="fv-bubble-arrow-bottom" /></div>' );
				}		
				
				$('#'+id).css("left", (fOffset.left+xOffset)+"px").fadeIn("slow");
				
				var e				= $('#'+id),
						eOffset = e.offset(),
						l 			= e.children('div:last'),
						ah			= l.outerHeight(), 
						bh			= e.outerHeight(); // ah (arrow-height) bh (bubble-height)
				
				if(fOffset.top - (bh+ah) > 0){
			  	e.css("top", (fOffset.top-(bh+ah))+"px");
			  }else{
			  	l.removeClass('fv-bubble-arrow-bottom').addClass('fv-bubble-arrow-top');
			  	e.css("top", (fOffset.top+$(f).outerHeight()+ah)+"px");
			  }
			  
			  if(eOffset.left+e.outerWidth() > w){
			  	var nL = (w-e.outerWidth());
			  	e.css("left", nL+"px");
			  	l.css('left', (fOffset.left-nL-5)+"px");
			  }
			}
		},
					
		addRule:function(f, o){
			var s = f.selector+((o.compareWith) ? ',#'+o.compareWith : '')+((o.group) ? ',#'+o.group.join(',#') : ''),
					fHandle	 = function(e){
												if( !$.fv.validate(f, o) ){
													if(e.target.tagName != 'FORM')
														e.stopImmediatePropagation(); 
													$.fv.markFields(f,o);
													$.fv.insertBubble(f,o);
													return false;
												}else{
													$.fv.unMarkFields(f,o);
													$.fv.removeBubble(f,o);
												}
										 };
			
			if(o.validateOn){
				$(s).bind( (($.isArray(o.validateOn)) ? o.validateOn.join(' ') : o.validateOn), fHandle );
			}
			
			// Validate on submit
			if(f.attr('form')){
				$(f.attr('form')).bind('submit', fHandle);
			}
		},
		
		validate:function(f, o){
			if(o.rule){
				var rule = o.rule.toLowerCase(),
						result = false;
				
				if($.isFunction($.fv[rule])){
					result = $.fv[rule](f, o);
				}
				
			}
			return result;
		},
		
		required:function(f){ 
			return /\S/.test(f.val());
		},
		
		rangelength:function(f,o){
			var l = f.val().length;
			return ((o.minValue == null || l >= o.minValue) && (o.maxValue == null || l <= o.maxValue));
		},
		
		rangevalues:function(f,o){
			var v = f.val();
			return ((o.minValue == null || v >= o.minValue) && (o.maxValue == null || v <= o.maxValue));
		},
		
		numeric:function(f,o){
			var v = f.val(),
					r = /^(\-?(\d+\.?\d+)|(-?\d+))?$/.test(v);
			
			if(r && o.positive){
				r = (Math.abs(v) == v);
			}
			
			if(r && o.integer){
				r = (parseInt(v) == v);
			}
			
			return r;
		},
		
		lettersonly:function(f){
			return /^[a-zA-Z\s]*$/.test(f.val());
		},
		
		zipcode:function(f){
			return /^(\d{5})?$/.test(f.val());
		},
		
		email:function(f){
			return /^(\S+@\S+(\.\S+)*\.(\S{2,4}))?$/i.test(f.val()) && !/[\(\)\<\>\,\;\:\\\"\[\]]/.test(f.val());
		},
		
		ischecked:function(f,o){
			var operator = (o.operator && o.operator.toLowerCase() == 'some') ? false : true;
			if(!operator && f.attr('checked')){
				return true
			}else if(operator && !f.attr('checked')){
				return false;
			}
			
			if(o.group && $.isArray(o.group)){
				for(var i=0, l=o.group.length; i < l; i++){
					if(!operator && $('#'+o.group[i]+':checked').length){
						return true
					}else if(operator && !$('#'+o.group[i]+':checked').length){
						return false;
					}
				}
			}
			
			return operator;
		},
		
		compare:function(f,o){
			return (o.compareWith && $('#'+o.compareWith).length > 0) ? f.val() == $('#'+o.compareWith).val() : true; 
		},
		
		expression:function(f,o){
			return o.expression.test(f.val());
		},
		
		creditcard:function(f){
			var s = f.val();
			
			s = s.replace(/\D/g, "");
			
			var nl=s.length,
	  			p=nl % 2,
	  			t=0;
	
		  for (i=0; i < nl; i++) {
		    var d=s.charAt(i);
		    if (i % 2 == p) {
		      d=d * 2;
		      if (d > 9) {
		        d=d - 9;
		      }
		    }
		    t = t + parseInt(d);
		  }
	
		  if (t % 10 != 0) {
		    return false;
		  }
		  
		  return true;
		}
	};
	
})(jQuery);
