
/**
 * jVertTabs - JQuery plugin for creating vertical tabs.
 *
 * By Seth Lenzi - slenzi@gmail.com
 *
 * This is free! Do with it as you want!
 */
 
 // .find() - travels down the dom (all levels)
 // .children() -on searches the first level

/**
 * String startsWith function. 
 */
String.prototype.startsWith = function(str){
	return (this.match("^"+str)==str);
}

/**
 * Creates vertical tabs!
 */
jQuery.fn.jVertTabs = function(options) {

	/**
     * default options
	 *
	 * selected: Index of the tab to open on initialization. 0-based, first tab is 0, second tab is 1, etc..
	 *
	 * select: A callback function that is called when a tab is clicked. The 'index' value will be the index of
	 *         the tab that was clicked. 0-based, first tab is 0, second tab is 1, etc..
	 *
	 * spinner: Text to show during ajax request. Pass in empty string to deactivate that behavior.
	 *
	 * equalHeights: If set to true the content panels will all have the same height. The min-heigh value
	 *               for each panel will be set to that of the tallest panel in the group. By default this
	 *               feature is turned off, or "false". Set to "true" to turn on.
	 *         
	 */
	var defaults = {
		selected: 0,
		select: function(index){
			//alert("Tab " + index + " clicked.");
		},
		spinner: "Retrieving data...",
		equalHeights: false
	};

	var opts = $.extend(defaults, options);

	return this.each(function(){
	
		/* add css classes to elements */
		var tabRoot = $(this);
		setStyle(tabRoot);
	
		/* references to tab column and tab content column */
		var tabColumn = $(this).children("div.tabs-tab-column");
		var tabContentColumn = $(this).children("div.tabs-content-column");
		
		/* locate all li elements  */
		$(this).find(".tabs-tab-column > ul > li").each(function(i){
			
			/* set css for initial state of tabs. first tab is open, the rest are closed.*/
			if(i < 1){
				$(this).addClass("open");
				$(this).find("a").addClass("open");
			}else{
				$(this).addClass("closed");
				$(this).find("a").addClass("closed");
			}
			
			/* add click events to all li elements */
			$(this).click(function() {
				handleTabClick($(this),i,tabColumn,tabContentColumn,true);
				return false;
			});
		});
		
		/* set initial state of tab content panels. first panel is open, the rest are closed */
		$(this).children(".tabs-content-column > div.tabs-content-panel").each(function(i){
			if(i>0){
				$(this).hide();
			}		
		});
		
		/* equalize heights if user specified to do so */
		if(opts.equalHeights){
			equalizeHeights(tabContentColumn);
		}
		
		/* open specified tab on itialization. this is customizable via the 'selected' option */
		var preSelectLi = tabColumn.find("ul > li").eq(opts.selected);
		handleTabClick(preSelectLi,opts.selected,tabColumn,tabContentColumn,false);
		
	});
	/**
	 * Click event handler.
	 *
	 * li 			      - <li></li> element that was clicked
	 * liIndex		 	  - index of the <li></li> element that was clicked. 0-based.
	 * tabCol		 	  - reference to the #tabs-tab-column element
	 * tabContentCol 	  - reference to the #tabs-content-column element
	 * doSelectedCallBack - true to call the 'select' callback function, false not to.
	 */
	function handleTabClick(li,liIndex,tabCol,tabContentCol,doSelectedCallBack){
				
		/* set css to closed for ones that are currently open */
		tabCol.find("ul > li").each(function(i){
			if($(this).hasClass("open")){
				$(this).removeClass("open").addClass("closed");
				$(this).find("a").removeClass("open").addClass("closed");
			}
		});
		/* set css for tab that was clicked */ 
		li.removeClass("closed").addClass("open");
		li.find("a").removeClass("closed").addClass("open");		
			
		/* hide all content panels and get reference to panel that needs to be showed. */
		var openContentPanel;
		tabContentCol.children("div.tabs-content-panel").each(function(i){
			$(this).hide();
			if(i == liIndex){
				openContentPanel = $(this);
			}
		});
		
		/* get link ahref value to see if we need to make an ajax call */
		var link = li.find("a");
		var linkText = link.text();
		var linkValue = link.attr("href");
		if(!linkValue.startsWith("#")){
			// set spinner message on link if we have a spinner value
			if(opts.spinner != ""){
				link.text(opts.spinner);
			}
			// make ajax call to get data
			$.ajax({
				url: linkValue,
				type: "POST",
				//dataType: "html",
				success: function(data) {
					// set data
					openContentPanel.html(data);				
					// open panel
					openContentPanel.fadeIn("normal");				
					// set link text back to what it originally was
					link.text(linkText);
					/* re-equalize heights if user specified to do so */
					if(opts.equalHeights){
						equalizeHeights(tabContentCol);
					}					
				},
				error: function(request,status,errorThrown) {
					// set link text back to what it originally was
					link.text(linkText);
					// alert error to user
					alert("Error requesting " + linkValue + ": " + errorThrown);
				}
			});
		}else{
			// no ajax request, open the panel
			openContentPanel.fadeIn("normal");
		}
		
		/* see if the user provided an optional callback function to call when a tab is clicked */
		if(doSelectedCallBack){
			if(jQuery.isFunction(opts.select)){
				opts.select.call(this,liIndex);
			}
		}		
		
	};
	/**
	 * Sets the height (min-height) of all content panels to that of the tallest one.
	 *
	 * tabContentCol - reference to the #tabs-content-column element
	 */
	function equalizeHeights(tabContentCol){
		var tallest = getTallestHeight(tabContentCol);
		setMinHeight(tabContentCol,tallest);	
	}
	/**
	 * Interates through all content panels and gets the height of the tallest one.
	 *
	 * tabContentCol - reference to the #tabs-content-column element
	 */
	function getTallestHeight(tabContentCol){
		var maxHeight = 0;
		tabContentCol.children("div.tabs-content-panel").each(function(i){
			if($(this).height() > maxHeight){
				maxHeight = $(this).height();
			}
		});
		return maxHeight;
	}
	/**
	 * Interates through all content panels and sets the min-height value for each one.
	 *
	 * tabContentCol - reference to the #tabs-content-column element
	 * minHeight - the min-height value
	 */
	function setMinHeight(tabContentCol,minHeight){
		tabContentCol.children("div.tabs-content-panel").each(function(i){
			$(this).css("min-height",minHeight);
		});
	}
	/**
	 * Adss the tab css classes to all the elements, then aligns the tab content panels
	 * to the right side of the tabs.
	 *
	 * tabRoot - reference to the root tab element.
	 */
	function setStyle(tabRoot){
		
		// add css
		tabRoot.addClass("tabs");
		tabRoot.children("div").eq(0).addClass("tabs-tab-column");
		tabRoot.children("div").eq(1).addClass("tabs-content-column");
		tabRoot.children("div").eq(1).children("div").addClass("tabs-content-panel");
		
		// align tab panels to the right side of the tabs.
		var tabColWidth = $('.tabs > .tabs-tab-column').width();
		$('.tabs > .tabs-content-column').css({"margin-left": tabColWidth + "px"});		
	}
};
