(function( jQuery ) {

	jQuery.fn.slider = function(options) {
		var thisObj = this;
		var settings = {
			// Dimensions
			'width'		 :   this.width(),
			'height'		:   this.height(),
			// Settings
			'wait'		  :   4000,
			'fade'		  :   750,
			'direction'	 :   'left',
			'showControls'  :   true,
			'showProgress'  :   true,
			'hoverPause'	:   true,
			'autoplay'	  :   true,
			// Callbacks
			'slidebefore'   :   function() {},
			'slideafter'	:   function() {},
			'rewind'		:   function() {}
		};

		var _timer = false;
		var _last = false;
		var _this = false;
		
		var _cycle = function() {
			clearTimeout(_timer);

			_last = _this;

			if (settings.direction == 'right') {
				_this = _this.prev('.jquery-slider-element');
			} else {
				_this = _this.next('.jquery-slider-element');
			}

			if (!_this.length) {
				_rewind();
			}
			
			_draw();

			if (!thisObj.hasClass('jquery-slider-paused') && settings.autoplay) {
				_timer = setTimeout(_cycle, settings.wait);
			}
		};

		var _rewind = function() {
			if (settings.direction == 'right') {
				_this = thisObj.children('.jquery-slider-element').last();
			} else {
				_this = thisObj.children('.jquery-slider-element').first();
			}
			settings.rewind(_this, thisObj);
		};

		var _draw = function() {
			thisObj.addClass('jquery-slider-sliding');
			if (settings.showProgress) {
				thisObj.find('.jquery-slider-page').removeClass('jquery-slider-page-current');
				thisObj.find('.jquery-slider-page:nth-child(' + (_this.nextAll('.jquery-slider-element').length + 1) + ')').addClass('jquery-slider-page-current');
			}
			settings.slidebefore(_this, thisObj);

			if (settings.direction == 'right') {
				_this.show().css('left', -settings.width);
			} else {
				_this.show().css('left', settings.width);
			}
			
			_this.stop(true, true).animate({
				'left'	  :   (settings.direction == 'right' ? '+=' : '-=') + settings.width + 'px'
			}, {
				'duration'  :   settings.fade,
				'complete'  :   function() {
					settings.slideafter(_this, thisObj);
					thisObj.removeClass('jquery-slider-sliding');
				}
			});
			if (_last) {
				_last.stop(true, true).animate({
					'left'	  :   (settings.direction == 'right' ? '+=' : '-=') + settings.width + 'px'
				}, {
					'duration'  :   settings.fade
				});
			}
		};

		var _next = function() {
			if (thisObj.hasClass('jquery-slider-sliding')) return;
			var direction = settings.direction;
			thisObj.addClass('jquery-slider-paused');
			settings.direction = 'left';
			_cycle();
			settings.direction = direction;
		};

		var _prev = function() {
			if (thisObj.hasClass('jquery-slider-sliding')) return;
			var direction = settings.direction;
			thisObj.addClass('jquery-slider-paused');
			settings.direction = 'right';
			_cycle();
			settings.direction = direction;
		};

		var _init = function() {
			if (options) {
				jQuery.extend( settings, options );
			}
			if (settings.hoverPause) {
				thisObj.bind({
					'mouseenter': function() {
						thisObj.addClass('jquery-slider-paused')
						clearTimeout(_timer);
					},
					'mouseleave': function() {
						thisObj.removeClass('jquery-slider-paused');
						if (settings.autoplay) {
							_timer = setTimeout(_cycle, settings.wait);
						}
					}
				});
			}

			var positionEls = jQuery('<span class="jquery-slider-pages"></span>');
			thisObj.addClass('jquery-slider').width(settings.width).height(settings.height);
			thisObj.children().each(function() {
				_this = jQuery(this).addClass('jquery-slider-element');
				positionEls.append('<span class="jquery-slider-page"></span>');
			});

			if (settings.showProgress) {
				thisObj.append(positionEls);
			}

			if (settings.showControls) {
				var controlPrev = jQuery('<span class="jquery-slider-control jquery-slider-control-prev">&laquo;</span>').bind('click', function() {_prev();});
				var controlNext = jQuery('<span class="jquery-slider-control jquery-slider-control-next">&raquo;</span>').bind('click', function() {_next();});
				thisObj.append(controlPrev);
				thisObj.append(controlNext);
			}

			_cycle();
		};

		_init();
	};

})( jQuery );
