/**
 * @author trixta
 */
(function($){
	
	function numsort (a, b) {
	  return a - b;
	}
	
	$.widget('ui.tabtree', {
		_init: function(){
			var that = this,
				o =  this.options,
				elem = this.element,
				isHTMLSelected
			;
			
			this.selectedIndexes = [];			
			this.slideShowtimer = null;
			
			this.buttons = $(o.buttonSel, elem[0]);
			
			this.panels = (o.panelSel) ? 
				$(o.panelSel, this.element[0]).each(function(i){
					var button 	= $(that.buttons[i]),
						panel 	= $(this).labelWith(button)
					;
					button.controlsThis(panel);
				}) : 
				this.buttons.map(function(){
					var button 	= $(this),
						idRef 	= button.getHrefHash(),
						panel 	= $(idRef)
					;
					
					panel.labelWith(button);
					button.attr({'aria-controls': idRef.replace('#', '')});
					return panel[0];
				});
							
			this.panels = $($.unique(this.panels.get()));
			
			if(o.focusDelay === 'auto'){
				o.focusDelay = (o.handleDisplay && o.handleDisplay !== 'initial') ? 201 : 401; // 400 ist default fx-duration
			}
			
			if(o.createPanelwrapper){
				this.panels.wrap('<div class="a11y-panelwrapper" />');
			}
			
			//get defaultselected
			isHTMLSelected = !!this.buttons.filter('.'+ o.activeButtonClass)[0];
							
			this.buttons
				.each(function(i){
					var button = $(this),
						initAction = ((isHTMLSelected && button.is('.'+ o.activeButtonClass)) ||
							(!isHTMLSelected && o.defaultSelected === i)) ? 
							'expand' :
							'collapse'
					;
					that[initAction].call(that, this, {type: 'init'});
				});
			
			if(o.addButtonRole && $.support.waiAria){
				this.buttons.attr({role: 'button'});
				if (this.buttons[0] && $.nodeName(this.buttons[0], 'a')) {
					this.buttons.each(function(){
						var jElm = $(this);
						this.setAttribute('data-href', jElm.attr('href'));
						jElm.removeAttr('href');
					});
				}
				this.panels.attr({role: 'group'}).addClass('a11y-js-overflow');
			}	
			
			
			if(o.selectEvents){
				this.buttons
					[o.bindStyle](o.selectEvents, function(e){
						var action = (o.toggleButton) ?
							'toggle' :
							'expand';
						that[action].call(that, this, e);
						clearInterval(that.slideShowtimer);
						return false;
					});
			}
			//focus panels onclick if no click event is added
			if(!o.selectEvents || o.selectEvents.indexOf('click') == -1){
				this.buttons[o.bindStyle]('click', function(){
					clearInterval(that.slideShowtimer);
					if(o.focusOnExpand){
						that.focusPanel.call(that, $($(this).attr('aria-controls')), 1);
					}
					return false;
				});
			}
			
			if(o.slideShow && isFinite(o.slideShow)){
				this.slideShowtimer = setInterval(function(){
					that.showPrevNext.call(that, 1);
				}, o.slideShow);
				this.element.inOut(
					function(){
						clearInterval(that.slideShowtimer);
					}, function(){
					if(o.restartSlideShow){
						clearInterval(that.slideShowtimer);
						that.slideShowtimer = setInterval(function(){
							that.showPrevNext.call(that, 1);
						}, o.slideShow);
					}
				});
			}
			
			if(o.addToHistory === 'auto'){
				o.addToHistory = !!($.hashHistory && !o.multiSelectable);
			}
			if(o.addToHistory){
				this.startHash = $.hashHistory.get();
				this.changeByHash(this.startHash, {type: 'hashInit'});
				this.startSelectedButton = this.buttons.filter('.'+ o.activeButtonClass);
				
				this.panels.each(function(){
					var jElm = $(this);
					//$('<a id="tab-'+ jElm.getID() +'" />').insertBefore(this).attr({tabindex: '-1'});
				});
				$(document).bind('hashHistoryChange', function(e, data){
					that.changeByHash(data.hash, $.extend({}, e, data));
				});
			}
			this._trigger('init', {type: 'init'}, this.ui());
		},
		
		showPrevNext: function(dir){
			var index = this.buttons
				.index(this.buttons.filter('.'+ this.options.activeButtonClass)[0]) + dir;
			if(index < 0){
				index = this.buttons.length - 1;
			} else if(index >= this.buttons.length){
				index = 0;
			}
			this.expand(this.buttons.get(index), {type: 'show-'+ dir});
		},
		toggle: function(button, e){			
			var action = ($(button).is('.'+ this.options.activeButtonClass)) ?
				'collapse' : 'expand';
			this[action](button, e);
		},
		collapse: function(button, e, _panel, _opener){
			e = e || {type: 'collapse'};
			button = $(button);
			
			//if button/panel is already inactive
			if(!button.is('.'+ this.options.activeButtonClass) && e.type != 'init'){				
				return false;
			}
			
			var panel 		= _panel || this.getPanel(button),
				buttons 	= this.getButtons(panel),
				type 		= (e.type == 'init') ? 
								'collapseinit' :
								'collapse',
				that 		= this,
				o 			= this.options,
				uiObj 		= {
								button: buttons,
								panel: panel
							}
			;			
			
			button.parent('li').removeClass('on');
			
			if(!o.multiSelectable){
				uiObj.expandElements = _opener || 
					{
						panel: $([]),
						button: $([])
					}
				;
			}
			
			this.removeIndex(panel);
			if(this._trigger(type, e, $.extend({}, this.ui(), uiObj)) === false){
				this.addIndex(panel);
				return;
			}
			
			this.setState(buttons, uiObj.panel, 'inactive');
			
			if(o.handleDisplay === true || (e.type == 'init' && o.handleDisplay)){
				uiObj.panel.hide();
			}
			uiObj.button = button;
			
			$.ui.SR.update();
			
			return uiObj;
		},
		addIndex: function(index){
			if(!isFinite(index) && index.jquery){
				index = this.panels.index(index[0]);
			}
			if($.inArray(index, this.selectedIndexes) === -1){
				this.selectedIndexes.push(index);
				this.selectedIndexes.sort(numsort);
			}
		},
		removeIndex: function(index){
			if(!isFinite(index) && index.jquery){
				index = this.panels.index(index[0]);
			}
			this.selectedIndexes = $.grep(this.selectedIndexes, function(num, i){
				return (index !== num);
			});
		},
		expand: function(button, e){
			e = e ||
				{type: 'expand'};
			button = $(button);
			
			//if button/panel is already active
			if(e.type != 'init' && button.is('.'+ this.options.activeButtonClass)){
				return false;
			}
			
			var type 			= (e.type == 'init') ? 
								'expandinit' :
								'expand',
				that 			= this,
				o 				= this.options,
				uiObj 			= {},
				panel 			= this.getPanel(button),
				buttons			= this.getButtons(panel),
				collapseButton 	= this.buttons.filter('.'+ o.activeButtonClass),
				posStyle,
				panelWrapper
			;
			
			button.parent('li').addClass('on');
			
			uiObj.button = buttons;
			uiObj.panel = panel;
			
			if(!o.multiSelectable){
				uiObj.collapseElements = {
							button: collapseButton, 
							panel: this.getPanel(collapseButton)
						};
			}
			this.addIndex(panel);
			
			if(this._trigger(type, e, $.extend({}, this.ui(), uiObj)) === false){
				this.removeIndex(panel);
				return false;
			}
			
			
			//collapse all other panels, if not multiSelectable
			if(e.type != 'init' && !o.multiSelectable){
				collapseButton.each(function(){
					that.collapse.call(that, this, e, false, {button: buttons, panel: panel});
				});
			}
			this.setState(buttons, panel, 'active');
			
			
			if(o.handleDisplay === true || (e.type == 'init' && o.handleDisplay == 'initial')){
				panel.show();
			}
			
			$.ui.SR.update();
			
			if(o.addToHistory && e.type !== 'init' && e.type !== 'hashHistoryChange'){
				$.hashHistory.add('tab-'+ panel.getID());
			}
			
			if(/click|hashHistoryChange/.test(e.type) && o.focusOnExpand){
				that.focusPanel(panel, o.focusDelay);
			}
			
		},
		getButtons: function(panel){
			return this.buttons.filter('[aria-controls='+ panel.getID() +']');
		},
		getPanel: function(button){
			return this.panels.filter('#'+ button.attr('aria-controls') );
		},
		changeByHash: function(hash, e){
			if(!hash.indexOf || (hash.indexOf('tab-') !== 0 && this.startHash !== hash)){return;}
			e = e || {type: 'hashHistory'};
			var button = this.buttons.filter('[aria-controls='+ hash.replace(/^tab-/, '') +']');
			if(!button[0] && hash === this.startHash){
				button = this.startSelectedButton;
			}
			if(button && button[0]){
				this.expand(button, e);
			}
		},
		setState: function(button, panel, state){
			var o	 	= this.options,
				set 	= (state == 'active') ? 
							{
								c: 'addClass',
								
								index: '-1',
								aria: 'true'
							} :
							{
								c: 'removeClass',
								index: '0',
								aria: 'false'
							}
			;
			if((!o.toggleButton)){
				button.attr({'tabindex': set.index, 'aria-disabled': set.aria})[set.c]('ui-disabled');
			} else {
				button.attr({'tabindex': '0'});
			}
			button[set.c](o.activeButtonClass).attr('aria-expanded', set.aria);
			panel[set.c](o.activePanelClass).attr('aria-expanded', set.aria);
		},
		focusPanel: function(panel, time){
			var o 			= this.options,
				focusElem 	= (o.focusSel === true || !o.focusSel) ? panel : $(o.focusSel, panel)
			;
			focusElem.setFocus({
				addTabindex: true,
				compMode: true,
				parent: panel,
				time: time || 1
			});
		},
		ui: function(){
			return {
				instance: this,
				panels: this.panels,
				buttons: this.buttons,
				selectedIndexes: this.selectedIndexes
			};
		}
	});
	
	$.ui.tabtree.defaults = {
		buttonSel: 'a',
		panelSel: false,
		focusOnExpand: true,
		focusSel: '> :visible:first',
		focusDelay: 'auto',
		addButtonRole: true,
		createPanelwrapper: false, 
		toggleButton: false,
		multiSelectable: false,
		selectEvents: 'ariaclick',
		bindStyle: 'bind',
		defaultSelected: 0,
		slideShow: false,
		restartSlideShow: true,
		activeButtonClass: 'js-selected',
		activePanelClass: 'js-expanded',
		handleDisplay: true, //initial | true | false
		addToHistory: false //'auto' || true ||  false
	};
})(jQuery);
