/*
 * CakePHP jQuery Validation Plugin
 * Copyright (c) 2009 Matt Curry
 * www.PseudoCoder.com
 * http://github.com/mcurry/cakephp_plugin_validation
 * http://sandbox2.pseudocoder.com/demo/validation
 *
 * @author      mattc <matt@pseudocoder.com>
 * @license     MIT
 *
 * @modified DKW - Changed name to validates() instead of validate() to prevent conflict with default jquery plugin
 *  				added patch where same form fields conflicted with different forms
 */

(function($) {
  var options = null;
  $.fn.validates = function(rules, opts) {
  
    // ADDED DKW - form specific rules
    form = this.selector;
  
    options = $.extend({}, $.fn.validates.defaults, opts);
		
		$.each(opts.watch, function(fieldId) {
			$(form + " #" + opts.watch[fieldId]).change(function() {
				$.fn.validates.ajaxField($(this));
			});
		});

    return this.each(function() {
      $this = $(this);
      $this.submit(function() {
        var errors = [];
        
        $.fn.validates.beforeFilter();
      	
      	// ADDED DKW - also all '#' + field modified with form + in front
    	form = "#" + $(this).closest("form").attr("id");
    
        $.each(rules, function(field) {
          var val = $(form + " #" + field).val();
          var fieldName = $(form + '#' + field).attr('name');
          if(typeof val == "string") {
            val = $.trim(val);
          }
          
          $.each(this, function() {
            //field doesn't exist...skip
            if ($(form + " #" + field).attr("id") == undefined) {
              return true;
            }

            if (this['allowEmpty'] && typeof val == "string" && val == '') {
              return true;
            }

            if (this['allowEmpty'] && typeof val == "object" && val == null) {
              return true;
            }
            
            if (!$.fn.validates.validateRule(val, this['rule'], this['negate'], fieldName)) {
              errors.push(this['message']);
              $.fn.validates.setError(field, this['message']);
              
              if (this['last'] === true) {
                return false;
              }  
            }
          });
        });
      
        $.fn.validates.afterFilter(errors);

        if(errors.length > 0) {
          return false;
        }
        
        return true;
      });
    });
  };
  
  $.fn.validates.validateRule = function(val, rule, negate, fieldName) {
    if(negate == undefined) {
      negate = false;
    }
        
    //handle custom functions
    if(typeof rule == 'object') {
      if($.fn.validates[rule.rule] != undefined) {
        return $.fn.validates[rule.rule](val, rule.params, fieldName);
      } else {
        return true;
      }
    }

    //handle regex rules
    if (negate && val.match(eval(rule))) {
      return false;
    } else if (!negate && !val.match(eval(rule))) {
      return false;
    }
    
    return true;
  };
  
  $.fn.validates.boolean = function(val) {
    return $.fn.validates.inList(val, [0, 1, '0', '1', true, false]);
  };
    
  $.fn.validates.comparison = function(val, params) {
    if(val == "") {
      return false;
    }
    
    val = Number(val);
    if(val == "NaN") {
      return false;
    }
    
    if(eval(val + params[0] + params[1])) {
      return true;
    }
    
    return false;
  };
  
  $.fn.validates.inList = function(val, params) {
    if(params != null) {
      if($.inArray(val, params) == -1) {
        return false;
      }
    }
    
    return true;
  };
  
  $.fn.validates.range = function(val, params) {
    if (val < parseInt(params[0])) {
      return false;
    }
    if (val > parseInt(params[1])) {
      return false;
    }
    
    return true;
  };
  
  $.fn.validates.multiple = function(val, params) {
    if(typeof val != "object" || val == null) {
      return false;
    }
    
    if(params.min != null && val.length < params.min) {
      return false;
    }
    if(params.max != null && val.length > params.max) {
      return false;
    }
    
    if(params["in"] != null) {
      for(i = 0; i < params["in"].length; i ++) {
        if($.inArray(params["in"][i], val) == -1) {
          return false;
        }
      }
    }
    
    return true;
  };
	
	$.fn.validates.ajaxField = function($field) {
		$.fn.validates.clearError($field);
		$.fn.validates.ajaxBeforeFilter($field);

		var data = new Object;
		data[$field.attr("name")] = $field.val();
		$.post(options.root + "js_validate/field/" + $field.attr("id"), data,
			function(validates) {
				$.fn.validates.ajaxAfterFilter($(form + " #" + validates.field));
				if(!validates.result) {
					$.fn.validates.setError(validates.field, validates.message);
				}
			},
			"json");
	}
	
	$.fn.validates.ajaxBeforeFilter = function($field) {
		$field.after("<img class=\"ajax-loader\" src=\"" + options.root + "js_validate/img/ajax-loader.gif\">");
	}

	$.fn.validates.ajaxAfterFilter = function($field) {
		$field.siblings(".ajax-loader").remove();
	}
	
	$.fn.validates.clearError = function($field) {
		if(typeof $field == "string") {
			$field = $(form + " #" + field);
		}
		
		$field.removeClass("form-error")
					.parents("div:first").removeClass("error")
					.children(".error-message").remove();		
	}
  
  $.fn.validates.setError = function(field, message) {
    $(form + " #" + field).addClass("form-error")
                  .parents("div:first").addClass("error")
                  .append('<div class="error-message">'  + message +  '</div>');
  };
	
  $.fn.validates.beforeFilter = function() {
    if(options.messageId != null) {
      $(form + " #" + options.messageId).html("")
                                .slideDown();
    }
    
    $(".error-message").remove();
    $("input").removeClass("form-error");
    $("div").removeClass("error")
  };  

  $.fn.validates.afterFilter = function(errors) {
    if(options.messageId != null) {
      $(form + " #" + options.messageId).html(errors.join("<br />"))
                                .slideDown();
    }
  };
})(jQuery);
