$(function () {
	Prolific.app('slideshow', function (slideshow) {
	
		//CONSTANTS
		var FADE_SPEED_IN = 400,
			FADE_SPEED_OUT = 400,
			SLIDE_SPEED = 400,
			AUTO_SCROLL = 4000,
			AUTO_PAUSE_TIMEOUT = 3000,
		
		//JQUERY CACHE
			$slideshow = $('#slideshow'),
			$slides = $slideshow.find('.slides li'),
			$slider = $slideshow.find('.slider'),
			$slider_nodelist = $slider.find('ul.nodes'),
			$slider_nodes = $slider_nodelist.find('li'),
			$slidepiece = $slider.find('.slidepiece'),
		
		//PRIVATE VARS
			_slides = [], //Holds the instantiated Slide()'s
			_curSlide = null, //The currently selected Slide()
			_sliderOffset = parseInt($slider_nodelist.css('margin-left')) - 11; //The pixel adjustment for the slider
			
		//PRIVATE METHODS
		
		//Spits out a surefire callback (if undefined is passed in, it returns an empty function )
		function _sureCallback (callback) {
			return callback || function () {};
		}
		
		//Fades any Slide() in. Not encapsulated to save memory.
		function _fadeIn (slide, callback) {
		
			//Animate it
			slide.getElement().animate({
				opacity: 1
			}, FADE_SPEED_IN, _sureCallback(callback));
			
			//Chain
			return slide;
		}
		
		//Fades any Slide() out. Not encapsulated to save memory.
		function _fadeOut (slide, callback) {
		
			//If it's already unselected, no need to do anything
			if (!slide.getElement().hasClass('selected')) {
				return slide;
			}
			
			//Animate it
			slide.getElement().animate({
				opacity: 0
			}, FADE_SPEED_OUT, _sureCallback(callback));
			
			//Chain
			return slide;
		}
		
		//CLASSES
		
		//A class that encapsulates showing, hiding, etc.
		slideshow.addClass('Slide', {
			init: function (specs) {
				var $el = $(specs.element),
					position = $el.prevAll().length,
					$sliderNode = $slider_nodes.eq(position),
					
					//slide is the instantiated object
					slide = {
						show: function () {
						
							//If it's already selected, no need to do anything
							if ($el.hasClass('selected')) {
								return this;
							}
							//Get it ready to fade in
							$el.css('opacity', 0).addClass('selected');
							
							//Hide the current slide
							_curSlide.hide();
							
							//Animate the slide						
							_fadeIn(this);
							
							//Use the generic moveTo method in the slider feature. Pass in the slider label, and callback.
							slideshow.slider.moveTo($sliderNode, function () {
								//Select this slide, unselected all the other ones
								$(this).addClass('selected').siblings().removeClass('selected');
								
							});
							
							//Updates the current slide reference
							_curSlide = this;
							
							//Chain
							return this;
						},
						hide: function () {
							//If it's not selected, no need to do anything
							if (!$el.hasClass('selected')) {
								return this;
							}
							
							//Fade it out
							_fadeOut(this, function () {
								$el.removeClass('selected');
							});
							
							//Chain
							return this;
						},
						getElement: function () {
						
							//Return the jQuery collection representing the slide
							return $el;
							
						},
						getSliderNode: function () {
						
							//Return the current slider label's node
							return $sliderNode;
							
						}
					};
					
				//If it's selected, set the currrent slide reference to the current one
				if ($el.hasClass('selected')) {
					_curSlide = slide;
				}
				
				//Hook up the click event on the slider label node
				$sliderNode.click(function () {
					
					//Change slides to this one
					slide.show();
					
					//Pause autoscroll momentarily
					slideshow.autoscroll.pause();
				});
				
				return slide;
			}
		});
	
		
		//Instantiate Slides
		$slides.each(function () {
		
			//Run through each slide list item and wrap it
			_slides.push(new slideshow.Slide({
				element: this
			}));
			
		});
	
		//FEATURES
		slideshow.feature('slider', function (slider) {
			slider.method('moveTo', function (node, callback) {
				var $node = $(node),
					left = $node.position().left - ($slidepiece.width() / 5);
				
				//Get the slidepiece to the newest item					
				$slidepiece.animate({
					left: left + 'px'
				}, SLIDE_SPEED, _sureCallback(callback).call(node));
				
				return node;
			});
			
		});
		
		slideshow.feature('autoscroll', function (autoscroll) {
			var _interval = null,
				_total = _curSlide.getElement().siblings().length + 1,
				_curIndex,
				_pauseTimeout = null,
				_paused = false;
			
			function nextSlide () {
				if (_paused) return;
				_curIndex++;
				if (_curIndex >= _total) {
					_curIndex = 0;
				}
				_slides[_curIndex].show();
			}
			
			autoscroll.method('start', function () {
				if (_interval) autoscroll.stop();
				_paused = false;
				_total = _curSlide.getElement().siblings().length + 1,
				_curIndex = _curSlide.getElement().prevAll().length;
				_interval = window.setInterval(nextSlide, AUTO_SCROLL);
				
				return this;
			});
			autoscroll.method('stop', function () {
				window.clearInterval(_interval);
				return this;
			});
			autoscroll.method('pause', function () {
				_paused = true;
				_pauseTimeout = window.setTimeout(function () {
					_paused = false;
					autoscroll.start();
				}, AUTO_PAUSE_TIMEOUT);
			});
			
			//Go
			autoscroll.start();
		});
		
		
	});
});