/*
* 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
*
* 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
 };

 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;

 // Autogenerate Pagination
 if (autogen) {
 $(obj).after( '<span id="'+options.prevId+'"><a href=\"javascript:void(0);\">'+options.prevText+'</a></span> '+
 '<span id="'+options.nextId+'"><a href=\"javascript:void(0);\">'+options.nextText+'</a></span>');
 }

 // 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 {
 current = (current==0) ? lastSlide-1 : current-1;
 }
 } else {
 if (dir == "next") {
 current = (current>=lastSlide) ? lastSlide : current+1;
 } else {
 current = (current<=0) ? 0 : current-1;
 }
 }
 var nex = 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);
