-window.Scroller = root = {}
-
 #
 # activatedElement is different from document.activeElement -- the latter seems to be reserved mostly for
 # input elements. This mechanism allows us to decide whether to scroll a div or to scroll the whole document.
 #
 activatedElement = null
 settings = null
-
-root.init = (frontendSettings) ->
-  settings = frontendSettings
-  handlerStack.push DOMActivate: -> activatedElement = event.target
 
 scrollProperties =
   x: {

  element[axisName] - before

# Scroll by a relative amount (a number) in some direction, possibly smoothly.
doScrollBy = do ->
  interval = 10 # Update interval (in ms).
  duration = 120 # This must be a multiple of interval (also in ms).
  fudgeFactor = 25
  timer = null

  clearTimer = ->
    if timer
      clearInterval timer
      timer = null

  # Allow a bit longer for longer scrolls.
  calculateExtraDuration = (amount) ->
    extra = fudgeFactor * Math.log Math.abs amount
    # Ensure we have a multiple of interval.
    return interval * Math.round (extra / interval)

  (element, direction, amount, wantSmooth) ->
    axisName = scrollProperties[direction].axisName
    clearTimer()

    unless wantSmooth and settings.get "smoothScroll"
      return performScroll element, axisName, amount

    requiredTicks = (duration + calculateExtraDuration amount) / interval
    # Round away from 0, so that we don't leave any scroll amount unscrolled.
    delta = (if 0 <= amount then Math.ceil else Math.floor)(amount / requiredTicks)

    if delta
      ticks = 0
      ticker = ->
        if performScroll(element, axisName, delta, false) != delta or ++ticks == requiredTicks
          # One final call of performScroll to check the visibility of the activated element.
          performScroll(element, axisName, 0, true)
          clearTimer()

      timer = setInterval ticker, interval
      ticker()

# scroll the active element in :direction by :amount * :factor.
# :factor is needed because :amount can take on string values, which scrollBy converts to element dimensions.
root.scrollBy = (direction, amount, factor = 1) ->
  # if this is called before domReady, just use the window scroll function
  if (!document.body and amount instanceof Number)
    if (direction == "x")
      window.scrollBy(amount, 0)
    else
      window.scrollBy(0, amount)
    return

  if (!activatedElement || !isRendered(activatedElement))
    activatedElement = document.body

  element = findScrollableElement activatedElement, direction, amount, factor
  elementAmount = factor * getDimension element, direction, amount
  doScrollBy element, direction, elementAmount, true

root.scrollTo = (direction, pos, wantSmooth = false) ->
  return unless document.body

  if (!activatedElement || !isRendered(activatedElement))
    activatedElement = document.body

  element = findScrollableElement activatedElement, direction, pos
  amount = getDimension(element,direction,pos) - element[scrollProperties[direction].axisName]
  doScrollBy element, direction, amount, wantSmooth

# TODO refactor and put this together with the code in getVisibleClientRect
isRendered = (element) ->
  computedStyle = window.getComputedStyle(element, null)
  return !(computedStyle.getPropertyValue("visibility") != "visible" ||
      computedStyle.getPropertyValue("display") == "none")


# Test whether element should be scrolled.
isScrollAllowed = (element, direction) ->
  computedStyle = window.getComputedStyle(element)
  # Elements with `overflow: hidden` should not be scrolled.
  return computedStyle.getPropertyValue("overflow-#{direction}") != "hidden" and
         ["hidden", "collapse"].indexOf(computedStyle.getPropertyValue("visibility")) == -1 and
         computedStyle.getPropertyValue("display") != "none"

# Test whether element actually scrolls in the direction required when asked to do so.
# Due to chrome bug 110149, scrollHeight and clientHeight cannot be used to reliably determine whether an
