/**
 * jQuery plugin for custom horizontal scroller.
 * Can be used on nodes structure like this:
 * <div class="scroller"><div class="leftArrow"/><div class="scroll"/><div class="rightArrow"/></div>
 * (classnames are locator examples and can be customized).
 * Proceeds scroll dragging and arrows pressing. Uses callback function, passing current scrollbar position
 * as percentage value into it. Also provides simple API.
 *
 * Usage example:
 *  var scrollbar = $.scrollbar($('.globalWrapper .navigationMenu .scroller'), {
 *    leftArrowLocator: '.leftArrow',
 *    scrollLocator: '.scroll',
 *    rightArrowLocator: '.rightArrow',
 *    onScrollMove: function (percentage) {
 *      self.$content.css('margin-left', $.px(-percentage * (self.$content.width() - $(window).width())));
 *    }
 *  });
 *
 * @author Grigory Bezyuk
 * @copyright Grigory Bezyuk (C)2009
 */

$.scrollbar = function ($scrollbar, params) {

  // passing default values for params
  if (!params) {
    params = {};
  }
  if (params.leftArrowLocator == undefined) {
    params.leftArrowLocator = '.leftArrow';
  }
  if (params.scrollLocator == undefined) {
    params.scrollLocator = '.scroll';
  }
  if (params.rightArrowLocator == undefined) {
    params.rightArrowLocator = '.rightArrow';
  }
  if (params.scrollSpeed == undefined) {
    params.scrollSpeed = 0.002;    // percentage step for arrows scrolling
  }
  var scrollSpeed = params.scrollSpeed;

  if (params.scrollAcceleration == undefined) {
    params.scrollAcceleration = 0.002;    // percentage step for arrows scrolling
  }
  var scrollAcceleration = params.scrollAcceleration;


  // nodes in HTML/XHTML
  var $scroll       = $scrollbar.find(params.scrollLocator);
  var $leftArrow    = $scrollbar.find(params.leftArrowLocator);
  var $rightArrow   = $scrollbar.find(params.rightArrowLocator);


  // flags for scroll dragging and arrows scrolling
  var draggingState = false;
  var draggingPoint = 0;
  var scrollingDirection = 0; // -1 for left scrolling, +1 for right scrolling


  // binding action listeners
  $leftArrow.mousedown(startLeftScroll);
  $(document).mouseup(finishLeftScroll);

  $rightArrow.mousedown(startRightScroll);
  $(document).mouseup(finishRightScroll);

  $scroll.mousedown(startScrollDragging);
  $(document).mousemove(proceedScrollDragging);
  $(document).mouseup(finishScrollDragging);


  // starting timer for arrows scrolling.
  // Scrolling starts when mouse is pressed on arrow node and continues until it's released
  setTimeout(proceedScroll, 100);

  // functions for arrow scrolling
  function startLeftScroll () {
    scrollingDirection = -1;
  }
  function startRightScroll () {
    scrollingDirection = 1;
  }
  function finishLeftScroll () {
    scrollingDirection = 0;
    scrollSpeed = params.scrollSpeed;
    scrollAcceleration = params.scrollAcceleration;
  }
  function finishRightScroll () {
    scrollingDirection = 0;
    scrollSpeed = params.scrollSpeed;
    scrollAcceleration = params.scrollAcceleration;
  }
  function proceedScroll () {
    if (scrollingDirection == 0) {
      setTimeout(proceedScroll, 100);
      return;
    }
    var scrollPosition = getScrollPosition() + scrollSpeed * scrollingDirection;
    scrollSpeed += scrollAcceleration;
    // scrollAcceleration *= 2;
    if (scrollPosition < 0 ) {
      scrollPosition = 0;
    }
    if (scrollPosition > 1 ) {
      scrollPosition = 1;
    }
    moveScrollToPosition(scrollPosition);
    setTimeout(proceedScroll, 100);
  }


  // functions for scroll dragging
  function startScrollDragging (e) {
    draggingState = true;
    draggingPoint = e.clientX - $scroll.offset().left;
    return false;
  }
  function finishScrollDragging (e) {
    draggingState = false;
    return false;
  }
  function proceedScrollDragging (e) {
    if (draggingState) {
      var newOffset = parseInt($scroll.css('left')) + e.clientX - $scroll.offset().left - draggingPoint;
      if (newOffset < $scrollbar.offset().left + $leftArrow.width()) {
        newOffset = $scrollbar.offset().left + $leftArrow.width();
      }
      if (newOffset > $rightArrow.offset().left - $scroll.width()) {
        newOffset = $rightArrow.offset().left - $scroll.width();
      }
      $scroll.css('left', newOffset);
      if (params.onScrollMove) {
        params.onScrollMove(
          (newOffset - $leftArrow.width())
            / ($scrollbar.width() - $leftArrow.width() - $rightArrow.width() - $scroll.width()));
      }
    }
    return false;
  }

  function moveScrollToPosition (percentage, animate) {
    if (animate) {
      $scroll.animate({'left': percentageToPixels(percentage)});
    }
    else {
      setPosition(percentage);
    }
    if (params.onScrollMove) {
      params.onScrollMove(percentage);
    }
  }

  // Returns scroll position as percentage
  function getScrollPosition () {
    return pixelsToPercentage($scroll.offset().left);
  }

  // Sets scroll position as percentage. No callback function is being called.
  function setPosition (percentage) {
    $scroll.css('left', percentageToPixels(percentage));
  }

  function percentageToPixels (percentage) {
    return $leftArrow.offset().left + $leftArrow.width()
            + percentage * ($scrollbar.width() - $scroll.width() - $leftArrow.width() - $rightArrow.width());
  }

  function pixelsToPercentage (pixels) {
    return (pixels - $leftArrow.width() - $leftArrow.offset().left)
            / ($scrollbar.width() - $scroll.width() - $leftArrow.width() - $rightArrow.width()); 
  }

  // Returning API
  return {
    setPosition: setPosition,
    percentageToPixels: percentageToPixels,
    pixelsToPercentage: pixelsToPercentage
  };
};
