/*
 *  Enhanced Easy Slider
 *
 *  Built off of the Easy Slider - jQuery plugin
 *  written by Alen Grakalic
 *  http://cssglobe.com/post/3783/jquery-plugin-easy-image-or-content-slider
 *
 *  enhancements by Joseph Pecoraro
 *  email: joepeck02@gmail.com
 *  http://blog.bogojoker.com
 *
 * Further enhanchments by Team SODA.
 *
 *
 *
 *  The Easy Slider Copyrights:
 *  Copyright (c) 2009 Alen Grakalic (http://cssglobe.com)
 *  Dual licensed under the MIT (MIT-LICENSE.txt)
 *  and GPL (GPL-LICENSE.txt) licenses.
 *
 *  Built for jQuery library
 *  http://jquery.com
 *
 */

/*
 *  Quick Documentation of New Features
 *
 *    * Non-Autogenerated Pagination - set the autogeneratePagination
 *      option to false in the easySlide options and be sure to provide
 *      id's in the prevId and nextId options.  Those provided ids will
 *      unobtrusively get the easySlide actions applied to them.
 *
 *    * Looping - just set the loop option to true in the easySlide
 *      options and you will be able to navigate forward/backward around
 *      the ends smoothly.
 *
 *    * Autoplay - just set the autoplayDuration to a non-zero value
 *      in the easySlide options and the content will slide on its own.
 *      The value you provide will only be the value between animations,
 *      so you don't have to compensate for the speed of transitions,
 *      that is handled automatically.  Autoplaying works fine with
 *      looping.
 *
 *      If you have pagination buttons, when the user clicks a button
 *      the autoplay will suspend for a little while.  The restartDuration
 *      value specifies the amount of time since the last user
 *      interruption to wait before restarting the autoplay.
 *
 *    * Hovering - just set hover to true and pagination will trigger
 *      when hovering instead of clicking.  The slides will continue to
 *      transition as long as you hover over the pagination element.
 *      Hovering works fine with looping.
 *
 *      If you want a pause between slides you can set the hoverPause
 *      value to an integer greater than 0.  That specifies the time
 *      to wait between transitions.
 *
 *    * Linear or Swing easing - jQuery offers two different styles
 *      of animations.  Just set the easing option to 'linear' or
 *      'swing' (default)and it will use that easing style.
 *
 *    * Pauseable - Pause autoplay by hovering over an image.  Likewise
 *      you can extend this to pause when hovering the buttons as well.
 *
 *    * Fade Orientation - Not Vertical or Horizontal Slideing, but Fading!
 *      Just provide orientation: 'fade' for fading to happen.
 *
 *    * Callbacks - You are allowed to provide your own functions for
 *      events triggered by the slider.  You can provide a function
 *      for 'beforeTransition' and 'afterTransition'.  Their signature
 *      is as follows:
 *
 *          function callback( slideNumber, jQuery_li, jQuery_ul )
 *                                 ^            ^         ^
 *                                 |            |         |
 *     int of the slide number -----            |         |
 *     jQuery wrapper for the now showing <li> --         |
 *     jQuery wrapper for the entire <ul> of all slides ---
 *
 *       For example, to get the explicit DOM <li> Node you could do
 *
 *          function after(num, $li, $ul) {
 *            dom_li = $li[0];
 *            console.log(dom_li);
 *          }
 *
 */

(function($) {

  $.fn.easySlider = function(options){

	// default configuration properties
	var defaults = {
	  prevId: 'prevBtn',             // id of the element to apply prev rules to
	  nextId: 'nextBtn',             // id of the element to apply next rules to
	  prevText: 'Previous',          // text for autogenerated prev link
	  nextText: 'Next',              // text for autogenerated next link
	  autogeneratePagination: false, // will automatically generate pagination links
	  orientation: '',               // 'vertical', 'fade', or anything else will assume horizontal
	  speed: 800,                    // duration of a transition
	  autoplayDuration: 0,           // auto-play if non-zero, this is the time between transitions
	  restartDuration: 2500,         // time to restart autoplay after a user interupts and autoplay
	  loop: false,                   // loop around the content
	  hoverPause: 0,                 // when hovering, the time between transitions
	  hover: false,                  // on hover instead of onclick
	  easing: null,                  // jQuery animation settings 'linear' or 'swing' (default)
	  pauseable: false,              // pause autoplay when hovering the image
	  pauseButtons: false,           // hovering over the cuttons will pause as well
	  beforeTransition: null,        // callback before transitioning
	  afterTransition: null,        // callback after transitioning
	  numeric: false,				 // enables numeric paging
	  numericId: 'controls',
	  showComment: false,
	  commentId: 'comments'			 // id of numeric paging data
	};

	var options = $.extend(defaults, options);

	return this.each(function() {

	  // Setup Measurements and Options
	  var obj = $(this),
		  totalSlides  = $("li", obj).length,
		  slideWidth   = obj.width(),
		  slideHeight  = obj.height(),
		  lastSlide    = totalSlides-1,
		  current      = 0;

	  // States
	  var vertical         = (options.orientation == 'vertical'),
		  fade             = (options.orientation == 'fade'),
		  horizontal       = (!vertical && !fade),
		  autogen          = options.autogeneratePagination,
		  pauseable        = options.pauseable,
		  loop             = options.loop,
		  speed            = options.speed,
		  easing           = options.easing,
		  hover            = options.hover,
		  hoverPause       = options.hoverPause,
		  buttonsPause     = options.pauseButtons,
		  restartDuration  = options.restartDuration,
		  autoplayDuration = Math.max(options.autoplayDuration,25)+speed,
		  autoplay         = (options.autoplayDuration > 0),
		  beforeTransition = options.beforeTransition,
		  afterTransition  = options.afterTransition;
		  interval         = null,
		  restart          = null,
		  numeric		   = options.numeric,
		  numericId		   = options.numericId,
		  showComment	   = options.showComment
		  commentId		   = options.commentId;

	  // Autogenerate Pagination
	  if (autogen) {

		  var numericHtml = "";
		  if (numeric) {
			  numericHtml = '<ol id="'+ options.numericId +'"></ol>';
		  }
		  $(obj).after( '<div id="slider-pag"><span id="'+options.prevId+'"><a href=\"javascript:void(0);\">'+options.prevText+'</a></span> '+
					  numericHtml +
					  '<span id="'+options.nextId+'"><a href=\"javascript:void(0);\">'+options.nextText+'</a></span></div>');
		  if (numeric) {
			  for(var i = 0; i < totalSlides; i++) {
					$(document.createElement("li"))
						.attr('id', options.numericId + (i+1))
						.html('<a rel='+ i +' href=\"javascript:void(0);\">'+ (i+1) +'</a>')
						.appendTo($("#"+ options.numericId))
						.click(function(){							
							if (autoplay) {
								pauseFunc();
								if ( !buttonsPause ) {
									restartFunc();
								}
							}
							animate($("a",$(this)).attr('rel'));
						}); 
			  }
			  $("ol#" + numericId + " > li:first").addClass("current");
		  }
			if (showComment) {
				$(obj).after("<span id=\"" + commentId + "\"></span>");
				$("#" + commentId).html($('ul > li:first img', obj).attr("alt"));
		  }
	  }

	  // Important Elements
	  var $ul   = $("ul", obj),
		  $next = $("#"+options.nextId),
		  $prev = $("#"+options.prevId);

	  // Loop - Duplicate the First Slide onto the end
	  if (loop) {
		$ul.append( $("li:first", obj).clone() );
		totalSlides += 1;
		lastSlide += 1;
	  }

	  // Horizontal - Make them float left and set the width of the ul (for all slides)
	  if (horizontal) {
		$("li", obj).css('float','left');
		$ul.css('width', totalSlides * slideWidth);
	  }

	  // Fade - Hide all but the first slide so they can fadeIn from nothing
	  if (fade) {
		$ul.find("li:not(:first)").hide();
	  }

	  // Reusable Closure to pause the autoplay timer
	  var pauseFunc = function() {
		clearInterval(interval);
		clearTimeout(restart);
	  }

	  // Reusable Closure to restart the autoplay timers using the restartDuration
	  var restartFunc = function() {
		restart = setTimeout(function() {
		  interval = setInterval(auto, autoplayDuration);
		}, restartDuration);
	  };

	  // Pauseable (should be autoplay only, but would have no effect otherwise)
	  // On Hover: cancel the autoplay timers
	  // On Leave: restart the autoplay timers
	  if ( pauseable && autoplay ) {
		$(obj).hover(pauseFunc, restartFunc);
		if ( buttonsPause ) {
		  $next.hover(pauseFunc, restartFunc);
		  $prev.hover(pauseFunc, restartFunc);
		}
	  }

	  // Add Actions to Next and Prev Buttons
	  // If Not Hover Mode made it click(), if it is Hover Mode, make it hover()
	  // When in autoplay mode make next/prev reset the autoplay timers
	  if ( !hover ) {

		$next.click(function(){
		  if (autoplay) {
			pauseFunc();
			if ( !buttonsPause ) {
			  restartFunc();
			}
		  };
		  animate("next");
		});

		$prev.click(function(){
		  if (autoplay) {
			pauseFunc();
			if ( !buttonsPause ) {
			  restartFunc();
			}
		  };
		  animate("prev");
		});

	  } else {

		var hoverNext = false,
			hoverPrev = false,
			isAnimating = false;

		$next.hover(
		  function() {
			var tfunc = arguments.callee;
			hoverNext = true;
			if ( !isAnimating ) {
			  isAnimating = true;
			  animate("next", function() {
				isAnimating = false;
				if ( hoverNext ) { tfunc(); }
			  });
			}
		  },
		  function() {
			hoverNext = false;
		  }
		);

		$prev.hover(
		  function() {
			var tfunc = arguments.callee;
			hoverPrev = true;
			if ( !isAnimating ) {
			  isAnimating = true;
			  animate("prev", function() {
				isAnimating = false;
				if ( hoverPrev ) { tfunc(); }
			  });
			}
		  },
		  function() {
			hoverPrev = false;
		  }
		);

	  }


	  //
	  // Enclosed Slide Animation
	  //
	  // This handles all of the sliding/faiding animation
	  // @param dir the direction "next" or "prev"
	  // @param cb the callback function
	  //
	  function animate(dir, cb) {

		// Before Transition, Guarantee
		if ( beforeTransition ) {
		  beforeTransition( current, $ul.find('li:eq('+current+')'), $ul );
		}


		// After Transition, Guarantee
		// Setup the next have
		// NOTE: That current will be the new value when this is called
		// due to it being a closure!
		var newcb = function() {
		  if ( cb != null ) {
			( hoverPause == 0 ) ? cb() : setTimeout(cb, hoverPause);
		  }
		  if ( afterTransition ) {
			afterTransition( current, $ul.find('li:eq('+current+')'), $ul );
		  }
		}



		// cur, nex, and update "current"
		// cur is the old current slide, the slide we are currently on
		// nex is the new current slide, the slide we are transitioning too
		// current is a global value that gets updated right here
		var cur = current;
		if ( loop ) {
		  if ( dir == 'next' ) {
			current = (current==lastSlide) ? 1 : current+1;
		  } else if ( dir == 'prev') {
			current = (current==0) ? lastSlide-1 : current-1;
		  } else if (!isNaN(dir)) {
			current = parseInt(dir);
		  }
		} else {
		  if (dir == "next") {
			current = (current>=lastSlide) ? lastSlide : current+1;
		  } else if ( dir == 'prev') {
			current = (current<=0) ? 0 : current-1;
		  } else if (!isNaN(dir)) {
			current = parseInt(dir);
		  }
		}
		var nex = current;


		//update the comment
		if (showComment) {
			$("#" + commentId).fadeOut("fast", function() {
				$(this).html($ul.find('li:eq('+current+') img').attr("alt")).fadeIn("fast");
			});
		}
		
		if (numeric) {
			$("ol#" + numericId + " > li").removeClass("current");
			var curHighlight = (current == lastSlide) ? 1 : current + 1;
			$("ol#" + numericId + " > li#" + numericId + curHighlight).addClass("current");
		}

		// Special Case for looping
		// If at the end and going forward, instantaneous jump to the first slide
		// If at the start and going backward, instantaneous jump to the last slide
		// NOTE: The instantaneous jump is an animate() so jQuery handles it in tune
		// with the rest of the animations, and is -1 (not 0) time so its instant.
		if ( loop ) {
		  if ( (dir == "next") && (cur == lastSlide) ) {
			(vertical) ?
			  $ul.animate({marginTop:0}, -1) :
			  $ul.animate({marginLeft:0}, -1);
		  } else if ( (dir == "prev") && (cur == 0) ) {
			(vertical) ?
			  $ul.animate({marginTop:(totalSlides-1)*slideHeight*-1}, -1) :
			  $ul.animate({marginLeft:(totalSlides-1)*slideWidth*-1}, -1);
		  }
		}


		// Dispatch jQuery Animation for the transition
		// Slide horizontally, vertically, or fade
		if ( horizontal ) {
		  $ul.animate( { marginLeft: (nex*slideWidth*-1)  }, speed, easing, newcb );
		} else if ( vertical ) {
		  $ul.animate( { marginTop:  (nex*slideHeight*-1) }, speed, easing, newcb );
		} else {
		  var curli = 'li:eq(' + cur + ')';
		  var nexli = 'li:eq(' + nex + ')';
		  $ul.find(curli).fadeOut("slow", function() {
			$ul.find(nexli).fadeIn("slow", newcb);
		  });
		}




		// Correctly show the Next/Prev links
		// When looping they always show, so we can ignore that
		// If at the end, hide the next link
		// If at the start, hide the previous link
		// Any other case we can show both links
		if ( !loop ) {
		  if ( nex <= 0 ) {
			$prev.fadeOut();
		  } else if ( nex >= lastSlide ) {
			$next.fadeOut();
		  } else {
			$next.fadeIn();
			$prev.fadeIn();
		  }
		}

	  };


	  //
	  // Autoplay
	  //
	  // Note that autoplayDuration already has the transitionDuration
	  // added to it (to prevent doing the addition over and over).
	  // However that means that the first invokation would take
	  // autoplayDuration+transitionDuration.  We remove that extra
	  // wait by first doing a single setTimeout with the correct
	  // time, followed by the correct setInterval.
	  //
	  if ( autoplay ) {
		var auto = function() {
		  animate('next');
		  if ( !loop && current>=lastSlide ) {
			clearInterval(interval);
		  }
		}
		restart = setTimeout(function() {
		  auto();
		  interval = setInterval(auto, autoplayDuration);
		}, autoplayDuration-speed);
	  }


	  // Initially Hide both buttons
	  $next.hide();
	  $prev.hide();

	  // Finally, Display the Next Link if more then one slide
	  if (totalSlides>1) {
		$next.fadeIn();
		if(loop) { $prev.fadeIn(); }
	  }

	});

  };

})(jQuery);