(function($) {
	$.fn.slider = function(options) {

		var defaults = {
			start: 0,
			delay: 1.5,
			autoPlay: true,
			jumpStart: true,
			activeClassName: "active",
			slideMethod: "fade",
			fadeSpeed: "fast",
			repeat: true,
			debug: false,
			buttons: {
				playpause: ".playpause"
				//play: ".play",
				//stop: ".stop",
				//next: ".next",
				//previous: ".previous"
			},
			container: {
				//main: ".slides",
				//shortcuts: ".shortcuts",
				//controller: ".controller"
			}
		};

		var options = $.extend(defaults, options);
		
		this.each(function() {
		
		var slider = $(this);

		buttons = {
			playpause: slider.find(options.buttons.playpause)
			//stop: slider.find(options.buttons.stop)
			//start: slider.find(options.buttons.start)
			//next: slider.find(options.buttons.next)
			//prev: slider.find(options.buttons.prev)
		};

		buttons.playpause.bind("click", function() {
			if(playing === true) 
			{
				if(options.debug) console.log(" == PAUSE ==");
				actionController("pause");
				
				removeClass = "stop";
				addClass = "play";
			}
			else
			{
				if(options.debug) console.log(" == PLAYING ==");

				if(options.jumpStart) 
				{
					if(options.debug) console.log("Jumpstarting..");
					actionController("next");
				}

				actionController("play");
				
				removeClass =  "play";
				addClass = "stop";
			}

			$(this).addClass(addClass);
			$(this).removeClass(removeClass);
		});

		/**
		 * @return int delay
		 */
		var getSlideDelay = function() {
			return options.delay * 1000;
		};

		/**
		 * Determines starting slide
		 * @return int starting slide index
		 */
		var getStartingSlide = function() 
		{
			if(options.start == "random") 
			{
				return Math.floor(Math.random()*slidesCount);
			}
			else if(options.start >= slidesCount) 
			{
				return (slidesCount - 1);
			}
			else if(options.start < 1) 
			{
				return 0;
			}
			else 
			{
				return options.start;
			}
		};

		/**
		 * @return int index of current slide
		 */
		var getCurrentSlideIndex = function() 
		{
			return (slider.children(".slide:visible").index() - 1);
		};

		/**
		 * @return int next slide index
		 */
		var getNextSlideIndex = function() 
		{
			if((getCurrentSlideIndex() + 1) == getSlidesCount())
			{
				if(options.repeat == true) 
				{
					if(options.debug === true) console.log("getNextSlideIndex(): returns 0 (repeat)");

					return 0;
				}
				else 
				{
					if(options.debug === true) console.log("getNextSlideIndex(): returns false (no repeat)");

					return false;
				}
			}
			else
			{
				return (getCurrentSlideIndex() + 1);
			}
		};

		/**
		 * @return int previous slide index
		 */
		var getPreviousSlideIndex = function() 
		{
			if(getCurrentSlideIndex() < 1)
			{
				if(options.repeat) 
				{
					return getSlidesCount();
				}
				else 
				{ 
					return false; 
				}
			}
			else
			{
				return getCurrentSlideIndex();
			}
		};

		/**
		 * @return int total slides count
		 */
		var getSlidesCount = function() 
		{
			return slider.children(".slide").length;
		};
		
		/**
		 * @return boolean 
		 */
		var slideIndexExists = function(slideIndex) 
		{
			if(slideIndex >= getSlidesCount() || slideIndex < 0) 
			{
				if(options.debug === true) console.log("slideIndexExists(): returned false");

				return false;
			}
			
			if(options.debug === true) console.log("slideIndexExists(): returned true");

			return true;
		};

		/**
		 * @param int slideIndex index to a slide
		 */
		var setSlide = function(slideIndex) 
		{
			switch(options.slideMethod)
			{
				case "fade":
				{
					fadeToSlide(slideIndex); break;
				}

				default:
				{
					gotoSlide(slideIndex); break;
				}
			}
		};

		/**
		 * The function for changing slides fade style using jQuery's .fadeIn/Out()
		 * @param int slideIndex 
		 */
		var fadeToSlide = function(slideIndex)
		{
			slider.children(".slide:visible").fadeOut(options.fadeSpeed, function() {
				slider.children(".slide:eq(" + slideIndex + ")").fadeIn(options.fadeSpeed);
			});
		};

		/**
		 * Changing slides instantly using jQuery's .hide()
		 * @param int slideIndex
		 */
		var gotoSlide = function(slideIndex) 
		{
			slider.children(".slide:visible").hide();
			slider.children(".slide:eq(" + slideIndex + ")").show();
		};

		/**
		 * All actions goes through here
		 * @param string action tell the program what do to
		 * @param int index [optional] if action is goto then an index is needed. note that index starts at 0.
		 *
		 * Examples:
		 * <code>
		 * actionController("next"); 
		 * actionController("goto", 1);
		 * </code>
		 */
		var actionController = function(action, index)
		{
			switch(action)
			{
				case "next":
				{
					nextSlideIndex = getNextSlideIndex();

					if(nextSlideIndex !== false)
					{
						if(options.debug === true) console.log("actionController(\"next\"): going " + nextSlideIndex);
						setSlide(nextSlideIndex);
					}
					else
					{
						if(options.debug === true) console.log("actionController(\"next\"): reached the end, quitting");

						actionController("pause");
					}

					break;
				}

				case "previous":
				{
					setSlide(getPreviousSlideIndex());
					
					break;
				}

				case "goto":
				{
					if(slideIndexExists(index))
					{
							setSlide(index);
					}

					break;
				}

				case "play":
				{
					if(options.debug === true) console.log("actionController(\"play\")");
					
					slider.everyTime(getSlideDelay(), function(timer) {
						actionController("next");
					});

					playing = true;

					break;
				}

				case "pause":
				{
					if(options.debug === true) console.log("actionController(\"pause\")");
					slider.stopTime();
					
					playing = false;

					break;
				}

				case "stop":
				{
					//Stop should technically stop the timer 
					//and go to the first slide but who wants that?

					break;
				}

				case "resetTimer":
				{
					if(options.debug === true) console.log("actionController(\"resetTimer\")");

					slider.stopTime();

					slider.everyTime(getSlideDelay(), function(timer) {
						actionController("next");
					});

					break;
				}
				
				default:
				{
					if(options.debug === true) console.log("actionController: unhandeled action");

					break;
				}
			}
		};

		/**
		 * We call this method last.
		 * It gathers all the starting functions and variables needed.
		 */
		(function() {
			
			var slides 	= slider.children(".slide");
			playing 	= (options.autoPlay) ? false : true;
			slidesCount = getSlidesCount();
			startSlide  = getStartingSlide();
			
			slides.each(function (i) {
				jQuery(this).removeClass("hidden");
			});

			if(options.debug) console.log("INIT: Going to starting slide: " + getStartingSlide());
			
			/* To prevent the item to fadeIn on page load */
			var slideMethod = options.slideMethod;
			options.slideMethod="";

			actionController("goto", getStartingSlide());
			
			options.slideMethod=slideMethod;
		
			if(options.autoPlay == true)
			{
				if(options.debug) console.log(" == AUTOSTART ==");
				
				actionController("play");
			}

		})();
		
			return this;

		});
	
	};

})(jQuery);
