(function ($) {
$.widget('ui.contentDropdown', {
	options: {
		active: false,
		header: '> h3',
		cancel: ':input',
		fx:  {opacity: 'toggle', height: 'toggle', duration: 'fast'},
		cursor: 'pointer',
		icons: {
			header: 'ui-icon-triangle-1-e',
			headerSelected: 'ui-icon-triangle-1-s'
		},
		navigation: true,
		navigationFilter: function () {
			return this.href.toLowerCase() == location.href.toLowerCase();
		},
		event: 'click',
		useClasses: false
	},
   
	_create: function () {
		var o = this.options;
		var self = this;
		this.hideFx;
		this.showFx;
		
		// find headers
		this.headers = this.element.find(o.header)
			.bind('keydown', function (event) { return self._keyDown(event); })
			.css('cursor', o.cursor);
		
		// find active headers
		if (o.navigation) {
			this._activateNavigation();
		}
		this.active = this._findActive((this.active && this.active.length) || o.active);
		
		// hide inactive contents
		this.headers.not(this.active || '').next().hide();
		
		// append icons
		if (o.icons) {
			this._createIcons();
		}
		
		// set up animations
		if (o.fx) {
			if ($.isArray(o.fx)) {
				this.hideFx = o.fx[0];
				this.showFx = o.fx[1];
			} else {
				this.hideFx = this.showFx = o.fx;
			}
		}

		// bind header activation
		if (o.event) {
			this.headers.bind((o.event) + '.contentDropdown', function (e) {
				
				// cancel activation on certain elements
				if ($(e.target).is(o.cancel)) return true;
				
				self._doEventHandler.call(self, this);
				e.preventDefault(); // stop default action, but do not stop event propagation
			});
		}
		
		// use jquery-ui css?
		if (o.useClasses) {
			this._useClasses();
		} 
	},
	
	activate: function (index) {
		this.options.active = index;
		this._doEventHandler(this._findActive(index));
		return this;
	},
	
	open: function (index) {
		var active = this._findActive(index);
		if (active.length > this.active.length) {
			this.options.active = active;
			this._doEventHandler(active);
		}
		return this;
	},
	
	_activateNavigation: function () {
		var o = this.options;
		var current = this.element.find('a').filter(o.navigationFilter);
		
		// TODO: traverse without using jquery-ui styles
		if (current.length) {
			var header = current.closest('.ui-contentDropdown-header');
			// anchor within header or content?
			if (header.length) {				
				this.active = header;
			} else {
				this.active = current.closest('.ui-contentDropdown-content').prev();
			}
		}		
	},
	
	_useClasses: function () {
		this.element.addClass('ui-contentDropdown ui-widget ui-helper-reset');
		
		this.headers.addClass('ui-contentDropdown-header ui-helper-reset ui-state-default ui-corner-all')
			.bind('mouseenter.contentDropdown', function () { $(this).addClass('ui-state-hover'); })
			.bind('mouseleave.contentDropdown', function () { $(this).removeClass('ui-state-hover'); })
			.bind('focus.contentDropdown', function () { $(this).addClass('ui-state-focus'); })
			.bind('blur.contentDropdown', function () { $(this).removeClass('ui-state-focus'); });
		
		this.headers.next().addClass('ui-contentDropdown-content ui-helper-reset ui-widget-content ui-corner-bottom');
		
		this.active.toggleClass('ui-state-default').toggleClass('ui-state-active');
		
		this.active.next().addClass('ui-contentDropdown-content-active');
	},
	
	_createIcons: function () {
		var o = this.options;
		
		$('<span />').addClass('icon ' + o.icons.header).prependTo(this.headers);
		this.active.find('.icon').toggleClass(o.icons.header).toggleClass(o.icons.headerSelected);
		if (o.useClasses) this.element.addClass('ui-contentDropdown-icons');
	},
	
	_destroyIcons: function () {
		this.headers.children('.icon').remove();
		this.element.removeClass('ui-contentDropdown-icons');
	},
	
	_keyDown: function (e) {
		var o = this.options;
		var keyCode = $.ui.keyCode;
		
		if (o.disabled || e.altKey || e.ctrlKey) return;
		
		var length = this.headers.length;
		var currentIndex = this.headers.index(e.target);
		var toFocus = false;
		
		switch (e.keyCode) {
			case keyCode.RIGHT:
			case keyCode.DOWN:
				toFocus = this.headers[(currentIndex + 1) % length];
				break;
				
			case keyCode.LEFT:
			case keyCode.UP:
				toFocus = this.headers[(currentIndex - 1 + length) % length];				
				break;
				
			case keyCode.SPACE:
			case keyCode.ENTER:
				this._doEventHandler(e.target);
				e.preventDefault();
				break;
		}
		
		if (toFocus) {
			toFocus.focus();
			return false;
		}
		
		return true;
	},
	
	_findActive: function (selector) {
		
		if (selector === false)	return $([]);
		if (typeof selector == 'number') return this.headers.eq(selector);
		if (typeof selector == 'undefined') return this.headers.eq(0);
		
		return this.headers.not(this.headers.not(selector));
	},
	
	_setOption: function (key, value) {
		$.Widget.prototype._setOption.apply(this, arguments);
		if (key == 'active') {
			this.activate(value);
		} else if (key == 'icons') {
			this._destroyIcons();
			if (value) {
				this._createIcons();
			}
		}
	},
	
	_toggle: function (toShow, toHide) {
		var o = this.options;
		var self = this;
		var completed = function () {
			self._completed(arguments);
		};
		
		// toggle header icons
		if (o.icons) {
			var inactive = this.headers.not(this.active).find('.icon');
			var active = this.active.find('.icon');			
			inactive.removeClass(o.icons.headerSelected).addClass(o.icons.header);
			active.removeClass(o.icons.header).addClass(o.icons.headerSelected);
		}
				
		// hide
		if (this.hideFx) {
			toHide.animate(this.hideFx, this.hideFx.duration || 'normal', completed);
		} else {
			toHide.hide();
		}
		
		// show
		if (this.showFx) {
			toShow.animate(this.showFx, this.showFx.duration || 'normal', completed);
		} else {
			toShow.show();
		}
		
		// call completed here if not using animation
		if (!this.hideFx && !this.showFx) {
			completed();
		}
	},
	
	_completed: function () {
		this._trigger('change', null, {active: this.active, headers: this.headers});
	},
	
	_doEventHandler: function (target) {		
		var o = this.options;
		var clicked = $(target);
		var clickedIndex = $.inArray(clicked[0], this.active);
		var clickedIsActive = (clickedIndex != -1);
		
		// deactivate?
		if (!clicked.length) {
			 var toHide = this.active.next();
			 var toShow = this.active = $([]);
			 this._toggle(toShow, toHide);
			 return;
		}
		
		// switch classes
		if (o.useClasses) {
			if (!clickedIsActive) {
				clicked.removeClass('ui-state-default ui-corner-all').addClass('ui-state-active ui-corner-top');
				clicked.next().addClass('ui-contentDropdown-content-active');
			} else {
				clicked.removeClass('ui-state-active ui-corner-top').addClass('ui-state-default ui-corner-all');
			}
		}
		
		// trigger pre change event
		this._trigger('preChange', null, {active: this.active, headers: this.headers});
		
		// toggle active
		if (clickedIsActive) {
			var toHide = $(this.active.splice(clickedIndex, 1)).next();
			var toShow = $([]);
		} else {
			this.active.push(clicked[0]);
			var toHide = $([]);
			var toShow = clicked.next();
		}
		this._toggle(toShow, toHide);
	}
});
})(jQuery);
