/**
 * @author alexander.farkas
 * @version 1.4.1
 */
(function($){
 var baseClasses = /ui-checkbox|ui-radio/;
    $.widget('ui.checkBox', {
  options: {
         hideInput: true,
   addVisualElement: true,
   addLabel: false,
   _delegated: false
     },
        _create: function(){
            var that = this, 
    opts = this.options
   ;
   
   if(!this.element.is(':radio,:checkbox')){
    if($.nodeName(this.element[0], 'input')){return false;}
    this._addDelegate();
    this.updateContainer();
    return false;
   }
            this.labels = $([]);
   
            this.checkedStatus = false;
   this.disabledStatus = false;
   this.hoverStatus = false;
            
            this.radio = (this.element.is(':radio'));
     
            this.visualElement = $([]);
            if (opts.hideInput) {
    this.element
     .addClass('ui-helper-hidden-accessible')
    ;
    if(opts.addVisualElement){
     this.visualElement = $('<span />')
      .addClass(this.radio ? 'ui-radio' : 'ui-checkbox')
      .css({
       'margin-top' : this.element.css('margin-top'),
       'margin-right' : this.element.css('margin-right'),
       'margin-bottom' : this.element.css('margin-bottom'),
       'margin-left' : this.element.css('margin-left')
      });
     this.element.after(this.visualElement[0]);
    }
            }
   
   if(opts.addLabel){
    this.labels = $('label[for=' + this.element.attr('id') + ']')
     .addClass(this.radio ? 'ui-radio' : 'ui-checkbox');
   }
   if(!opts._delegated){
    this._addEvents();
   }
   this.initialized = true;
            this.reflectUI({type: 'initialReflect'});
   return undefined;
        },
  updateContainer: function(){
   if(!this.element.is(':radio,:checkbox') && !$.nodeName(this.element[0], 'input')){
    $('input', this.element[0])
     .filter(function(){
      return !($.data(this, 'checkBox'));
     })
     .checkBox($.extend({}, this.options, {_delegated: true}))
    ;
   }
  },
  _addDelegate: function(){
   var opts   = this.options,
     
    toggleHover = function(e, that){
     if(!that){return;}
     that.hover = !!(e.type == 'focus' || e.type == 'mouseenter' || e.type == 'focusin' || e.type == 'mouseover');
     that._changeStateClassChain.call(that);
     return undefined;
    }
   ;
   
   
   this.element
    .bind('click', function(e){
     if(!$.nodeName(e.target, 'input')){return;}
     var inst = ($.data(e.target) || {}).checkBox;
     if(!inst){return;}
     inst.reflectUI.call(inst, e.target, e);
    })
    .bind('focusin.checkBox focusout.checkBox', function(e){
     if(!$.nodeName(e.target, 'input')){return;}
     var inst = ($.data(e.target) || {}).checkBox;
     toggleHover(e, inst);
    })
   ;
   
   if (opts.hideInput){
    this.element
     .bind('usermode', function(e){
      if(!e.enabled){return;}
      $('input', this).each(function(){
                      var inst = ($.data(this) || {}).checkBox;
       (inst && inst.destroy.call(inst, true));
      });
                 })
    ;
            }
   
   if(opts.addVisualElement){
    this.element
     .bind('mouseover.checkBox mouseout.checkBox', function(e){
      if(!$.nodeName(e.target, 'span')){return;}
      var inst = ( $.data($(e.target).prev()[0]) || {} ).checkBox;
      toggleHover(e, inst);
     })
     .bind('click.checkBox', function(e){
      if(!$.nodeName(e.target, 'span') || !baseClasses.test( e.target.className || '' )){return;}
      $(e.target).prev()[0].click();
      return false;
     })
    ;
   }
   if(opts.addLabel){
    this.element
     .delegate('label.ui-radio, label.ui-checkbox', 'mouseenter.checkBox mouseleave.checkBox', function(e){
      var inst = ( $.data(document.getElementById( $(this).attr('for') )) || {} ).checkBox;
      toggleHover( e, inst );
     });
   }
   
  },
  _addEvents: function(){
   var that   = this, 
   
    opts   = this.options,
     
    toggleHover = function(e){
     if(that.disabledStatus){
      return false;
     }
     that.hover = (e.type == 'focus' || e.type == 'mouseenter');
     that._changeStateClassChain();
     return undefined;
    }
   ;
   
   this.element
    .bind('click.checkBox', $.proxy(this, 'reflectUI'))
    .bind('focus.checkBox blur.checkBox', toggleHover)
   ;
   if (opts.hideInput){
    this.element
     .bind('usermode', function(e){
                     (e.enabled &&
                         that.destroy.call(that, true));
                 })
    ;
            }
   if(opts.addVisualElement){
     this.visualElement
      .bind('mouseenter.checkBox mouseleave.checkBox', toggleHover)
      .bind('click.checkBox', function(e){
       that.element[0].click();
       return false;
      })
     ;
    }
   if(opts.addLabel){
    this.labels.bind('mouseenter.checkBox mouseleave.checkBox', toggleHover);
   }
  },
  _changeStateClassChain: function(){
   var allElements = this.labels.add(this.visualElement),
    stateClass  = '',
    baseClass  = 'ui-'+((this.radio) ? 'radio' : 'checkbox')
   ;
    
   if(this.checkedStatus){
    stateClass += '-checked'; 
    allElements.addClass(baseClass+'-checked');
   } else {
    allElements.removeClass(baseClass+'-checked');
   }
   
   if(this.disabledStatus){
    stateClass += '-disabled'; 
    allElements.addClass(baseClass+'-disabled');
   } else {
    allElements.removeClass(baseClass+'-disabled');
   }
   if(this.hover){
    stateClass += '-hover'; 
    allElements.addClass(baseClass+'-hover');
   } else {
    allElements.removeClass(baseClass+'-hover');
   }
   
   baseClass += '-state';
   if(stateClass){
    stateClass = baseClass + stateClass;
   }
   
   function switchStateClass(){
    var classes = this.className.split(' '),
     found = false;
    $.each(classes, function(i, classN){
     if(classN.indexOf(baseClass) === 0){
      found = true;
      classes[i] = stateClass;
      return false;
     }
     return undefined;
    });
    if(!found){
     classes.push(stateClass);
    }
    this.className = classes.join(' ');
   }
   
   this.labels.each(switchStateClass);
   this.visualElement.each(switchStateClass);
  },
        destroy: function(onlyCss){
            this.element.removeClass('ui-helper-hidden-accessible');
   this.visualElement.addClass('ui-helper-hidden');
            if (!onlyCss) {
                var o = this.options;
                this.element.unbind('.checkBox');
    this.visualElement.remove();
                this.labels
     .unbind('.checkBox')
     .removeClass('ui-state-hover ui-state-checked ui-state-disabled')
    ;
            }
        },
  
        disable: function(){
            this.element[0].disabled = true;
            this.reflectUI({type: 'manuallyDisabled'});
        },
  
        enable: function(){
            this.element[0].disabled = false;
            this.reflectUI({type: 'manuallyenabled'});
        },
  
        toggle: function(e){
            this.changeCheckStatus((this.element.is(':checked')) ? false : true, e);
        },
  
        changeCheckStatus: function(status, e){
            if(e && e.type == 'click' && this.element[0].disabled){
    return false;
   }
   this.element.attr({'checked': status});
            this.reflectUI(e || {
                type: 'changeCheckStatus'
            });
   return undefined;
        },
  
        propagate: function(n, e, _noGroupReflect){
   if(!e || e.type != 'initialReflect'){
    if (this.radio && !_noGroupReflect) {
     //dynamic
                 $(document.getElementsByName(this.element.attr('name')))
      .checkBox('reflectUI', e, true);
             }
             return this._trigger(n, e, {
                 options: this.options,
                 checked: this.checkedStatus,
                 labels: this.labels,
     disabled: this.disabledStatus
             });
   }
   return undefined;
        },
  
        reflectUI: function(e){
   
            var oldChecked    = this.checkedStatus, 
    oldDisabledStatus  = this.disabledStatus
   ;
                 
   this.disabledStatus = this.element.is(':disabled');
   this.checkedStatus = this.element.is(':checked');
   
   if (this.disabledStatus != oldDisabledStatus || this.checkedStatus !== oldChecked) {
    this._changeStateClassChain();
    
    (this.disabledStatus != oldDisabledStatus &&
     this.propagate('disabledChange', e));
    
    (this.checkedStatus !== oldChecked &&
     this.propagate('change', e));
   }
            
        }
    });
})(jQuery);

