(function($){

	var methods = {
		
		init : function(options) {
			
			var settings = {
				'displayed' : 1,					//number of items displayed
				'width' : 300,						//width of a single item
				'height' : 200,						//height of a single item
				'margin' : 10,						//amount of margin right for each item
				'left' : ".left",					//left control
				'right' : ".right",					//right control
				'autoscroll' : false,				//enable autoscrolling
				'speed' : 1000,						//time for the autoscroller
				'scrollbar' : false,				//enable the scrollbar
				'scrollbarelem' : ".scrollbar",		//scrollbar element
				'scrollbarheight' : 1,				//height of the scroll bar (1 by default for a bottom border)
				'scrollbarwidth' : 200,				//width of the scroll bar
				'scrollbarsnap' : false				//snap the scroll marker movement instead of smoothly animating it
			};
			
			var constants = { //not sure these need to be pre defined but its nice to know
				'div' : null,
				'carousel' : null,
				'count' : 0,
				'timer' : null,
				'scrollbar' : null,
				'scrollmarker' : null,
				'lefter' : null
			};
			
			//allow jquery chaining
			return this.each(function() {

				//overwrite defaults with users chosen settings
				$.extend(settings, options);

				//locate the div and remember it for the function calls
				constants['div'] = $(this);

				//locate the carousel and remember it
				constants['carousel'] = $(this).find('ul');
				
				//locate the left control and remember it
				constants['lefter'] = $(this).find(settings['left']);

				//count the number of li's
				constants['count'] = $(this).find("li").length;

				//set the width of each li and add margin to the left of each li too
				$(this).find('li').width(settings['width']).height(settings['height']).css({'margin-right' : settings['margin']});

				//set the width of the ul to cover all li's and margin's
				constants['carousel'].width( constants['count'] * (settings['width']+settings['margin']) );

				//set the width of the viewer to cover the number of li's we want to see
				$(this).find('.view').width( ( settings['displayed'] * ( settings['width'] + settings['margin'] ) ) - settings['margin'] ).height( settings['height'] + settings['scrollbarheight'] );

				if (settings['scrollbar']) {
				
					//locate the scrollbar and remember it
					constants['scrollbar'] = $(this).find(settings['scrollbarelem']);
					
					//set the scrollbar size according to the settings
					constants['scrollbar'].height(settings['scrollbarheight']).width(settings['scrollbarwidth']);
					
					//append the scrollmarker to the scrollbar
					constants['scrollbar'].append('<div class="scrollmarker"></div>');
					
					//append an anchor tag for each li present
					for (i=1;i<=constants['count'];i++) constants['scrollbar'].append(function(){ return '<a href="'+i+'"></a>';});

					//locate the scrollmarker and remember it
					constants['scrollmarker'] = $(this).find('.scrollmarker');
					
					//set the scrollmarker size proportionally
					constants['scrollmarker'].width( ($(this).find('.view').width()/constants['carousel'].width()) * constants['scrollbar'].width() );
					
					//set the anchor size proportionally and lift them over the top of the scrollbar
					constants['scrollbar'].find("a").width( (1/constants['count']) * constants['scrollbar'].width() ).css({
						'position' : 'relative',
						'top' : (-1*settings['scrollbarheight'])
					}).each(function(index) {
					
						//add moveTo to each anchor
						$(this).click(function() {
							$(this).lucy('moveTo', constants['div'], $(this).attr('href'));
							return false;
						});
						
					});

				}

				//activate the left button
				constants['lefter'].click(function(){
						
					//if the carousel isn't already moving, move it
					if (!constants['carousel'].is(":animated")) $(this).lucy('moveLeft', constants['div']);	

					return false;
				});

				//activate the right button
				$(this).find(settings['right']).click(function() {
				
					//if the carousel isn't already moving, move it
					if (!constants['carousel'].is(":animated")) $(this).lucy('moveRight', constants['div']);

					return false;
				});
				
				if (settings['autoscroll']) {
				
					//activate the initial scroller
					constants['timer'] = setInterval( function(){ $(this).lucy('moveLeft', constants['div']); }, settings['speed'] );
	
					$(this).hover(function() {
					
						//cancel the scroller with hover
						clearInterval(constants['timer']);
					
					}, function() {
						
						//re activate the scroller on blur
						$(this).lucy('gogoScroller', constants['div']);
						
					});
				
				}

				//attach the data to the outer div to be picked up by the functions
				$(this).data("settings", settings);
				$(this).data("constants", constants);

			});

		}, //end init method
		
		gogoScroller : function(outer) {
		
			//remember shizzle
			var settings = outer.data("settings");
			var constants = outer.data("constants");
			
			//allow jquery chaining
			return this.each(function() {
				
				constants['timer'] = setInterval( function(){ $(this).lucy('moveLeft', constants['div']); }, settings['speed'] );
				
				//attach the data to the outer div to be picked up by the functions
				$(this).data("settings", settings);
				$(this).data("constants", constants);
			});
		
		}, //end gogoScroller method
		
		moveLeft : function(outer) {
			
			//remember shizzle
			var settings = outer.data("settings");
			var constants = outer.data("constants");
			
			//allow jquery chaining
			return this.each(function() {

				//how many pixels has the ul travelled left
				var pixelstravelled = parseInt(constants['carousel'].css('margin-left'));

				//how much margin is on screen at any time
				var numberofmargins = settings['displayed'] * settings['margin'];

				//what is the remaining width of the ul in terms of the widths of the li's that are there
				var remainingwidth = (pixelstravelled - numberofmargins) + parseInt(constants['carousel'].width());
				
				//pre set the reduction in margin-left
				var marginleft = '-='+( settings['width'] + settings['margin'] );

				//if the width of the remaining li's is the same as the width of the li's on screen then reset
				if (remainingwidth == settings['displayed'] * settings['width']) marginleft = 0;

				//animate the carousel according to marginleft
				constants['carousel'].animate({"margin-left" : marginleft},"fast", function() {
					
					//animate the scrollbar proportionally to match the carousel after moving the carousel
					if (settings['scrollbar']) $(this).lucy('moveScroll', constants['div']);
					
				});
				
			});
			
		}, //end moveLeft method
		
		moveRight : function(outer) {
		
			//remember shizzle
			var settings = outer.data("settings");
			var constants = outer.data("constants");
			
			//allow jquery chaining
			return this.each(function() {
				
				//pre set the increase in margin-left
				var marginleft = '+='+(settings['width']+settings['margin']);
				
				//if we are up against the left edge of the ul then scroll the carousel to only show the last required li's
				if (parseInt(constants['carousel'].css('margin-left')) >= 0) marginleft = '-='+((constants['count']-settings['displayed'])*(settings['width'] + settings['margin']));

				//animate the carousel according to marginleft
				constants['carousel'].animate({"margin-left" : marginleft},"fast", function() {
					
					//animate the scrollbar proportionally to match the carousel
					if (settings['scrollbar']) $(this).lucy('moveScroll', constants['div']);
				
				});
				
			});	
		}, //end moveRight method
		
		moveScroll : function(outer) {
		
			//remember shizzle
			var settings = outer.data("settings");
			var constants = outer.data("constants");
			
			//allow jquery chaining
			return this.each(function() {
			
				//calculate how far to move the scrollmarker
				var distancetotravel = ( ( parseInt(constants['carousel'].css('margin-left')) / constants['carousel'].width() ) * -1 ) * constants['scrollmarker'].parent().width();
				
				//if user wants snapping, use css
				if (settings['scrollbarsnap']) constants['scrollmarker'].css({'margin-left' : distancetotravel});
				
				//else animate
				else constants['scrollmarker'].animate({'margin-left' : distancetotravel}, "fast");
			});

		}, //end moveScroll method
		
		moveTo : function(outer, pos) {
		
			//remember shizzle
			var settings = outer.data("settings");
			var constants = outer.data("constants");
			
			//allow jquery chaining
			return this.each(function() {
				
				//calculate the number of the leftmost li of the farthest right group
				var rightedge = constants['count'] - settings['displayed'];
				
				//if the clicked pos is too close to the edge, set pos to as far as it should go
				if ( pos > rightedge ) pos = rightedge;
				
				//bring pos into line (or something else witty, I don't know)
				else pos--;
				
				//move the carousel to the desired position
				constants['carousel'].animate({'margin-left' : ( pos * (settings['width']+settings['margin']) )*-1}, "fast", function() {
				
					//animate the scrollbar proportionally to match the carousel after moving carousel
					if (settings['scrollbar']) $(this).lucy('moveScroll', constants['div']);
				
				});

			});
		} //end moveTo method
		
	} //end methods

	$.fn.lucy = function(method) {

		//if the method exists then use it
		if ( methods[method] ) return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));

		//if the user passed an object, chuck it at the init method
		else if ( typeof method === 'object' || ! method ) return methods.init.apply( this, arguments );

		//if the user has failed miserable then say so
		else $.error( 'Method ' +  method + ' does not exist fool!' );

	};

})( jQuery );

