/**
 *  Script  : über-scroller
 *  Version : 1.0
 *
 *
**/

var scrollHandler   = new Array();
var scrollBars      = new Array(); // needed for indicators
var scrollWheelName = null;
var scrollMarker    = 0;

var scrollBarsAutoHide            = true;
var scrollDefaultIndicatorColor   = null; // '#505050';

/** scrollObject()
 *
 *  sourceObject      The object that is initiating the scroll (e.g. onmouseover="scrollObject(this, etc.);")
 *  scrollName        The name of the scroller; only pass the name before "-wrap" 
 *  scrollDirection   up, down, left, right
 *  hoverSpeed        1 - 10 (fastest); set to 0 to not scroll onmouseover
 *  clickSpeed        1 - 10 (fastest); set to 0 to not do anything special onmousedown
 *
**/
function scrollObject(sourceObject, scrollName, scrollDirection, hoverSpeed, clickSpeed) {

  var scrollThis    = document.getElementById(scrollName + '-wrap');

  if( scrollThis ) {

    // Calculate the speed this scroll will operate at
    var hoverInterval   = scrollInterval(hoverSpeed, 7);
    var clickInterval   = scrollInterval(clickSpeed, 10);

    // Get the object that is causing this scroll and set
    // a unique marker to identify this scroll action
    var scrollSource    = sourceObject ? sourceObject.id : null;
        scrollMarker++;


    // Set the scroller values that will be used
    scrollHandler[scrollMarker]               = scrollHandler[scrollMarker] != undefined ?
                                                scrollHandler[scrollMarker] : new Array();
    scrollHandler[scrollMarker]['scrollname'] = scrollName;
    scrollHandler[scrollMarker]['object']     = scrollThis;
    scrollHandler[scrollMarker]['direction']  = scrollDirection;
    scrollHandler[scrollMarker]['start-y']    = scrollThis.scrollTop;
    scrollHandler[scrollMarker]['current-y']  = scrollThis.scrollTop;
    scrollHandler[scrollMarker]['start-x']    = scrollThis.scrollLeft;
    scrollHandler[scrollMarker]['current-x']  = scrollThis.scrollLeft;

    // This function can be commented out if a scrollbar is not desired
    scrollIndicator(scrollMarker);

    // If the scroller does not need to do anything but collect
    // it's information and set the indicator, stop things here.
    if( scrollSource   == null ) { return scrollMarker; }


    // See if the scroller should scroll onmouseover (hoverInterval)
    scrollHandler[scrollMarker]['hover']      =
      hoverInterval != 0 ? setInterval('scrollObjectOn(\'' + scrollMarker + '\')', hoverInterval) : false;


    // Look for onmousedown events
    sourceObject.onmousedown = function() {
      scrollHandler[scrollMarker]['click']    =
        clickInterval != 0 ? setInterval('scrollObjectOn(\'' + scrollMarker + '\')', clickInterval) : false;

    } // ! onmousedown

    // Look for onmouseup events
    sourceObject.onmouseup  = function() {
      scrollObjectOff(scrollMarker, 'click');

    } // ! onmouseup


    // If the mouse leaves the source object, stop everything
    sourceObject.onmouseout = function() {
      scrollObjectOff(scrollMarker);

    } // ! onmouseout

  } // ! valid scroll wrapper?


} // ! scrollObject()



/** scrollInterval()
 *
 *  Calculate the time interval at which a scroller should
 *  run (based on a speed declaration of 0 through 10).
 *
**/
function scrollInterval(speedValue, defaultSpeed) {

  speedValue        = speedValue == undefined ? defaultSpeed : speedValue;
  var timeInterval  = typeof(speedValue) == 'number' &&
                      speedValue >= 1 &&
                      speedValue <= 10 ? 101 - (speedValue * 10) : 0;

  return timeInterval;

} // ! scrollInterval()




/** scrollMouseTracker
 *
 *  This function tracks mouse movement when a scroll indicator is
 *  grabbed. It will update the scroller according to movement.
 *
**/
function scrollMouseTracker(scrollMark) {

  document.onmousemove = function(scrollMouseTrack) {

    if( !scrollMouseTrack ) {
      var scrollMouseTrack = window.event;
    }

    // Get the current mouse position. It doesn't have to be
    // exact as relative measurements will be used.
    var scrollMouseY    = scrollMouseTrack.pageY ?
                          scrollMouseTrack.pageY : (scrollMouseTrack.clientY + document.body.scrollTop + document.documentElement.scrollTop);

    scrollBars[scrollMark]['mouse-y'] = scrollMouseY;

    scrollBars[scrollMark]['click-y'] = scrollBars[scrollMark]['click-y'] != null ?
                                        scrollBars[scrollMark]['click-y'] : scrollMouseY;

    scrollBars[scrollMark]['indicator-y-start'] = scrollBars[scrollMark]['indicator-y-start'] != null ?
                                                  scrollBars[scrollMark]['indicator-y-start'] :
                                                  scrollBars[scrollMark]['indicator-y'].style.top.replace('px', '') * 1;

    // Change the position of the indicator depending on the drag
    if( scrollMouseY != scrollBars[scrollMark]['click-y'] ) {

      var scrollMouseChangeY  = scrollMouseY - scrollBars[scrollMark]['click-y'];

      var indicatorTopY       = scrollBars[scrollMark]['indicator-y-start'];
      var indicatorTopMax     = scrollBars[scrollMark]['indicator-y-stop'];

      var indicatorNewY       = indicatorTopY + scrollMouseChangeY;
          indicatorNewY       = indicatorNewY < 0 ? 0 : indicatorNewY;
          indicatorNewY       = indicatorNewY > indicatorTopMax ? indicatorTopMax : indicatorNewY;

      scrollBars[scrollMark]['indicator-y'].style.top = indicatorNewY + 'px';

      // Scroll the content acording to the new position of the indicator
      // Start by getting the percentage that the indicator has been moved
      var indicatorPercentY   = Math.ceil((indicatorNewY * 100) / (scrollBars[scrollMark]['scrollbar-y-size'] - scrollBars[scrollMark]['indicator-y-size']));
      var contentPixelsY      = Math.ceil(scrollBars[scrollMark]['total-y'] * (indicatorPercentY / 100));

      // Move the content to it's new position
      scrollHandler[scrollBars[scrollMark]['lastmark']]['object'].scrollTop = contentPixelsY;

      // Sometimes dragging the scrollbars will result in a selection
      // being made (e.g. text). This clears it in most browsers.
      if( document.selection && document.selection.empty ) {
        document.selection.empty();
        if( scrollIndicator.parentNode ) {
          scrollIndicator.parentNode.blur();
        }
      } else if( window.getSelection ) {
        window.getSelection().removeAllRanges();
      }

    } // ! change in movement?

  } // ! onmousemove?

  document.onmouseup = function() {

    document.onmousemove              = null;
    scrollBars[scrollMark]['click-y'] = null;
    scrollBars[scrollMark]['indicator-y-start'] = null;

  }

} // ! scrollMouseTracker()




/** scrollIndicator()
 *
 *  Check (or create) the scroll indicator for a given scroll object.
 *  This function is only needed if a scroll indicator is desired. 
 *
**/
function scrollIndicator(scrollMark) {

  var scrollData        = scrollHandler[scrollMark];

  if( scrollData ) {

    var scrollName      = scrollHandler[scrollMark]['scrollname'];
    var scrollThis      = scrollHandler[scrollMark]['object'];

    // Load the content object so data can be read from it
    var scrollContent   = document.getElementById(scrollName + '-content');

    if( scrollContent ) {

      // Get information about the vertical scrollbar (if it exists)
      var scrollBarY    = scrollBars[scrollName] && scrollBars[scrollName]['scrollbar-y'] ?
                          scrollBars[scrollName]['scrollbar-y'] : document.getElementById(scrollName + '-bar-y');

      if( scrollBarY ) {

        // Do not built a new object if it already exists
        scrollBars[scrollName]  = scrollBars[scrollName] != undefined ?
                                  scrollBars[scrollName] : new Array();

        // Detect how much space that can be scrolled
        var wrapperHeight = scrollThis.clientHeight     ? scrollThis.clientHeight     : scrollThis.offsetHeight;
        var contentHeight = scrollContent.clientHeight  ? scrollContent.clientHeight  : scrollContent.offsetHeight;
        var scrollAmountY = contentHeight - wrapperHeight;

        scrollBars[scrollName]['total-y']    = scrollAmountY;
        scrollBars[scrollName]['wrapper-y']  = wrapperHeight;
        scrollBars[scrollName]['content-y']  = contentHeight;

        scrollBars[scrollName]['lastmark']   = scrollMark;

        var scrollIndicatorY  = scrollBars[scrollName]['indicator-y'] ?
                                scrollBars[scrollName]['indicator-y'] : document.getElementById(scrollName + '-indicator-y');

        if( !scrollIndicatorY ) {

          var newIndicatorY   = document.createElement('div');
              newIndicatorY.setAttribute('id', scrollName + '-indicator-y');
              newIndicatorY.style.position = 'relative';
              newIndicatorY.style.width    = '100%';

          scrollBarY.appendChild(newIndicatorY);

          scrollIndicatorY    = document.getElementById(scrollName + '-indicator-y');

        } // ! new indicator?

        scrollBars[scrollName]['scrollbar-y']  = scrollBarY;
        scrollBars[scrollName]['indicator-y']  = scrollIndicatorY;

        // Get data about the scrollbar
        var scrollBarHeightY      = scrollBarY.clientHeight ? scrollBarY.clientHeight : scrollBarY.offsetHeight;

        var scrollPercentY        = Math.floor((wrapperHeight * 100) / contentHeight);
        var scrollIndicatorSizeY  = Math.floor(scrollBarHeightY * (scrollPercentY / 100));
            scrollIndicatorSizeY  = scrollIndicatorSizeY < 10 ? 10 : scrollIndicatorSizeY;

        // If the indicator already has a height set, do not adjust it
        var indicatorManualSizeY  = scrollIndicatorY.clientHeight ?
                                    scrollIndicatorY.clientHeight : scrollIndicatorY.offsetHeight;

        scrollIndicatorSizeY      = indicatorManualSizeY ? indicatorManualSizeY : scrollIndicatorSizeY;

        scrollBars[scrollName]['scrollbar-y-size']  = scrollBarHeightY;
        scrollBars[scrollName]['indicator-y-size']  = scrollIndicatorSizeY;
        scrollBars[scrollName]['indicator-y-stop']  = scrollBarHeightY - scrollIndicatorSizeY;

        // Start monitoring the indicator for grabbing
        scrollIndicatorY.onmousedown = function() {

          // Start tracking the mouse position to calculate movements
          scrollMouseTracker(scrollName);

        } // ! onmousedown (grab)


        var scrollArrowUp         = document.getElementById(scrollName + '-up');
        var scrollArrowDown       = document.getElementById(scrollName + '-down');

        if( scrollBarsAutoHide == true && scrollAmountY < 1 ) {
          // Hide the scrollbars if this is enabled and there
          // is no content that needs to be scrolled.

          if( scrollArrowUp ) {
            scrollArrowUp.style.display = 'none';
          }
          if( scrollArrowDown ) {
            scrollArrowDown.style.display = 'none';
          }

          scrollBarY.style.display  = 'none';
          return true;

        // ! auto-hide scrollbars?
        } else {
          scrollBarY.style.display  = 'block';
          scrollArrowUp.style.display = 'block';
          scrollArrowDown.style.display = 'block';
          return true;
        }

        // Set the indicator to it's values
        //scrollIndicatorY.style.height           = scrollIndicatorSizeY + 'px';

        if( scrollDefaultIndicatorColor ) {
          scrollIndicatorY.style.backgroundColor  = scrollDefaultIndicatorColor;
        }

      } // ! any scrollbar?

    } // ! scroll content?

  } // ! valid scroller?

} // ! scrollIndicator()




/** scrollObjectOn
 *
 *  This is the function that actually scrolls the content
 *
**/
function scrollObjectOn(scrollMark, scrollAmount) {

  var scrollData      = scrollHandler[scrollMark];
  var scrollName      = scrollData['scrollname'];
  var scrollThis      = scrollData['object'];
  var scrollDirection = scrollData['direction'];

      scrollAmount    = scrollAmount == undefined ? 2 : scrollAmount;

  switch(scrollDirection) {
  case 'down':
    scrollThis.scrollTop += 2;

  break;
  case 'up':
    scrollThis.scrollTop -= 2;

  break;
  default:
    // no scrolling...
  }

  // If the scroller reaches the end (vertical/y), stop the scrolling
  // This is accomplished by checking if scrollTop is the same as last pass
  if( scrollThis.scrollTop == scrollHandler[scrollMark]['current-y'] ) {
    scrollObjectOff(scrollMark);

  } // ! end?

  scrollHandler[scrollMark]['current-y'] = scrollThis.scrollTop;
  scrollHandler[scrollMark]['current-x'] = scrollThis.scrollLeft;


  /*
  This section can be taken out if a scrollbar is not desired
  */

  // Get the percentage that has been scrolled, and move the
  // indicator accordingly (if there is an indicator).
  if( scrollBars[scrollName]['indicator-y'] ) {

    var scrollPercentY        = Math.ceil((scrollHandler[scrollMark]['current-y'] * 100) / scrollBars[scrollName]['total-y']);
    var scrollMoveIndicatorY  = Math.ceil((scrollBars[scrollName]['scrollbar-y-size'] - scrollBars[scrollName]['indicator-y-size']) * (scrollPercentY / 100));

    if( scrollMoveIndicatorY <= scrollBars[scrollName]['indicator-y-stop'] ) {

      scrollBars[scrollName]['indicator-y'].style.top = scrollMoveIndicatorY + 'px';

    }

  } // ! any scroll indicator?

  /*
  This concludes the section that pertains only to the scrollbar
  */

} // ! scrollObjectOn()



function scrollObjectOff(scrollMark, scrollType) {

  if( scrollHandler[scrollMark] != undefined ) {

    (scrollType == undefined || scrollType == 'hover') ?
      clearInterval(scrollHandler[scrollMark]['hover']) : false;

    (scrollType == undefined || scrollType == 'click') && scrollHandler[scrollMark]['click'] ?
      clearInterval(scrollHandler[scrollMark]['click']) : false;

  }

} // ! scrollObjectOff()




/** scrollWheelTracker()
 *
 *  This function will be called to monitor the scroll wheel on the
 *  mouse for browsers that support it.
 *
**/
function scrollWheelTracker(wheelEvent) {

  var scrollMouseWheel = 0;

  if( !wheelEvent ) {
    wheelEvent = window.event;
  }

  if( wheelEvent.wheelDelta ) {
    scrollMouseWheel = wheelEvent.wheelDelta/120;

  } else if( wheelEvent.detail ) {
    scrollMouseWheel = -wheelEvent.detail/3;

  }

  // Do something here if the wheel is used
  if( scrollMouseWheel ) {

    // Get a marker
    var scrollWheelMarker = scrollObject(null, scrollWheelName);
    var scrollCurrentTop  = scrollHandler[scrollWheelMarker]['current-y'];

    var scrollWheelJump   = scrollMouseWheel > 0 ? (scrollCurrentTop - 10) : (scrollCurrentTop + 10);

    scrollJump(scrollWheelName, scrollWheelJump);

  }

  if( wheelEvent.preventDefault ) {
    wheelEvent.preventDefault();
  }

  wheelEvent.returnValue = false;

} // ! scrollWheelTracker()




function scrollWheel(scrollName) {

  var scrollWheelObject   = scrollName ? document.getElementById(scrollName + '-wrap') : null;

  if( scrollWheelObject ) {

    scrollWheelName   = scrollName;

    if( window.addEventListener ) {
      window.addEventListener('DOMMouseScroll', scrollWheelTracker, false);
    }

    window.onmousewheel = document.onmousewheel = scrollWheelTracker;

    scrollWheelObject.onmouseout = function() {
      scrollWheel(null);
    }

  } else {

    scrollWheelName     = null;
    window.onmousewheel = document.onmousewheel = null;

  }

} // scrollWheel()





/** scrollJump()
 *
 *  Allows the scroller to jump to a specified position or anchor (in the content)
 *
**/
function scrollJump(scrollName, scrollTo) {

  var scrollMark    = scrollObject(null, scrollName);
      scrollThis    = scrollHandler[scrollMark]['object'];

  if( scrollThis ) {

    // Check if the scroll target is an anchor or position
    var scrollJumpType  = typeof(scrollTo) == 'number' ? 'position' : 'anchor';

    // If the jump is to an anchor, check if it exists
    if( scrollJumpType == 'anchor' ) {

      var scrollAnchorObject  = document.getElementById(scrollTo);

      if( scrollAnchorObject ) {

        // Get the anchor's offset from the content
        var scrollAnchorOffset  = 0;

        if( scrollAnchorObject.offsetParent ) {
          do {

            if( scrollAnchorObject.id == (scrollName + '-content') ) { break; }

            scrollAnchorOffset += scrollAnchorObject.offsetTop;

          } while( scrollAnchorObject = scrollAnchorObject.offsetParent );
        }

        scrollTo    = scrollAnchorOffset;

      } else { return false; }

    } // ! anchor detection


    // Make sure the anchor wont cause the scroller to jump out
    // of bounds (adjust the jump height to max if needed).
    scrollTo        = scrollTo < scrollBars[scrollName]['total-y'] ?
                      scrollTo : scrollBars[scrollName]['total-y'];

    scrollThis.scrollTop    = scrollTo;
    scrollHandler[scrollMark]['current-y'] = scrollThis.scrollTop;

    // Update the scroll indicator to show the correct position
    scrollObjectOn(scrollMark);

  } // ! valid object?

} // ! scrollJump()





function scrollClear() {

  scrollJump('feature-details', 0);

  scrollHandler   = new Array();
  scrollBars      = new Array();

} // ! scrollClear()

