/*
 * Sliding Tabs 1.0.8 - jQuery Plugin
 * Copyright 2010, Christian André
 *
 * You need to buy a license if you want to use this script.
 * http://codecanyon.net/wiki/buying/howto-buying/licensing/
 *
 */

(function($) { 
 	
	$.fn.slideTabs = function(client_config) {	
        var default_config = {
            tabsList: 'ul.tabs',					
			viewContainer: 'div.view_container',		
			btnNext: 'a.next',
			btnPrev: 'a.prev',
			tabClass: 'tab',
			tabActiveClass: 'active',
			viewActiveClass: 'active_view',
			btnDisabledClass: 'disabled',
			orientation: 'horizontal',
			slideLength: 694,
			offsetTL: 0,
			offsetBR: 0,	
			tabsEasing: '',
			tabsAnimTime: 300,
			tabsScroll: true,
			contentAnim: 'slideH',
			contentEasing: 'easeInOutExpo',		
			contentAnimTime: 600,
			autoHeight: false,
			autoHeightTime: 0	
        };
        		
		var conf = $.extend(true, {}, default_config, client_config);
        
		return this.each(function() {
            var tabs = new SlideTabs($(this), conf);
            tabs.init();			
        });
    };
	
	function SlideTabs($container, conf) {							
		var $tabs = $container.find(conf.tabsList),
			$content = $container.find(conf.viewContainer).css('overflow', 'hidden'), // Hide the overflowing content
			$prev = $container.find(conf.btnPrev).click(function() { tabMethods.prevTab(val); return false; }), // Bind the prev button click event
			$next = $container.find(conf.btnNext).click(function() { tabMethods.nextTab(val); return false; }), // Bind the next button click event										
			$activeElem = $tabs.children('li').find('.'+conf.tabActiveClass),			
			$tab, $elem, $lastElem, $activeView, $view, 
			val = {}, elemMargin = 0;																													
					
		this.init = function() {			
			// Set the correct function and object names
			if (conf.orientation == 'horizontal') {										
				val.func = 'outerWidth';
				val.obj = 'left';				
				val.attr = 'marginLeft';											
			} else {
				val.func = 'outerHeight';										
				val.obj = 'top';													
				val.attr = 'marginTop';											
			}
			
			tabMethods.posActiveTab(); // Position the active tab			
			tabMethods.bindEvents(); // Bind tab events						
		};
				
		/* 
		 * Tab methods
		 */			 
		var tabMethods = {												
			tabsAnim: '#'+$container.attr('id')+' '+conf.tabsList+':animated',
			
			bindEvents: function() {
				// Delegate the tabs click event
				$tabs.delegate('li a.'+conf.tabClass, 'click', function() {
					tabMethods.tabClick(this);
					return false;
				});														
		
				// Mouse scroll wheel event				
				if (conf.tabsScroll == true) {				
					$tabs.mousewheel(function(event, delta) {
						(delta > 0) ? tabMethods.prevTab(val) : tabMethods.nextTab(val);					
						return false; // Prevents default scrolling
					});
				}			
			},
			
			posActiveTab: function() {
				// Set the first tab element to 'active' if no tab element has the active class
				if (!$activeElem.length) { $activeElem = $tabs.find('a:first').addClass(conf.tabActiveClass); }	
				
				// Show the active tab's content
				contentMethods.showActiveContent();
				
				$lastElem = $tabs.children('li:last');
				$activeElem = $activeElem.parent('li');
			
				if (($lastElem[val.func](true) + $lastElem.position()[val.obj]) > conf.slideLength) {					
					// Get the values needed to get the total width/height of the tabs
					val.elemD = $activeElem[val.func](true);
					val.elemP = $activeElem.position()[val.obj];	
					
					// Find the active element's position
					if (val.elemP > conf.slideLength) {
						elemMargin += (val.elemD + (val.elemP - conf.slideLength));							
						elemMargin = (elemMargin + conf.offsetBR);						
					} else if ((val.elemP + val.elemD) > conf.slideLength) {
						elemMargin += (val.elemD - (conf.slideLength - val.elemP));						
						elemMargin = (elemMargin + conf.offsetBR);
					} else {
						elemMargin = (elemMargin - conf.offsetTL);
					}								
																																	
					// Set the active element's position					
					$tabs.css(val.attr, -+elemMargin);
					
					// Show the directional buttons after the position has been set
					tabMethods.showTabButtons();
				}								
			},
			
			showTabButtons: function() {
				// Deactivate the arrow button if the tab element is at the beginning or end of the list								
				if ($tabs.children("li:first").position()[val.obj] == (0 + conf.offsetTL)) {				
					$prev.addClass(conf.btnDisabledClass);	
				} else if (($lastElem.position()[val.obj] + $lastElem[val.func](true)) == (conf.slideLength - conf.offsetBR)) {
					$next.addClass(conf.btnDisabledClass);
				}
												
				// Show the directional buttons
				$prev.show(); $next.show();
			},
			
			tabClick: function(tab) {
				$tab = $(tab);
				
				// Return false if an animation is running				
				if ($(contentMethods.contAnim).length || $tab.hasClass(conf.tabActiveClass)) { return false; }								
				
				$elem = $tab.parent('li');				
				
				// Set new active states		
				$activeElem = $tabs.children('li').find('a.'+conf.tabActiveClass).removeClass(conf.tabActiveClass);
				$tab.addClass(conf.tabActiveClass);
								
				// Assign the element's position
				val.elemP = $elem.position();
				val.activeElemP = $activeElem.position();								
				
				// Slide partially hidden tab into view
				tabMethods.slideClicked(val);												
											
				// Set the content vars and remove/add the active class
				$activeView = $content.children('div.'+conf.viewActiveClass).removeClass(conf.viewActiveClass);				
				$view = $content.children('div#'+$tab.attr('hash')).addClass(conf.viewActiveClass);																							
								
				if (conf.autoHeight == true) { contentMethods.adjustHeight(); }								
				
				// Show/animate the clicked tab's content into view	
				if (conf.contentAnim.length > 0) {			
					contentMethods[conf.contentAnim](val);
				} else {
					$activeView.hide();	$view.show();		
				}								
			},
			
			slideClicked: function(val) {
				val.elemP = val.elemP[val.obj];
				val.elemD = $elem[val.func](true);					
				val.nextElemPos = ($elem.next().length == 1) ? $elem.next().position()[val.obj] : 0;
				
				if (val.elemP < (0 + conf.offsetTL)) {															
					val.elemHidden = (val.elemD - val.nextElemPos);						
					elemMargin = (elemMargin - (val.elemHidden + conf.offsetTL));
					
					$next.removeClass(conf.btnDisabledClass); 		
				} else if ((val.elemD + val.elemP) > (conf.slideLength - conf.offsetBR)) {						
					elemMargin += (val.elemD - (conf.slideLength - (val.elemP + conf.offsetBR)));
																	
					$prev.removeClass(conf.btnDisabledClass); 	
				}																															
				
				tabMethods.animateTabs();
			},
			
			prevTab: function(val) {
				// Return false if an animation is running
				if ($(tabMethods.tabsAnim).length) { return false; }	
				
				// Find the element and set the margin 			
				$tabs.children('li').each(function() {	
					$elem = $(this);										
					val.elemP = $elem.position()[val.obj];												
					
					if (val.elemP >= (0 + conf.offsetTL)) {																			
						val.elemHidden = ($elem.prev()[val.func](true) - val.elemP);																		
						elemMargin = ((elemMargin - val.elemHidden) - conf.offsetTL);							
						
						$elem = $elem.prev(); // Set the $elem variable to the first visible element
						
						tabMethods.animateTabs();
						
						return false;
					}																									
				});
				
				// Enable the next link				
				$next.removeClass(conf.btnDisabledClass);  	
			},
			
			nextTab: function(val) {									
				// Return false if an animation is running
				if ($(tabMethods.tabsAnim).length) { return false; }								
				
				// Find the element and set the margin					
				$tabs.children('li').each(function() {						
					$elem = $(this);
					val.elemD = $elem[val.func](true);
					val.elemP = $elem.position()[val.obj];																																																																		
													
					if ((val.elemD + val.elemP) > (conf.slideLength - conf.offsetBR)) {																																																		
						val.elemHidden = (conf.slideLength - val.elemP);																																																				
						elemMargin += ((val.elemD - val.elemHidden) + conf.offsetBR);														
													
						tabMethods.animateTabs();																					
						
						return false;
					}																							
				});
				
				// Enable the prev link								
				$prev.removeClass(conf.btnDisabledClass);   											
			},
			
			animateTabs: function() {					
				// Animate tabs with the new value					
				if (conf.orientation == 'horizontal') { $tabs.animate({'marginLeft': -+elemMargin}, conf.tabsAnimTime, conf.tabsEasing); } 
				else { $tabs.animate({'marginTop': -+elemMargin}, conf.tabsAnimTime, conf.tabsEasing); }
									
				tabMethods.setActiveState();
			},
			
			setActiveState: function() {					
				if ($elem.is(':first-child')) {	$prev.addClass(conf.btnDisabledClass); } 
				else if ($elem.is(':last-child')) { $next.addClass(conf.btnDisabledClass); }
			}
		};
		
		/* 
		 * Content methods
		 */	
		var contentMethods = {
			contAnim: '#'+$container.attr('id')+' :animated',
			
			showActiveContent: function() {				
				// Set the content container's height to auto if autoHeight is set to; true
				if (conf.autoHeight == true) { $content.parent().css('height', 'auto'); }			
				
				// Show the active tab's content
				$content.children($activeElem.attr('href')).addClass(conf.viewActiveClass);
				
				 // Set the content div's to absolute and hide the 'inactive' content		
				$content.children('div').css('position', 'absolute').not('div.'+conf.viewActiveClass).hide();
			},
			
			adjustHeight: function() {				
				// Set the content's height
				if (conf.autoHeightTime > 0) { $content.animate({'height': $view.height()}, conf.autoHeightTime); } 
				else { $content.css('height', $view.height()); }		
			},
			
			fade: function() {
				$activeView.fadeOut(conf.contentAnimTime, function() {														
					$view.fadeIn(conf.contentAnimTime);														
				});												
			},								
			
			slideH: function(val) {								
				val.wh = $container.outerWidth(true);															
				contentMethods.setSlideValues(val);										
				
				$activeView.animate({'left': val.animVal}, conf.contentAnimTime, conf.contentEasing);												
							
				$view.css({'display': 'block', 'left': val.cssVal}).animate({'left': '0px'}, conf.contentAnimTime, conf.contentEasing, function() {				
					$activeView.css('display', 'none');				
				});																												
			},
			
			slideV: function(val) {
				val.wh = $container.outerHeight(true);					
				contentMethods.setSlideValues(val);										
				
				$activeView.animate({'top': val.animVal}, conf.contentAnimTime, conf.contentEasing);
											
				$view.css({'display': 'block', 'top': val.cssVal}).animate({'top': '0px'}, conf.contentAnimTime, conf.contentEasing, function() {				
					$activeView.css('display', 'none');												
				});		
			},
			
			setSlideValues: function(val) {									
				if (val.elemP > val.activeElemP[val.obj]) {	val.animVal = -val.wh; val.cssVal = val.wh;	} 
				else { val.animVal = val.wh; val.cssVal = -val.wh; }	
			}
		};												
	};

})(jQuery);
