// #@(#)jquery.basictabs.js	1.4 11:45:50,12/01/03 (yy/mm/dd) 
/**
 * Basic Tabs (Created AM Nov '11)
 * 
 * Version 1.2.1
 * 
 * JQuery Plugin to create Tab functionality but with the ability to use built in transitions.
 * 
 * In order to have this automatically fire, there needs to be a container div with a class of '.basictabs'.
 * This is not compulsory and it's possible to point this plugin at other class names/selectors.
 * 
 * Inside the container will be two sections tab-head and tab-body.
 * 
 * The tab-head will contain one "ul" list which contains the options. By default the first tab is selected.
 * Each li within the ul will have an anchor tag which has an href to the id of the tab that it should be associated with.
 * 
 * The tab-body will contain a collection of divs each with corresponding ID's (that tie in with the li tags)
 * Each of these divs is required to have a class of js-tab to which this plugin looks for.
 * 
 * The plugin will apply classes of .current, .locked, .hover, .inactive, .active to both the lis and divs.
 * 
 * .locked, .hover, .current will all be applied to li's
 * .inactive, .active will be applied to the js-tab div's
 * 
 * Revisions
 * 1.0 Initial Release
 * 1.1 Fixed IE7+8 issue with href, Fixed intial height transition issue
 * 1.2 Added #anchor linking - loads #tags in the location bar/adds them when changing tabs to enable bookmarking
 * 1.2.1 Modified to prevent complete collapsing of tabs on change. Removed anchor tags from updating location - however can still jump to tabs.
 * 
 * Future plans (to do)
 * # Implement different preselected tabs (either via classname or with defaults)
 * # Add extra transitions
 */

(function($){
	// Private vars
	var 
		// Constants / Methods to be expanded upon
		VERTICAL_SHRINK_FADE_IN = {
			"opacity":1
		},
		VERTICAL_SHRINK_FADE_OUT = {
			"opacity":0
		},
		// Global Holders
		storedNewTab,
		storedOptions,
		animateInMethod,
		animateOutMethod,
		animateInDuration,
		animateOutDuration,
		methods;
		
	
	
	// Private methods
	switchTab = function (oldTab, newTab, options, this_tc, this_tc_clicked) {
		animateInMethod	 	= eval(options.animateIn);
		animateOutMethod 	= eval(options.animateOut);
		animateInDuration 	= options.animateInDuration;
		animateOutDuration 	= options.animateOutDuration;
		
		var storedNewTab 	= newTab;
		var storedOptions 	= options;
		
		
		// Set the default animations if none are provided.
		if(animateInMethod === null || animateInMethod === undefined) {
			animateInMethod 	= VERTICAL_SHRINK_FADE_IN;
		}
		
		if(animateOutMethod === null || animateOutMethod === undefined) {
			animateOutMethod 	= VERTICAL_SHRINK_FADE_OUT;
		} 
			
		// Add any custom properties based on animation type
		switch(animateInMethod) {
			case VERTICAL_SHRINK_FADE_IN:
				// Animate to the height of the new tab (not sure if required)
				//animateInMethod.height = $(storedNewTab).data("height");
				break;
			default:
				break;
		}
		
		switch(animateOutMethod) {
			case VERTICAL_SHRINK_FADE_OUT:
				$(storedNewTab).css("opacity", VERTICAL_SHRINK_FADE_OUT.opacity);	// Match the pairs opacity
				animateOutMethod.height = $(storedNewTab).data("height");			// Take the height back to the new tab
				break;
			default:
				break;
		}
		
		$(oldTab).animate(animateOutMethod, animateOutDuration, function() {

			$(this).removeClass("active").addClass("inactive").hide();
			// Restore the now hidden tab to it's original height
			
			// Set the old tabs height back
			$(oldTab).css("height", $(oldTab).data("height"));
			
			this_tc_clicked.addClass("current");
			
			// Need to find a better way of doing this, but key is preparing new tab before using.
			$(newTab).show();
			
			$(storedNewTab).animate(animateInMethod, animateInDuration, function() {
				
			
				// IE7&8 fade/font issue
				try { this.style.removeAttribute("filter"); } catch(err) {};
					
				$(this).removeClass("inactive").addClass("active");
				this_tc.find("li").removeClass("locked");
				
				if(storedOptions.callBack !== undefined) {
					storedOptions.callBack();
				}
			})	
		})
	}
	
	/**
	 * Core set of methods which are exposed as part of the plugin
	 */
	methods = {
		
		/**
		 * The main/default constructor of the plugin
		 * @param {Object} inOptions An Object containing the custom set of options to be applied to each 
		 * of the instances of the plugins.
		 */
		init : function (inOptions) {
			var options = $.extend({}, $.fn.basictabs.defaults, inOptions);		// Combine the options and defaults into a new object
			
			initOptions = options;
			
			return this.each(function () {
				// Variables
				var this_tc = $(this);
					
				
				// Hide the tabs and work out what their heights were before hiding
				this_tc.find('.js-tab').each(function() {
					$(this).data("height", $(this).height());
					$(this).addClass("inactive").hide();
				});
				
				
				$(this_tc).find('.tab-head').each(function() {
					
					
					// Put code here to determine the hash and see which one matches - then add current if matched - if not do to the first
					var currentSet = false;
					
					var thisTag = window.location.hash;
					var oldTab, newTab;
					
					$(this).find("li").each(function() {
						
						// Match hash;
						var thisHash = $(this).find("a").attr("href");
						
						if(thisHash == thisTag) {
							$(this).addClass("current");
							this_tc.find(thisHash).show().addClass("active").removeClass("inactive");
							currentSet = true;	
						}
						
						
						$(this).bind('click', function() {
							if(!$(this).hasClass("current") && !$(this).hasClass("locked")) {
								
								this_tc_clicked = $(this);
	
								// Add locked to all the tabs (prevent further clicking?)
								this_tc.find("li").addClass("locked").removeClass("current");
	
								newTab = $(this).find("a").attr("href");
								newTab = newTab.substring(newTab.indexOf('#'));
								
								oldTab = $(this_tc).find(".js-tab.active");
								
								// Call the close tab method
								switchTab(oldTab, newTab, options, this_tc, this_tc_clicked);
							}
							
							// Stop the hash from being returned
							return false;
						});
						
						$(this).hover(
							function() {
								$(this).addClass("hover")
							},
							function() {
								$(this).removeClass("hover");
							}
						)
					})
					
					if(currentSet == false) {
						$(this).find("li:first").addClass("current");
						this_tc.find('.js-tab:first').show().addClass("active").removeClass("inactive");
					}
				});
				
					
			});
		},
		reset : function (inOptions) {
			var options = $.extend({}, $.fn.basictabs.defaults, inOptions);		// Combine any updated options and the passed in ones
			
			return this.each(function () {
				
			});
		}
	};
	
	
	/**
	 * Main Constructor which then goes on to use the method object.
	 */
	$.fn.basictabs = function (method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
	    } else if (typeof method === 'object' || !method ) {
			return methods.init.apply(this, arguments);
	    } else {
			$.error('Method ' +  method + ' does not exist on jQuery.basictabs');
	    }
	};
	
	/**
	 * Defaults which can be passed in as over-ride
	 */
	$.fn.basictabs.defaults = {
		animateOut:"VERTICAL_SHRINK_FADE_OUT",
		animateIn:"VERTICAL_SHRINK_FADE_IN",
		animateInDuration:250,
		animateOutDuration:250
	};
	
	/** 
	 * Automatic call to instiate basic functionality
	 */
	$(document).ready(function() {
		// Default Method
		$('.basictabs').basictabs();
	});
	
})(jQuery)

