/*
Extend jQuery UI to override _tabify function
See line 14 for important change
*/

(function($) {
	$.extend($.ui.tabs.prototype, {
		_tabify: function(init) {
		
			/*
			Using "find" method rather than the
			"children" method
			*/
			this.list = this.element.find('ul:first');
			//this.list = $('ul.ui-tabs-nav');
			this.lis = $('li:has(a[href])', this.list);
			this.anchors = this.lis.map(function() { return $('a', this)[0]; });
			this.panels = $([]);

			var self = this, o = this.options;

			var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
			this.anchors.each(function(i, a) {
				var href = $(a).attr('href');

				// For dynamically created HTML that contains a hash as href IE < 8 expands
				// such href to the full page url with hash and then misinterprets tab as ajax.
				// Same consideration applies for an added tab with a fragment identifier
				// since a[href=#fragment-identifier] does unexpectedly not match.
				// Thus normalize href attribute...
				var hrefBase = href.split('#')[0], baseEl;
				if (hrefBase && (hrefBase === location.toString().split('#')[0] ||
						(baseEl = $('base')[0]) && hrefBase === baseEl.href)) {
					href = a.hash;
					a.href = href;
				}

				// inline tab
				if (fragmentId.test(href)) {
					self.panels = self.panels.add(self._sanitizeSelector(href));
				}

				// remote tab
				else if (href != '#') { // prevent loading the page itself if href is just "#"
					$.data(a, 'href.tabs', href); // required for restore on destroy

					// TODO until #3808 is fixed strip fragment identifier from url
					// (IE fails to load from such url)
					$.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data

					var id = self._tabId(a);
					a.href = '#' + id;
					var $panel = $('#' + id);
					if (!$panel.length) {
						$panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom')
							.insertAfter(self.panels[i - 1] || self.list);
						$panel.data('destroy.tabs', true);
					}
					self.panels = self.panels.add($panel);
				}

				// invalid tab href
				else {
					o.disabled.push(i);
				}
			});

			// initialization from scratch
			if (init) {

				// attach necessary classes for styling
				this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all');
				this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
				this.lis.addClass('ui-state-default ui-corner-top');
				this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom');

				// Selected tab
				// use "selected" option or try to retrieve:
				// 1. from fragment identifier in url
				// 2. from cookie
				// 3. from selected class attribute on <li>
				if (o.selected === undefined) {
					if (location.hash) {
						this.anchors.each(function(i, a) {
							if (a.hash == location.hash) {
								o.selected = i;
								return false; // break
							}
						});
					}
					if (typeof o.selected != 'number' && o.cookie) {
						o.selected = parseInt(self._cookie(), 10);
					}
					if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) {
						o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
					}
					o.selected = o.selected || 0;
				}
				else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release
					o.selected = -1;
				}

				// sanity check - default to first tab...
				o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0;

				// Take disabling tabs via class attribute from HTML
				// into account and update option properly.
				// A selected tab cannot become disabled.
				o.disabled = $.unique(o.disabled.concat(
					$.map(this.lis.filter('.ui-state-disabled'),
						function(n, i) { return self.lis.index(n); } )
				)).sort();

				if ($.inArray(o.selected, o.disabled) != -1) {
					o.disabled.splice($.inArray(o.selected, o.disabled), 1);
				}

				// highlight selected tab
				this.panels.addClass('ui-tabs-hide');
				this.lis.removeClass('ui-tabs-selected ui-state-active');
				if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list
					this.panels.eq(o.selected).removeClass('ui-tabs-hide');
					this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active');

					// seems to be expected behavior that the show callback is fired
					self.element.queue("tabs", function() {
						self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected]));
					});
					
					this.load(o.selected);
				}

				// clean up to avoid memory leaks in certain versions of IE 6
				$(window).bind('unload', function() {
					self.lis.add(self.anchors).unbind('.tabs');
					self.lis = self.anchors = self.panels = null;
				});

			}
			// update selected after add/remove
			else {
				o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
			}

			// update collapsible
			this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible');

			// set or update cookie after init and add/remove respectively
			if (o.cookie) {
				this._cookie(o.selected, o.cookie);
			}

			// disable tabs
			for (var i = 0, li; (li = this.lis[i]); i++) {
				$(li)[$.inArray(i, o.disabled) != -1 &&
					!$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled');
			}

			// reset cache if switching from cached to not cached
			if (o.cache === false) {
				this.anchors.removeData('cache.tabs');
			}

			// remove all handlers before, tabify may run on existing tabs after add or option change
			this.lis.add(this.anchors).unbind('.tabs');

			if (o.event != 'mouseover') {
				var addState = function(state, el) {
					if (el.is(':not(.ui-state-disabled)')) {
						el.addClass('ui-state-' + state);
					}
				};
				var removeState = function(state, el) {
					el.removeClass('ui-state-' + state);
				};
				this.lis.bind('mouseover.tabs', function() {
					addState('hover', $(this));
				});
				this.lis.bind('mouseout.tabs', function() {
					removeState('hover', $(this));
				});
				this.anchors.bind('focus.tabs', function() {
					addState('focus', $(this).closest('li'));
				});
				this.anchors.bind('blur.tabs', function() {
					removeState('focus', $(this).closest('li'));
				});
			}

			// set up animations
			var hideFx, showFx;
			if (o.fx) {
				if ($.isArray(o.fx)) {
					hideFx = o.fx[0];
					showFx = o.fx[1];
				}
				else {
					hideFx = showFx = o.fx;
				}
			}

			// Reset certain styles left over from animation
			// and prevent IE's ClearType bug...
			function resetStyle($el, fx) {
				$el.css({ display: '' });
				if ($.browser.msie && fx.opacity) {
					$el[0].style.removeAttribute('filter');
				}
			}

			// Show a tab...
			var showTab = showFx ?
				function(clicked, $show) {
					$(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active');
					$show.hide().removeClass('ui-tabs-hide') // avoid flicker that way
						.animate(showFx, showFx.duration || 'normal', function() {
							resetStyle($show, showFx);
							self._trigger('show', null, self._ui(clicked, $show[0]));
						});
				} :
				function(clicked, $show) {
					$(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active');
					$show.removeClass('ui-tabs-hide');
					self._trigger('show', null, self._ui(clicked, $show[0]));
				};

			// Hide a tab, $show is optional...
			var hideTab = hideFx ?
				function(clicked, $hide) {
					$hide.animate(hideFx, hideFx.duration || 'normal', function() {
						self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default');
						$hide.addClass('ui-tabs-hide');
						resetStyle($hide, hideFx);
						self.element.dequeue("tabs");
					});
				} :
				function(clicked, $hide, $show) {
					self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default');
					$hide.addClass('ui-tabs-hide');
					self.element.dequeue("tabs");
				};

			// attach tab event handler, unbind to avoid duplicates from former tabifying...
			this.anchors.bind(o.event + '.tabs', function() {
				var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'),
						$show = $(self._sanitizeSelector(this.hash));

				// If tab is already selected and not collapsible or tab disabled or
				// or is already loading or click callback returns false stop here.
				// Check if click handler returns false last so that it is not executed
				// for a disabled or loading tab!
				if (($li.hasClass('ui-tabs-selected') && !o.collapsible) ||
					$li.hasClass('ui-state-disabled') ||
					$li.hasClass('ui-state-processing') ||
					self._trigger('select', null, self._ui(this, $show[0])) === false) {
					this.blur();
					return false;
				}

				o.selected = self.anchors.index(this);

				self.abort();

				// if tab may be closed
				if (o.collapsible) {
					if ($li.hasClass('ui-tabs-selected')) {
						o.selected = -1;

						if (o.cookie) {
							self._cookie(o.selected, o.cookie);
						}

						self.element.queue("tabs", function() {
							hideTab(el, $hide);
						}).dequeue("tabs");
						
						this.blur();
						return false;
					}
					else if (!$hide.length) {
						if (o.cookie) {
							self._cookie(o.selected, o.cookie);
						}
						
						self.element.queue("tabs", function() {
							showTab(el, $show);
						});

						self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
						
						this.blur();
						return false;
					}
				}

				if (o.cookie) {
					self._cookie(o.selected, o.cookie);
				}

				// show new tab
				if ($show.length) {
					if ($hide.length) {
						self.element.queue("tabs", function() {
							hideTab(el, $hide);
						});
					}
					self.element.queue("tabs", function() {
						showTab(el, $show);
					});
					
					self.load(self.anchors.index(this));
				}
				else {
					throw 'jQuery UI Tabs: Mismatching fragment identifier.';
				}

				// Prevent IE from keeping other link focussed when using the back button
				// and remove dotted border from clicked link. This is controlled via CSS
				// in modern browsers; blur() removes focus from address bar in Firefox
				// which can become a usability and annoying problem with tabs('rotate').
				if ($.browser.msie) {
					this.blur();
				}

			});

			// disable click in any case
			this.anchors.bind('click.tabs', function(){return false;});

		}
	});
})(jQuery);