(function(jQuery)
{

	// scrollerOptions contains default options for the plugin
	var scrollerOptions =
	{
		fadeOutSpeed:				300,
		collapseSpeed:				300,
		fadeInSpeed:				400,
		offScreenFadeOutSpeed:		100,
		offScreenCollapseSpeed:		100,
		expandSpeed:				300,
		loopDirection:				'right',
		loopInterval:				3000,
		minItems:					5
	};

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

	};

	// scrollerClasses contains string classes which are to be given to certain elements
	var scrollerClasses =
	{
		scrollItem:			'scroller-item',
		scrollerLeft:		'scroller-left',
		scrollerRight:		'scroller-right',
		scrollerUp:			'scroller-up',
		scrollerDown:		'scroller-down'
	};

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

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

		set:					function(element, data)
								{
									if (data)
									{
										var oldData = scrollerData.get(element);
										var extendedData = jQuery.extend({}, oldData, data);
										jQuery.data(element.get(0), scrollerData.DATA_NAME, extendedData);
										return data;
									}
									return false;
								},
								
		get:					function(element)
								{
									return jQuery.data(element.get(0), scrollerData.DATA_NAME) || {};
								},
								
		opts:					function(element, options)
								{
									if (options != undefined) return scrollerData.set(element, {opts: options}).opts;
									return scrollerData.get(element).opts;	
								},
					
		clss:					function(element, classes)
								{
									if (classes != undefined) return scrollerData.set(element, {clss: classes}).clss;
									return scrollerData.get(element).clss;	
								},
								
		callbacks:				function(element, callbacks)
								{
									if (callbacks != undefined) return scrollerData.set(element, {callbacks: callbacks}).callbacks;
									return scrollerData.get(element).callbacks;	
								},
								
		isHovering:				function(element, status)
								{
									if (status != undefined) return scrollerData.set(element, {isHovering: status}).isHovering;
									return scrollerData.get(element).isHovering || false;	
								},
								
		isScrolling:				function(element, status)
								{
									if (status != undefined) return scrollerData.set(element, {isScrolling: status}).isScrolling;
									return scrollerData.get(element).isScrolling || false;	
								}
	};
	
	// scrollerFind is used to find and return certain elements
	var scrollerFind =
	{			
		
	};
	
	// scrollerCreate is used to create and return new elements with some default settings: id, class, css, children
	var scrollerCreate =
	{		
		
	};
	
	// scrollerBinds contains functions used in binds and all accept the event argument
	var scrollerBinds = 
	{
		move:				function(ev)
							{
								ev.preventDefault();
								var scrollerContainer = ev.data.scrollerContainer;
								var direction = ev.data.direction;
								move(scrollerContainer, direction)
							},
							
		mouseEnter:			function(ev)
							{
								var scrollerContainer = ev.data.scrollerContainer;
								scrollerData.isHovering(scrollerContainer, true);
								ev.preventDefault();
								stopLoop(scrollerContainer);
							},
							
		mouseLeave:			function(ev)
							{
								var scrollerContainer = ev.data.scrollerContainer;
								scrollerData.isHovering(scrollerContainer, false);
								ev.preventDefault();
								startLoop(scrollerContainer);
							}
	};

	// this is the starting point of the plugin
	jQuery.fn.scroller = function(command, args)
	{
		// loop through each of the passed elements and then return them for chaining
		return this.each(function()
		{
			var scrollerContainer = $(this);
			
			// determine what command was given and act on it appropriately
			
			if (typeof(command) == 'string')
			{
				switch (command)
				{
					case 'initialize': case 'init':
						initialize(scrollerContainer, args.options, args.classes, args.callbacks);
						break;
				}
			}
		});
	};
	
	// function initialize
	function initialize(scrollerContainer, options, classes, callbacks)
	{
		// extend the default options with the specified options and then store them
		options = scrollerData.opts(scrollerContainer, jQuery.extend({}, scrollerOptions, options));
		
		// extend the default classes with the specified classes and then store them
		classes = scrollerData.clss(scrollerContainer, jQuery.extend({}, scrollerClasses, classes));
		
		// extend the default callbacks with the specified callbacks and then store them
		callbacks = scrollerData.callbacks(scrollerContainer, jQuery.extend({}, scrollerCallbacks, callbacks));
		
		wrapContainer(scrollerContainer);
		bindStuff(scrollerContainer, options, classes, callbacks);
	};
	
	function bindStuff(scrollerContainer, options, classes, callbacks)
	{
		bindData =
		{
			scrollerContainer:	scrollerContainer
		}
		
		$('.' + classes.scrollerLeft).bind('click', jQuery.extend({}, bindData, {direction:'left'}), scrollerBinds.move);
		$('.' + classes.scrollerRight).bind('click', jQuery.extend({}, bindData, {direction:'right'}), scrollerBinds.move);
		
		scrollerContainer.bind('mouseenter', bindData, scrollerBinds.mouseEnter);
		scrollerContainer.bind('mouseleave', bindData, scrollerBinds.mouseLeave);
	};
	
	function wrapContainer(scrollerContainer)
	{
		var wrapContainer = $("<div></div>")
			.addClass('scroller-wrap-container')
			.css({
				width: scrollerContainer.width(),
				height: scrollerContainer.outerHeight(true),
				overflow: 'hidden'
			});
			
		scrollerContainer.css({
			position: 'relative'
		})
			
		scrollerContainer.after(wrapContainer);
		scrollerContainer.appendTo(wrapContainer);
		startLoop(scrollerContainer);
	};
	
	function move(scrollerContainer, direction, options, classes)
	{		
		// don't scroll if already scrolling
		if (scrollerData.isScrolling(scrollerContainer)) return false;
		
		if (options === undefined) options = scrollerData.opts(scrollerContainer);
		if (classes === undefined) classes = scrollerData.clss(scrollerContainer);
		
		// don't scroll if too few items
		var items = scrollerContainer.find('.' + classes.scrollItem);
		if (items.length <= options.minItems) return false;
		
		scrollerData.isScrolling(scrollerContainer, true);
		stopLoop(scrollerContainer);
		
		switch(direction)
		{
			case 'left':
				moveLeft(scrollerContainer, items, options, classes);
				break;
			case 'right':
				moveRight(scrollerContainer, items, options, classes);
				break;
		}
	};
	
	function moveComplete(scrollerContainer)
	{
		scrollerData.isScrolling(scrollerContainer, false);
		startLoop(scrollerContainer);
	};
	
	function moveRight(scrollerContainer, items, options, classes)
	{
		var firstItem = $(items.get(0));
		firstItem
			.animate({opacity: 0}, options.fadeOutSpeed, function()
			{
				firstItem.animate({width:0, marginLeft:0, marginRight:0, borderLeft:0, borderRight:0, paddingLeft:0, paddingRight:0}, options.collapseSpeed,
				function()
				{
					firstItem.css('display', 'none').css
						({
							width: 			'',
							marginLeft:		'',
							marginRight:	'',
							borderLeft:		'',
							borderRight:	'',
							paddingLeft:	'',
							paddingRight:	''
						});
					
					firstItem
						.appendTo(firstItem.parent())
						.css('display', 'block')
						.animate({opacity: 1}, options.fadeInSpeed, function()
						{
							moveComplete(scrollerContainer);	
						});
				});
			});
	};
	
	function moveLeft(scrollerContainer, items, options, classes)
	{
		var count = items.length;
		var lastItem = $(items.get(count - 1));
		lastItem
			.animate({opacity: 0}, options.offScreenFadeOutSpeed, function()
			{
				var width = lastItem.width();
				var marginLeft = parseInt(lastItem.css('marginLeft') || 0);
				var marginRight = parseInt(lastItem.css('marginRight') || 0);
				var borderLeft = parseInt(lastItem.css('borderLeft') || 0);
				var borderRight = parseInt(lastItem.css('borderRight') || 0);
				var paddingLeft = parseInt(lastItem.css('paddingLeft') || 0);
				var paddingRight = parseInt(lastItem.css('paddingRight') || 0);
				
				lastItem.animate({width:0, marginLeft:0, marginRight:0, borderLeft:0, borderRight:0, paddingLeft:0, paddingRight:0}, options.offScreenCollapseSpeed,
				function()
				{					
					lastItem
						.prependTo(lastItem.parent())
						.animate
							({
								width:			width,
								marginLeft:		marginLeft,
								marginRight:	marginRight,
								borderLeft:		borderLeft,
								borderRight:	borderRight,
								paddingLeft:	paddingLeft,
								paddingRight:	paddingRight}, options.expandSpeed, 
								function()
								{
									lastItem
										.animate({opacity: 1}, options.fadeInSpeed, function()
										{
											moveComplete(scrollerContainer);	
										});
								});
				});
			});
	};
	
	function startLoop(scrollerContainer)
	{
		var options = scrollerData.opts(scrollerContainer);
		var sliding = scrollerData.isScrolling(scrollerContainer);
		var hovering = scrollerData.isHovering(scrollerContainer);
		
		if (options.loopInterval > 0 && !sliding && !hovering)
		{
			scrollerContainer.get(0).loop = window.setInterval(
				function()
				{
					move(scrollerContainer, options.loopDirection, options);
				}, options.loopInterval);
		}
	}
	
	function restartLoop(scrollerContainer)
	{
		stopLoop(scrollerContainer);
		startLoop(scrollerContainer);
	}

	function stopLoop(scrollerContainer)
	{
		clearInterval(scrollerContainer.get(0).loop);
	};

})(jQuery);
