$.fn.slSlider = function( options ) {

	var settings = {
		autoStart			: false,
		bidirectional		: false, // utile seulement pour slide
		changeOnHover		: false,
		dragDrop			: false, // utile seulement pour slide
		effectDuration		: false, // false ou même options que pour les effets jQuery standards ('slow', 'fast', 200, ...). Ne fonctionne pas pour dragDrop
		elementsSelector	: 'img',
		linksToHtml			: '<li><a class="slcLinkTo" href="#">$i</a></li>', // $i est le numéro de l'image
		moveOnKeyPress		: false,
		nbElementsDisplayed	: 1,
		nextLinkHtml		: '<li class="slcNext"><a href="#">Suivant</a></li>',
		paginationHtml		: '<ul class="slcPagination" />',
		previousLinkHtml	: '<li class="slcPrevious"><a href="#">Précédent</a></li>',
		temporisation		: 3000,
		transition			: 'none', // 'none', 'slide' ou 'fade'
		vertical			: false // utile seulement pour slide
	};
    
	return this.each(function() {
		// If options exist, lets merge them
		// with our default settings
		if ( options ) { 
			$.extend( settings, options );
		}
		
		var slider = $(this);
		
		// Ajout pagination
		var pagination = $(settings.paginationHtml);
		var previous = $(settings.previousLinkHtml);
		var next = $(settings.nextLinkHtml);
		
		previous.appendTo(pagination);
		next.appendTo(pagination);
		pagination.insertAfter(slider);
		
		// Initialisation des elements
		var elements = slider.find(settings.elementsSelector);
		var indexCurrent = 0;
		var currentElement = $(elements[indexCurrent]);
		
		// Ajout numeros
		if (settings.linksToHtml)
		{
			for (i = 0; i < elements.length; ++i)
			{
				var linkTo = $(settings.linksToHtml.replace('$i', i));
				linkTo.find('a').attr('href', '#' + i);
				linkTo.insertBefore(next);
				
				linkTo.find('a').bind((settings.changeOnHover ? 'mouseover' : 'click'), function () { goTo(parseFloat($(this).attr('href').split('#')[1])); clearInterval(timer); return false; });
			}
		}
		
		var autoStart = settings.autoStart;
		var timer;
		
		var currentlyMoving = false;
		
		slider.css({
			position	: 'relative',
			overflow	: 'hidden',
			height		: currentElement.height() * (settings.vertical ? settings.nbElementsDisplayed : 1),
			width		: currentElement.width() * (!settings.vertical ? settings.nbElementsDisplayed : 1)
		});
		
		elements.css( {
			position	: 'absolute',
			left		: 0,
			top			: 0
		});
		
		if (settings.transition == 'slide' && settings.bidirectional)
		{
			var offset = 0;
			if (settings.vertical)
			{
				elements.each(function () {
					$(this).css('top', offset);
					offset += $(this).height();
				});
			}
			else{
				elements.each(function () {
					$(this).css('left', offset);
					offset += $(this).width();
				});
			}
		}
		
		if (settings.moveOnKeyPress)
		{
			$($.merge($.merge([], slider), pagination)).keydown(function (event) {
				var keyPrevious = (settings.transition == 'slide' && settings.vertical) ? '38' : '37';
				var keyNext = (settings.transition == 'slide' && settings.vertical) ? '40' : '39';
				
				if (event.which == keyPrevious)
				{
					goToPrevious();
					clearInterval(timer);
				}
				else if (event.which == keyNext)
				{
					goToNext();
					clearInterval(timer);
				}
			});
		}
		
		if (settings.transition == 'slide' && settings.bidirectional && settings.dragDrop)
		{
			slider.bind('mousedown', function (event) {
				clearInterval(timer);
				
				if (!currentlyMoving)
				{
					currentlyMoving = true;
					
					var start = (settings.vertical) ? event.pageY : event.pageX;
					var element = $(this);
					
					var waitingForEffect = false;
					
					$('html').bind('mousemove', function (event) {
						if (!waitingForEffect)
						{
							waitingForEffect = true;
							effectTimer = setInterval(function() { waitingForEffect = false; clearInterval(effectTimer); }, 50);
							
							elements.each(function () {
								if (settings.vertical)
								{
									animateTo($(this), 0, event.pageY - start, 50, true);
								}
								else
								{
									animateTo($(this), 0, event.pageX - start, 50, true);
								}
							});

							start = settings.vertical ? event.pageY : event.pageX;
						}
					});
					
					$('html').bind('mouseup', function () {
						$('html').unbind('mouseup');
						$('html').unbind('mousemove');
						
						var tempTimer = setInterval(function () {
						
							clearInterval(tempTimer);
							
							var cssAttr = settings.vertical ? 'top' : 'left';
							var elementSize = (settings.vertical ? slider.height() : slider.width()) / settings.nbElementsDisplayed;
							var currentPosition = parseFloat(elements.first().css(cssAttr));
							
							if (currentPosition > 0)
							{
								indexCurrent = 0;
								currentElement = $(elements[indexCurrent]);
								
								elements.each(function () {
									animateTo($(this), -currentPosition, 0);
								});
							}
							else if (-currentPosition > (elements.length - settings.nbElementsDisplayed) * elementSize)
							{
								indexCurrent = elements.length - settings.nbElementsDisplayed;
								currentElement = $(elements[indexCurrent]);
								
								elements.each(function () {
									animateTo($(this), -currentPosition, -(elements.length - settings.nbElementsDisplayed) * elementSize);
								});
							}
							else
							{
								var positionToMove = currentPosition % elementSize;
								indexCurrent = (positionToMove - currentPosition) / elementSize;
								currentElement = $(elements[indexCurrent]);
								
								if (-positionToMove > elementSize / 2)
								{
									++indexCurrent;
									currentElement = $(elements[indexCurrent]);
								}
								
								elements.each(function () {
									animateTo($(this), -currentPosition, -(indexCurrent) * elementSize);
								});
							}
							
						}, 100);
					});
					
					
				}
				
				return false;
			});
		}
		
		next.bind('click', function() {
			goToNext();
			clearInterval(timer);
			
			return false;
		});

		previous.bind('click', function() {
			goToPrevious();
			clearInterval(timer);
			
			return false;
		});
		
		var goToNext = function () {
			goTo(indexCurrent == elements.length - settings.nbElementsDisplayed ? 0 : indexCurrent + 1);
		};
		
		var goToPrevious = function () {
			goTo(indexCurrent == 0 ? elements.length - settings.nbElementsDisplayed : indexCurrent - 1);
		};
		
		var goTo = function (index) {
			if (index == indexCurrent || currentlyMoving)
				return;

			currentlyMoving = true;

			var previousElement = currentElement;
			
			indexCurrent = index;
			
			if (index >= elements.length - settings.nbElementsDisplayed)
				indexCurrent = elements.length - settings.nbElementsDisplayed;
			
			currentElement = $(elements[indexCurrent]);
			
			runTransition(previousElement, currentElement);
		};
		
		var runTransition = function (previousElement, currentElement) {
			switch (settings.transition) {
				case 'fade':
					runFade(previousElement, currentElement);
					break;
				case 'slide':
					runSlide(previousElement, currentElement);
					break;
				default :
					runToggle(previousElement, currentElement);
			}
		};
		
		var runFade = function (previousElement, currentElement) {
			previousElement.fadeOut(settings.effectDuration);
			currentElement.fadeIn(settings.effectDuration, function() { currentlyMoving = false; });
		};
		
		var runSlide = function (previousElement, currentElement) {
			if (settings.bidirectional)
			{
				var indexDiff = elements.index(previousElement) - elements.index(currentElement);
				
				elements.each(function () {
					if (settings.vertical)
					{
						animateTo($(this), 0, indexDiff * previousElement.height());
					}
					else
					{
						animateTo($(this), 0, indexDiff * previousElement.width());
					}
				});
			}
			else
			{
				if (settings.vertical)
				{
					currentElement.css('top', previousElement.height()).show();
					$([previousElement, currentElement]).each(function () {
						this.animate({ top: '-=' + previousElement.height() }, settings.effectDuration, function() { $(previousElement).hide(); $([previousElement, currentElement]).css('top', 0); currentlyMoving = false; })
					});
				}
				else
				{
					currentElement.css('left', previousElement.width()).show();
					$([previousElement, currentElement]).each(function () {
						this.animate({ left: '-=' + previousElement.width() }, settings.effectDuration, function() { $(previousElement).hide(); $([previousElement, currentElement]).css('left', 0); currentlyMoving = false; })
					});
				}
			}
		};
		
		var runToggle = function (previousElement, currentElement) {
			if (!settings.effectDuration)
			{
				previousElement.hide(false);
				currentElement.show(false);
				currentlyMoving = false;
			}
			else
			{
				previousElement.hide(settings.effectDuration);
				currentElement.show(settings.effectDuration, function () { currentlyMoving = false; });
			}
		};
		
		var animateTo = function (element, from, to, duration, continueMoving) {
			var sizeToScroll = from + to;
			var operateur = '+=';
			
			if (!duration)
				duration = settings.effectDuration;
			
			if (sizeToScroll < 0)
			{
				operateur = '-=';
				sizeToScroll = sizeToScroll * -1;
			}
			
			if (settings.vertical)
			{
				element.animate({ top: operateur + sizeToScroll }, duration, function() { if (!continueMoving) currentlyMoving = false; });
			}
			else
			{
				element.animate({ left: operateur + sizeToScroll }, duration, function() { if (!continueMoving) currentlyMoving = false; });
			}
		};
			
		// Init
		if (settings.transition != 'slide' || !settings.bidirectional)
			elements.hide();
	
		currentElement.show();

		if (autoStart)
			timer = setInterval(function() { goToNext(); }, settings.temporisation);
	});
};
