/*
 * 	Easy Slider 1.7 - jQuery plugin
 *	written by Alen Grakalic	
 *	http://cssglobe.com/post/4004/easy-slider-15-the-easiest-jquery-plugin-for-sliding
 *
 *	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
 *
 */
 
/*
 *	markup example for $("#slider").easySlider();
 *	
 * 	<div id="slider">
 *		<ul>
 *			<li><img src="images/01.jpg" alt="" /></li>
 *			<li><img src="images/02.jpg" alt="" /></li>
 *			<li><img src="images/03.jpg" alt="" /></li>
 *			<li><img src="images/04.jpg" alt="" /></li>
 *			<li><img src="images/05.jpg" alt="" /></li>
 *		</ul>
 *	</div>
 *
 */

(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: '',          // text for autogenerated prev link
      nextText: '',              // text for autogenerated next link
      autogeneratePagination: true, // will automatically generate pagination links
      orientation: 'fade',               // 'vertical', 'fade', or anything else will assume horizontal
      speed: 2000,                    // duration of a transition
      autoplayDuration: 5000,           // auto-play if non-zero, this is the time between transitions
      restartDuration: 2000,         // time to restart autoplay after a user interupts and autoplay
      loop: true,                   // 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: true,              // 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);



