﻿(function($)
{
    $.fn.tabify = function(options)
	{
		var max_height = 49; // max height due to background image

		// maximum height allowed (due to bg image)
		if (options.height > max_height)
       		options.height = max_height;

		return this.each(function()
		{
			var ele = $(this);
			var ele_li = $("li", this);
			var ele_li_a = $("li a", this);
			
			ele.addClass("tabs");

			// default settings
			var settings =
			{
				width: 0, // 0 = auto
				height: 0, // 0 = auto
				iwidth: 0, // 0 = auto
				underline: true
			};
			// extending options to settings
			options = options || {};
			$.extend(settings, options);

			//---------------------------------------------
			// apply settings...

			if (settings.underline == true)
			{
				ele.addClass("underline");
			}

			if (settings.iwidth > 0)
			{
				ele_li_a.width(settings.iwidth);
			}
			
			var li_height_offset =
				tabify_pxval(ele_li.css("margin-top")) +
				tabify_pxval(ele_li.css("padding-top"));
			var li_a_height_offset =
				tabify_pxval(ele_li_a.css("margin-top")) +
				tabify_pxval(ele_li_a.css("padding-top"));

			if (settings.height > 0)
			{
				ele.height(settings.height);
				ele_li_a.height(settings.height - li_height_offset - li_a_height_offset);
			}
			else // auto height (if height <= 0)
			{
				var tHeight=0;
				// figure out the tallest tab
				ele_li_a.each(function()
				{
					var t = $(this);
					if (t.height() > tHeight)
						tHeight = t.height();
				});

				// make sure not over maximum height
				if (tHeight + li_height_offset + li_a_height_offset > max_height)
					tHeight = max_height - li_height_offset - li_a_height_offset;

				// set all tabs to the same tallest height
				ele_li_a.height(tHeight);

				// save height and set ul box to appropriate height
				settings.height = tHeight + li_height_offset + li_a_height_offset;
				ele.height(settings.height);
			}

			//---------------------------------------------
			// set width/height settings values if need be

			if (settings.width <= 0)
				settings.width = ele.width() + tabify_pxval(ele.css("padding-right")) + tabify_pxval(ele.css("padding-left"));

			if (settings.height <= 0)
				settings.height = ele.height();

			//---------------------------------------------
			// create container div, and wrap ele with

			var container = $(document.createElement("div"));
			container.width(settings.width);
			container.height(settings.height+1);
			container.css(
				{
					"position":"relative",
					"overflow":"hidden",
					"margin":0,
					"padding":0,
					"border":0
				});
			// wrap ele with container, and set ele to relative positioning
			ele.wrap(container);
			ele.css("position","relative");

			//---------------------------------------------
			// now that the general dimensions have been set
			// for the tabs, and container, etc
			// figure out and store the widths of each tab

			var tWidth=0, tCount=0, tabWidths=[], activeOffset=0;
			// figure out individual and total width of tabs
			ele_li.each(function()
			{
				var t = $(this);

				tWidth += tabWidths[tCount] =
					t.width() +
					tabify_pxval(t.css("padding-right")) +
					tabify_pxval(t.css("padding-left")) +
					tabify_pxval(t.css("margin-right")) +
					tabify_pxval(t.css("margin-left"));

				// if this is the active tab then remember
				// the width from the beginning of the tabs to
				// this tab (including this one)
				if (t.hasClass("active"))
					activeOffset = tWidth;

				tCount++;
			});
			// ensure ele is large enough for all the tabs
			ele.width(tWidth > settings.width ? tWidth : settings.width);
			ele.css("overflow", "visible");

			// save tab widths to settingsq
			settings.tabWidths = tabWidths;

			//---------------------------------------------
			// create buttons (prev/next)
			settings = tabify_createbuttons(ele, settings);
			
			//---------------------------------------------
			// store settings in jquery object (ele)
			ele.data("settings", settings);

			//---------------------------------------------
			// figure out the offset we should have (based on activeOffset found above)
			// offset the tabs so the "active" tab is viewable, show/hide buttons as needed
			if (activeOffset > settings.width)
			{
				var padding = tabify_pxval(ele.css("padding-right")) + tabify_pxval(ele.css("padding-left"));
				activeOffset = settings.width - activeOffset - padding;

				// show buttons if appropriate
				var bstate = tabify_showhidebuttons(ele, activeOffset);

				// if the next button is showing then compinsate for
				// the loss of viewable area by offseting by the button width
				if (bstate.next) activeOffset -= settings.bWidth;
				
				// set new offset
				ele.css("left", activeOffset+"px");
			}
			else tabify_showhidebuttons(ele)
		});
	}
	
	function tabify_createbuttons(ele, settings)
	{
		var container = ele.parent();

		var prev_button = $(document.createElement("a"));
		var next_button = $(document.createElement("a"));
		
		prev_button.addClass("tabify_prevbutton");
		next_button.addClass("tabify_nextbutton");
		
		prev_button.text("<");
		next_button.text(">");
		
		prev_button.css("cursor", "pointer");
		next_button.css("cursor", "pointer");
		
		prev_button.height(settings.height-1);
		next_button.height(settings.height-1);
		
		prev_button.bind("click", function(){ ele.tabify_prev(); });
		next_button.bind("click", function(){ ele.tabify_next(); });

		container.prepend(prev_button);
		container.prepend(next_button);
		
		settings.bWidth = prev_button.width();
		return settings;
	}
	
	function tabify_showhidebuttons(ele, offset)
	{
		var container = ele.parent();
		var settings = ele.data("settings");

		var fulltabs_width = ele.width();
		var viewable_width = settings.width;
		if (!offset) offset = 0; //tabify_pxval(ele.css("left"));
		
		var button_state = { prev:false, next:false }

		// if the tabs have been offset any, then we need a "prev" button
		if (offset < 0)
		{
			$("a.tabify_prevbutton", container).show();
			button_state.prev = true;
		}
		else
			$("a.tabify_prevbutton", container).hide();

		// if the viewable width (and offset taken into account) is
		// smaller than the width of all the tabs then we need a "next" button
		if (viewable_width - offset < fulltabs_width)
		{
			$("a.tabify_nextbutton", container).show();
			button_state.next = true;
		}
		else
			$("a.tabify_nextbutton", container).hide();

		return button_state;
	}
	
	$.fn.tabify_next = function()
	{
		var ele = this;

		// slide over to next tab (next tab is at the right)

		var settings = this.data("settings");
		var extra = (tabify_pxval(ele.css("padding-left")) + tabify_pxval(ele.css("padding-right")));
		var offset = tabify_pxval(ele.css("left"));

		// size from start of tabs (which could be hidden off the left side : offset)
		// to the right most viewable pixel of the tabs
		var x = settings.width - offset;
		
		// loop through the tab widths, subtracting each tab width from x
		// once x is below 0 then we know we've got a value indicating what
		// is necessary to view the next tab to the right
		for(i=0; i < settings.tabWidths.length; ++i)
		{
			if (x < 0) break; // gone past viewable (inc. offset)

			x -= settings.tabWidths[i]; // subtract the width of the next tab in the list
		}

		// we now have the value (negative, ie. leftwards slide) that we require to slide the tabs over
		// in order to view the next tab(s)... we need to add that value onto the amount the tabs
		// are already offset by (and also take into account the extra padding)
		x += offset - extra;
		
		// show buttons if appropriate
		var bstate = tabify_showhidebuttons(ele, x);

		// if the next button is showing then compinsate for
		// the loss of viewable area by offseting by the button width
		if (bstate.next) x -= settings.bWidth;

		// set new offset
		ele.animate({left:(x)+"px"}, 300);
	}

	$.fn.tabify_prev = function()
	{
		var ele = this;

		// slide over to prev tab (prev tab is at the left)

		var settings = ele.data("settings");
		var offset = tabify_pxval(ele.css("left"));
		
		var x = 0;

		// loop through the tab widths, subtracting each tab width from x
		// if x - next tab width = (negative) value greater (less than) or equal to offset
		// then that means we've gone past the offset into the viewable area, so just break
		// out at that point without actually subtracting that tab width
		// x should at that point be a smaller value than offset, a value that is the new
		// offset used to show the "prev" tab
		for(i=0; i < settings.tabWidths.length; ++i)
		{
			// gone past offset into viewable area
			// then x equals the offset necessary to view the
			// tab that is hidden to the left (prev tab)
			// don't subtract this next tab width, just break
			if (x - settings.tabWidths[i] <= offset) break;

			x -= settings.tabWidths[i];
		}

		// show buttons if appropriate
		var bstate = tabify_showhidebuttons(ele, x);
		
		// if the prev button is showing then compinsate for
		// the loss of viewable area by offseting by the button width
		if (bstate.prev) x += settings.bWidth;

		// set new offset
		ele.animate({left:(x)+"px"}, 300);
	}

})(jQuery);

function tabify_pxval(v) { if(!v) return 0; else return parseInt(v.replace("px","")) || 0; }
