/*
 * jQuery Slider
 * author:     Johannes Wüller
 * created on: 08.10.2009
 *
 * This sliding-mechanism is capable of scrolling the content by moving the
 * mouse over certain areas or holding certain buttons pressed.
 *
 * Usage:
 *    jQuery('.slider').mediaSlider(options);
 *
 * Options:
 *    [selector] leftButton   scroll to the left on mousedown.
 *    [selector] rightButton  scroll to the right on mousedown.
 *    [selector] leftArea     scroll to the left on mouseover.
 *    [selector] rightArea    scroll to the right on mouseover.
 *    [integer]  buttonSpeed  scrolling speed when clicking buttons.
 *    [integer]  areaSpeed    scrolling speed when hovering areas.
 *    [float]    falloff      scrolling fall off.
 *    [string]   falloffType  'linear' or 'exponential'.
 *    [bool]     continuous   wether the slider should be endless scrollable
 *    [bool]     autoScroll   wether the slider should scroll automatically
 *                            (only works if continuous is true)
 *    [integer]  autoSpeed    scrolling speed when automated scrolling is active
 *    [selector] entry        .find() selector to determine auto scrolling
 */
jQuery.fn.mediaSlider = function(options) {
   
   /*
    * options
    */
   var defaults = {
      buttonSpeed: 20,
      areaSpeed:   5,
      falloff:     0.93,
      falloffType: 'exponential',
      continuous:  false,
      autoScroll:  false,
      autoSpeed:   1
   };
   options = jQuery.extend(defaults, options);
   
   /*
    * slider
    */
   jQuery(this).each(function () {
      
      /*
       * variables
       */
      var velocity         = 0;            // how fast we are moving
      var velocityInterval = false;        // reference to animation interval
      var slider           = jQuery(this); // reference to this at entry point
      var slideOut         = false;        // wether to apply the falloff
      
      /*
       * functions
       */
      // actual animation
      var applyVelocity = function () {
         if (slideOut) {
            velocity = applyFalloff(velocity);
         }
         var newPos = slider[0].scrollLeft + parseInt(velocity);
         if (options.continuous) {
            var entries = slider.find(options.entry);
            var entryWidth = jQuery(entries[0]).outerWidth(true);
            if (newPos > entryWidth) {
               newPos -= entryWidth;
               var element = jQuery(entries[0]);
               jQuery(entries[entries.length - 1]).after(element.clone());
               element.remove();
            }
            if (newPos < 0) {
               newPos += entryWidth;
               var element = jQuery(entries[entries.length - 1]);
               jQuery(entries[0]).before(element.clone());
               element.remove();
            }
         }
         slider[0].scrollLeft = newPos;
         if (slideOut && velocity == 0) {
            slideOut = false;
            velocity = 0;
            clearVelocityInterval();
         }
      };
      
      // create animation interval
      var setVelocityInterval = function () {
         slideOut = false;
         clearVelocityInterval();
         velocityInterval = window.setInterval(function(){
            applyVelocity();
         }, 39); // ~60fps
      };
      
      // remove animation interval
      var clearVelocityInterval = function () {
         window.clearInterval(velocityInterval);
         velocityInterval = false;
      };
      
      // enable fall off
      var stopSliding = function () {
         slideOut = true;
      };
      
      // calculate fall off
      var applyFalloff = function(velocity) {
         if (options.falloffType == 'exponential') {
            if (velocity != 0) {
               velocity *= options.falloff;
               if (parseInt(velocity) == 0) {
                  velocity = 0;
               }
            }
         } else if (options.falloffType == 'linear') {
            if (velocity < 0) {
               velocity += options.falloff;
               if (velocity > 0) {
                  velocity = 0;
               }
            } else if (velocity > 0) {
               velocity -= options.falloff;
               if (velocity < 0) {
                  velocity = 0;
               }
            }
         }
         return velocity;
      };
      
      /*
       * bindings
       */
      if (options.leftButton && !options.autoScroll) {
         jQuery(options.leftButton).mousedown(function () {
            velocity = options.buttonSpeed * -1;
            setVelocityInterval();
         }).mouseup(function () {
            stopSliding();
         }).hover(function () {}, function () {
            stopSliding();
         });
      }
      if (options.rightButton && !options.autoScroll) {
         jQuery(options.rightButton).mousedown(function () {
            velocity = options.buttonSpeed;
            setVelocityInterval();
         }).mouseup(function () {
            stopSliding();
         }).hover(function () {}, function () {
            stopSliding();
         });
      }
      if (options.leftArea && !options.autoScroll) {
         jQuery(options.leftArea).hover(function () {
            velocity = options.areaSpeed * -1;
            setVelocityInterval();
         }, function () {
            stopSliding();
         });
      }
      if (options.rightArea && !options.autoScroll) {
         jQuery(options.rightArea).hover(function () {
            velocity = options.areaSpeed;
            setVelocityInterval();
         }, function () {
            stopSliding();
         });
      }
      
      /*
       * automated sliding
       */
      if (options.continuous && options.autoScroll && options.autoSpeed && options.entry) {
         velocity = options.autoSpeed;
         setVelocityInterval();
      }
   
   });
   
}; 


