//
// create closure
//
(function($) {
  //
  // plugin definition
  //
  $.fn.ajaxvalidator = function(arg1, arg2) {
    var cmd, options;    
    if(typeof(arg1) == 'undefined' && typeof(arg2) == 'undefined'){
      cmd = 'validate';
    } else if(typeof(arg2) == 'undefined'){
      cmd = 'validate';
      options = arg1;
    } else {
      cmd = arg1;
      options = arg2;
    }
   
    switch(cmd){
      case 'add':
        this.each(function(){     
          $(this).bind(options['event'] || 'blur', function(){
            $(this).ajaxvalidator(options);
          });    
        });
        break;
      case 'afterValidate':
        this.each(function(){    
          var element = $(this);
	        //$this.data('ajaxvalidator', options);
	        jQuery().bind('ajaxvalidator.aftervalidate', function(sender, data){
	          if(jQuery.inArray(options.attribute, data.attributes) >= 0 && options.model == data.model && options.index == data.index) {
	            if(data.errors) {
	              var errors=data.errors;
	              if(errors[options.model]){
	                errors=errors[options.model];
	                if(errors[options.index]){
	                  errors=errors[options.index];
	                  errors=errors[options.attribute];
	                }
	              }
	              	            
	              if(jQuery.isFunction(options.fn))
	                options.fn.call($this, { 'errors': errors || [ ] });
	              else 
	                element.ajaxvalidator('apply', { 'errors': errors || [ ] });	              	                
	            }
	          }	          
	        });
	      });
	      break;
	    case 'addAction':
	      $.fn.ajaxvalidator.actions[options.action] = options.url;
	      break;
	    case 'defaults':
	      $.fn.ajaxvalidator.defaults = $.extend({}, $.fn.ajaxvalidator.defaults, options);
	      break;
	    case 'apply':
	      if(options.errors.length)	      
	        this.each(function(){
	           $this = $(this);
	           var o = $.meta ? $.extend({}, $.fn.ajaxvalidator.defaults, $this.data('ajaxvalidator')) : $.fn.ajaxvalidator.defaults;
	           $this.html(options.errors[0]);	           
	           $this.removeClass(o.successcss);
	           $this.addClass(o.errorcss);
	        });
	      else
	        this.each(function(){
             $this = $(this);
             var o = $.meta ? $.extend({}, $.fn.ajaxvalidator.defaults, $this.data('ajaxvalidator')) : $.fn.ajaxvalidator.defaults;
             $this.html('&nbsp;');             
             $this.removeClass(o.errorcss);
             $this.addClass(o.successcss);
          });
	      break; 
      case 'validate':
      default:
        if($.fn.ajaxvalidator.actions[options.action]) {
          var postdata=jQuery(this).parents("form").serialize();
          var hash;
          var attributesArray= [ options.attribute ]; 
          
          if($.jCache && $.fn.ajaxvalidator.defaults.cache) {            
            hash=calcHash($.fn.ajaxvalidator.actions[options.action]+ postdata);
            if(data = $.jCache.getItem(hash)) {                                    
              jQuery().trigger('ajaxvalidator.aftervalidate', {'model': options.model, 'index':options.index, 'attributes':attributesArray, 'errors': data.errors});
              return;
            }            
          }
                              
	        jQuery.ajax({
	          'type':'POST',
	          'url':$.fn.ajaxvalidator.actions[options.action], 
	          'dataType':'json', 
	          'cache':true,
	          'data':postdata,
	          'success':function(data){	     
	            if(hash)
                $.jCache.setItem(hash, data);      
	            jQuery().trigger('ajaxvalidator.aftervalidate', {'model': options.model, 'index':options.index, 'attributes':attributesArray, 'errors': data.errors});                        
	          }  
	        });
	      }
        break;    
    }	 
  };
  
  //
  // private function for debugging
  //
  function debug($obj) {
	  if (window.console && window.console.log)
	    window.console.log('hilight selection count: ' + $obj.size());
  };
  

  function calcHash(str)
  {
    var hash = 2166136261;//offset_basis;
    var l = str.length, i;
    
    for(i=0; i < l; i++)
    {
      hash ^= str.charCodeAt(i);
      hash *= 16777619;//FNV_prime
    }
    
    return hash          
  }			

  
  $.fn.ajaxvalidator.actions = [ ];

  $.fn.ajaxvalidator.defaults = {    
	  errorcss: 'errorMessage',
	  successcss: 'successMessage',
	  cache: true
  };
//
// end of closure
//
})(jQuery);

