//jQuery.tabnav 0.9.1

(function ($) {
	$.fn.tabnav = function (options) {
		// settings created by extending the defaults with the options.
		var settings = $.extend({}, $.fn.tabnav.defaults, options);

		// global.
		var global = {
			$self: this,
			index: 0,
			fragment: document.location.hash.substring(1)
		};

		// public interface.
		return this.each(function () {
			var $tabList;
			var state = {
				$self: $(this),
				$tabs: null,
				$panes: null,
				index: 0,
				selfId: undefined
			};

			var getSessionStorageKey = function () {
				return 'tabnav' + document.location.pathname + '#' + state.selfId;
			};

			var storeSelectedPaneInSession = function ($pane) {
				if (!settings.enableSessionStorage || !window.sessionStorage) {
					return;
				}

				window.sessionStorage.setItem(getSessionStorageKey(), $pane.attr('id'));
			};

			var retrieveSelectedPaneFromSession = function () {
				if (!settings.enableSessionStorage || !window.sessionStorage) {
					return null;
				}

				return window.sessionStorage.getItem(getSessionStorageKey());
			};

			var selectPane = function ($pane, $tab) {
				$pane.show().siblings().hide();
				$tab.addClass('selected').siblings().removeClass('selected');
				storeSelectedPaneInSession($pane);
				return true;
			};

			var selectPaneByIndex = function (index) {
				if (index < 0) {
					state.$panes.hide(); // filter(':visible') ?
				} else {
					selectPane(state.$panes.eq(index), state.$tabs.eq(index));
				}
			};

			var getTab = function ($pane) {
				var paneId;
				var $tab = $(document.createElement('li'));
				var $link = $(document.createElement('a'));
				var $heading = $pane.find(settings.tabTextSelector).remove();

				if ($pane.attr('id').length === 0) {
					// generate and set id if none exists.
					paneId = state.selfId + '-' + state.index;
					$pane.attr('id', paneId);
				} else {
					paneId = $pane.attr('id');
				}

				$link.text($heading.text())
					.attr('href', '#' + paneId)
					.click(function () {
						if (settings.enableFragmentSelection) {
							return !$tab.hasClass('selected') && selectPane($pane, $tab);
						} else {
							if (!$tab.hasClass('selected')) {
								selectPane($pane, $tab);
							}

							return false;
						}
					})
					.appendTo($tab);

				return $tab;
			};

			var getTabList = function () {
				var $tabList = $(document.createElement('ul'));

				state.$panes = state.$self.find(settings.paneSelector)
					.addClass(settings.paneClass)
					.each(function () {
						state.index++;
						$tabList.append(getTab($(this)));
					}
				);

				return $tabList;
			};

			var getSelectedPaneFromUrl = function () {
				if (settings.enableFragmentSelection || global.fragment.length === 0) {
					return false;
				}

				var $pane = state.$panes.filter('[id=' + global.fragment + ']');

				return $pane.length && $pane;
			};

			var getSelectedPaneFromSession = function () {
				var paneId = retrieveSelectedPaneFromSession();

				if (!paneId) {
					return false;
				}

				var $pane = state.$panes.filter('[id=' + paneId + ']');

				return $pane.length && $pane;
			};

			var initView = function () {
				var $pane = getSelectedPaneFromUrl() || getSelectedPaneFromSession();

				if (!$pane || !selectPane($pane, state.$tabs.eq(state.$panes.index($pane)))) {
					selectPaneByIndex(settings.initialIndex);
				}				
			};

			var setSelfId = function () {
				// Sets the id attribute on the element and stores it in state.
				if (state.$self.attr('id').length === 0) {
					// If the element has no id attribute we create one.
					state.selfId = settings.prefix + global.index;
					state.$self.attr('id', state.selfId);
				} else {
					// The element has an id attribute, let's store its value in state.
					state.selfId = state.$self.attr('id');
				}
			};

			var appendTabs = function ($tabList) {
				switch (settings.tabsPlacement) {
					case $.fn.tabnav.tabsPlacements.before:
						state.$self.before($tabList);
						break;
					case $.fn.tabnav.tabsPlacements.inside:
						state.$self.prepend($tabList);
						break;
				}
			};

			global.index++;
			setSelfId();
			$tabList = getTabList().addClass(settings.tabsClass);
			state.$tabs = $tabList.children('li');
			settings.initialIndex = Math.min(settings.initialIndex, state.$tabs.length - 1);
			appendTabs($tabList);
			initView();
		});
	};

	// possible values of $.fn.tabnav.settings.tabsPlacement
	$.fn.tabnav.tabsPlacements = {
		before: 1,
		inside: 2
	};

	// default settings.
	$.fn.tabnav.defaults = {
		enableFragmentSelection: true, // select tabs based on the fragment of the url.
		enableSessionStorage: true, // store tab selection based in the session storage.
		initialIndex: 0, // the index (zero-based) of the pane to display inially. a value of -1 will hide all panes.
		tabTextSelector: '', // selector to find the element, inside each pane, used for setting the text of the tabs.
		paneClass: 'pane', // class name to add to each pane.
		paneSelector: '>*', // selector to find the panes.
		prefix: 'pane', // string to prefix generated id attributes with.
		tabsClass: 'tabs', // class name to add to the list of tabs.
		tabsPlacement: $.fn.tabnav.tabsPlacements.before // placement of tabs relative to the list of panes.
	};
})(jQuery);
