/*
 *  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.
 *
 */

(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', or anything else will assume horizontal
      speed: 1500,                    // duration of a transition
      autoplayDuration:  500,           // auto-play if non-zero, this is the time between transitions
      restartDuration: 500,         // 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: 'swing'                   // jQuery animation settings 'linear' or 'swing' (default)
    };

    var options = $.extend(defaults, options);

    return this.each(function() {

      // Setup Measurements and Options
      var obj = $(this);
      var totalSlides  = $("li", obj).length;
      var slideWidth   = obj.width();
      var slideHeight  = obj.height();
      var lastSlide    = totalSlides-1;
      var current      = 0;

      // States
      var vertical         = (options.orientation == 'vertical');
      var autogen          = options.autogeneratePagination;
      var loop             = options.loop;
      var speed            = options.speed;
      var easing           = options.easing;
      var hover            = options.hover;
      var hoverPause       = options.hoverPause;
      var restartDuration  = options.restartDuration;
      var autoplayDuration = Math.max(options.autoplayDuration,25)+speed;
      var autoplay         = (options.autoplayDuration > 0);
      var interval         = null;
      var 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);
      var $next = $("#"+options.nextId);
      var $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 (!vertical) {
        $("li", obj).css('float','left');
        $ul.css('width', totalSlides * slideWidth);
      }

      // Add Actions to Next and Prev Buttons
      if ( !hover ) {

        $next.click(function(){
          if (autoplay) {
            clearInterval(interval);
            clearTimeout(restart);
            restart = setTimeout(function() {
              interval = setInterval(auto, autoplayDuration)
            }, restartDuration);
          };
          animate("next");
          if (current>=lastSlide && !loop) $(this).fadeOut();
          $prev.fadeIn();
        }).hide();
        $prev.click(function(){
          if (autoplay) {
            clearInterval(interval);
            clearTimeout(restart);
            restart = setTimeout(function() {
              interval = setInterval(auto, autoplayDuration)
            }, restartDuration);
          };
          animate("prev");
          if (current<=0 && !loop) $(this).fadeOut();
          $next.fadeIn();
        }).hide();

      } else {

        var hoverNext = false;
        var hoverPrev = false;
        var 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;
          }
        ).hide();

        $prev.hover(
          function() {
            var tfunc = arguments.callee;
            hoverPrev = true;
            if ( !isAnimating ) {
              isAnimating = true;
              animate("prev", function() {
                isAnimating = false;
                if ( hoverPrev ) { tfunc(); }
              });
            }
          },
          function() {
            hoverPrev = false;
          }
        ).hide();

      }

      // Enclosed Slide Animation
      function animate(dir, cb){

        // Special Case for looping
        if ( loop ) {
          if (dir == "next") {
            if ( current == lastSlide ) {
              (vertical) ? $ul.css('marginTop',0) : $ul.css('marginLeft',0);
              current = 1;
            } else {
              current += 1;
            }
          } else {
            if ( current == 0 ) {
              (vertical) ? $ul.css('marginTop',(totalSlides-1)*slideHeight*-1) : $ul.css('marginLeft',(totalSlides-1)*slideWidth*-1);
              current = lastSlide-1;
            } else {
              current -= 1;
            }
          }
        }

        // No Loops
        else {
          if (dir == "next") {
            current = (current>=lastSlide) ? lastSlide : current+1;
          } else {
            current = (current<=0) ? 0 : current-1;
          }
        }

        // The Callback
        var newcb = cb;
        if ( cb != null && hoverPause > 0 ) {
          newcb = function() { setTimeout(cb, hoverPause); }
        }

        // Dispatch jQuery Animation
        if(!vertical) {
          $ul.animate( { marginLeft: (current*slideWidth*-1) }, speed, easing, newcb);
        } else {
          $ul.animate( { marginTop: (current*slideHeight*-1) }, speed, easing, newcb);
        }

      };

      //
      // 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);
          }
        }
        setTimeout(function() {
          auto();
          interval = setInterval(auto, autoplayDuration);
        }, autoplayDuration-speed);
      }

      // Finally, Display the Next Link if more then one slide
      if (totalSlides>1) {
        $next.fadeIn();
        if(loop) { $prev.fadeIn(); }
      }

    });

  };

})(jQuery);
