class Turbolinks.ProgressBar

ANIMATION_DURATION = 300

@defaultCSS: """
  .turbolinks-progress-bar {
    position: fixed;
    display: block;
    top: 0;
    left: 0;
    height: 3px;
    background: #0076ff;
    z-index: 9999;
    transition: width #{ANIMATION_DURATION}ms ease-out, opacity #{ANIMATION_DURATION / 2}ms #{ANIMATION_DURATION / 2}ms ease-in;
    transform: translate3d(0, 0, 0);
  }
"""

constructor: ->
  @stylesheetElement = @createStylesheetElement()
  @progressElement = @createProgressElement()

show: ->
  unless @visible
    @visible = true
    @installStylesheetElement()
    @installProgressElement()
    @startTrickling()

hide: ->
  if @visible and not @hiding
    @hiding = true
    @fadeProgressElement =>
      @uninstallProgressElement()
      @stopTrickling()
      @visible = false
      @hiding = false

setValue: (@value) ->
  @refresh()

# Private

installStylesheetElement: ->
  document.head.insertBefore(@stylesheetElement, document.head.firstChild)

installProgressElement: ->
  @progressElement.style.width = 0
  @progressElement.style.opacity = 1
  document.documentElement.insertBefore(@progressElement, document.body)
  @refresh()

fadeProgressElement: (callback) ->
  @progressElement.style.opacity = 0
  setTimeout(callback, ANIMATION_DURATION * 1.5)

uninstallProgressElement: ->
  if @progressElement.parentNode
    document.documentElement.removeChild(@progressElement)

startTrickling: ->
  @trickleInterval ?= setInterval(@trickle, ANIMATION_DURATION)

stopTrickling: ->
  clearInterval(@trickleInterval)
  @trickleInterval = null

trickle: =>
  @setValue(@value + Math.random() / 100)

refresh: ->
  requestAnimationFrame =>
    @progressElement.style.width = "#{10 + (@value * 90)}%"

createStylesheetElement: ->
  element = document.createElement("style")
  element.type = "text/css"
  element.textContent = @constructor.defaultCSS
  element

createProgressElement: ->
  element = document.createElement("div")
  element.className = "turbolinks-progress-bar"
  element