(function($)
{
	$.fn.crossFade = function(options)
	{
		options = $.extend({ }, $.fn.crossFade.defaults, options);
		return this.each(function()
		{
			var list = $(this);
			var items = list.find('li');
			if (items.length > 1)
			{
				items.hide();
				var startItem = dynamicFilter(options.startItem, items);
				startItem = startItem.length == 1 ? startItem : list.children('li:first-child');
				startItem.addClass('cross-fade-active');
				startItem.show();
				queue(startItem, options);
			}
		});
	};
	
	$.fn.crossFade.defaults =
	{
		itemDuration: 4000,
		fadeDuration: 2000,
		startItem: null
	};
	
	function rotate(currentItem, options)
	{
		var nextItem = currentItem.next();
		nextItem = nextItem.length > 0 ? nextItem : currentItem.parent().children('li:first-child');
		currentItem.removeClass('cross-fade-active');
		nextItem.addClass('cross-fade-active');
		nextItem.fadeIn(options.fadeDuration, function()
		{
			currentItem.hide();
			queue(nextItem, options);
		});
	};
	
	function queue(item, options)
	{
		setTimeout(function()
		{
			rotate(item, options);
		}, options.itemDuration);
	};
	
	function dynamicFilter(item, items)
	{
		switch (typeof item)
		{
			case 'number':
				// Get the item at the specified index.
				item = items.eq(item);
				break;
			case 'string':
				// Get the items matching the given expression.
				item = items.filter(item);
				break;
			default:
				// Ensure that the item is a jQuery object.
				item = $(item);
				
				// Check that the item is in the given context.
				if (items.index(item) < 0)
				{
					item = $([]);
				}
				
				break;
		}
		
		// Make sure there's only one being returned.
		return item.eq(0);
	}
})(jQuery);
