(function(jQuery)
{

	// tabbyOptions contains default options for the plugin
	var tabbyOptions =
	{
		fadeSpeed:		100
	};

	// tabbyIdentifiers contains string id's which are to be attached to certain elements
	var tabbyIdentifiers =
	{

	};

	// tabbyClasses contains string classes which are to be given to certain elements
	var tabbyClasses =
	{
		tab:					'tabby-tab',
		contentContainer:		'tabby-content'
	};

	//	tabbyCallbacks contains references to default callbacks
	var tabbyCallbacks =
	{
		
	};

	// tabbyData contains functions used for getting and setting data unique to the plugins parent element
	var tabbyData =
	{
		DATA_NAME:				'tabby-data',

		set:					function(element, data)
								{
									if (data)
									{
										var oldData = tabbyData.get(element);
										var extendedData = jQuery.extend({}, oldData, data);
										jQuery.data(element.get(0), tabbyData.DATA_NAME, extendedData);
										return data;
									}
									return false;
								},
								
		get:					function(element)
								{
									return jQuery.data(element.get(0), tabbyData.DATA_NAME) || {};
								},
								
		opts:					function(element, options)
								{
									if (options != undefined) return tabbyData.set(element, {opts: options}).opts;
									return tabbyData.get(element).opts;	
								},
					
		clss:					function(element, classes)
								{
									if (classes != undefined) return tabbyData.set(element, {clss: classes}).clss;
									return tabbyData.get(element).clss;	
								},
								
		callbacks:				function(element, callbacks)
								{
									if (callbacks != undefined) return tabbyData.set(element, {callbacks: callbacks}).callbacks;
									return tabbyData.get(element).callbacks;	
								}
	};
	
	// tabbyFind is used to find and return certain elements
	var tabbyFind =
	{			
		tabs:					function(tabbyContainer, classes)
								{
									return tabbyContainer.find('.' + classes.tab);
								},
								
		contentContainers:		function(tabbyContainer, classes)
								{
									return tabbyContainer.find('.' + classes.contentContainer);
								},
								
		contentByKey:			function(tabbyContainer, classes, key)
								{
									return tabbyContainer.find('.' + classes.contentContainer + key);
								},
								
		tabByKey:				function(tabbyContainer, classes, key)
								{
									return tabbyContainer.find('.' + classes.tab + '[rel=' + key + ']');
								}
	};
	
	// tabbyCreate is used to create and return new elements with some default settings: id, class, css, children
	var tabbyCreate =
	{		
		
	};
	
	// tabbyBinds contains functions used in binds and all accept the event argument
	var tabbyBinds = 
	{
		doTab:					function(ev)
								{
									ev.preventDefault();
									
									var tabbyContainer = ev.data.tabbyContainer;
									var options = ev.data.options;
									var classes = ev.data.classes;
									var callbacks = ev.data.callbacks;
									var key = $(ev.currentTarget).attr('rel');
									
									changeContent(tabbyContainer, key, options, classes, callbacks);
								}
	};

	// this is the starting point of the plugin
	jQuery.fn.tabby = function(command, args)
	{
		// loop through each of the passed elements and then return them for chaining
		return this.each(function()
		{
			var tabbyContainer = $(this);
			
			// determine what command was given and act on it appropriately
			
			if (typeof(command) == 'string')
			{
				switch (command)
				{
					case 'initialize': case 'init':
						initialize(tabbyContainer, args.options, args.classes, args.callbacks);
						break;
				}
			}
		});
	};
	
	// function initialize
	function initialize(tabbyContainer, options, classes, callbacks)
	{
		// extend the default options with the specified options and then store them
		options = tabbyData.opts(tabbyContainer, jQuery.extend({}, tabbyOptions, options));
		
		// extend the default classes with the specified classes and then store them
		classes = tabbyData.clss(tabbyContainer, jQuery.extend({}, tabbyClasses, classes));
		
		// extend the default callbacks with the specified callbacks and then store them
		callbacks = tabbyData.callbacks(tabbyContainer, jQuery.extend({}, tabbyCallbacks, callbacks));
		
		// bind tabs
		bindTabs(tabbyContainer, options, classes, callbacks);
	};
	
	// function bindTabs
	function bindTabs(tabbyContainer, options, classes, callbacks)
	{
		var bindOptions	=
		{
			tabbyContainer:		tabbyContainer,
			options:			options,
			classes:			classes,
			callbacks:			callbacks
		};
		
		var tabs = tabbyFind.tabs(tabbyContainer, classes);
		tabs.bind('click', bindOptions, tabbyBinds.doTab);
	};

	// function changeContent
	function changeContent(tabbyContainer, key, options, classes, callbacks, speed)
	{
		if (speed === undefined) speed = options.fadeSpeed;
		
		if ($.browser.msie) speed = 0;
		
		var tabs = tabbyFind.tabs(tabbyContainer, classes);
		var contentContainers = tabbyFind.contentContainers(tabbyContainer, classes);
		var wantedContent = tabbyFind.contentByKey(tabbyContainer, classes, key);
		var contentTab = tabbyFind.tabByKey(tabbyContainer, classes, key);
		
		contentContainers.css('display', 'none');
		
		if (speed > 0) wantedContent.css('opacity', 0);
		wantedContent.css('display', 'block');
		
		if (speed > 0) wantedContent.animate({opacity: 1}, speed);
		
		tabs.removeClass('selected');
		contentTab.addClass('selected');		
	};

})(jQuery);
