/**
 * @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);
