(function ($, Modules) {

'use strict'

Modules.TableOfContents = function () {
  var $html = $('html')

  var $toc
  var $tocList

  var $openButton
  var $closeButton

  this.start = function ($element) {
    $toc = $element
    $tocList = $toc.find('.js-toc-list')
    // Open link is not inside the module
    $openButton = $html.find('.js-toc-show')
    $closeButton = $toc.find('.js-toc-close')

    fixRubberBandingInIOS()
    updateAriaAttributes()

    // Need delegated handler for show link as sticky polyfill recreates element
    $openButton.on('click.toc', preventingScrolling(openNavigation))
    $closeButton.on('click.toc', preventingScrolling(closeNavigation))
    $tocList.on('click.toc', 'a', closeNavigation)

    // Allow aria hidden to be updated when resizing from mobile to desktop or
    // vice versa
    $(window).on('resize.toc', updateAriaAttributes)

    $(document).on('keydown.toc', function (event) {
      var ESC_KEY = 27

      if (event.keyCode === ESC_KEY) {
        closeNavigation()
      }
    })
  }

  function fixRubberBandingInIOS () {
    // By default when the table of contents is at the top or bottom,
    // scrolling in that direction will scroll the body 'behind' the table of
    // contents. Fix this by preventing ever reaching the top or bottom of the
    // table of contents (by 1 pixel).
    //
    // http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/
    $toc.on('touchstart.toc', function () {
      var $this = $(this)
      var top = $this.scrollTop()
      var totalScroll = $this.prop('scrollHeight')
      var currentScroll = top + $this.prop('offsetHeight')

      if (top === 0) {
        $this.scrollTop(1)
      } else if (currentScroll === totalScroll) {
        $this.scrollTop(top - 1)
      }
    })
  }

  function openNavigation () {
    $html.addClass('toc-open')

    toggleBackgroundVisiblity(false)
    updateAriaAttributes()
    $toc.focus()
  }

  function closeNavigation () {
    $html.removeClass('toc-open')
    $html.removeClass('has-search-results-open')

    toggleBackgroundVisiblity(true)
    updateAriaAttributes()
  }

  function toggleBackgroundVisiblity (visibility) {
    $('.toc-open-disabled').attr('aria-hidden', visibility ? '' : 'true')
  }

  function updateAriaAttributes () {
    var tocIsVisible = $toc.is(':visible')

    $($openButton).add($closeButton)
      .attr('aria-expanded', tocIsVisible ? 'true' : 'false')

    $toc.attr('aria-hidden', tocIsVisible ? 'false' : 'true')
  }

  function preventingScrolling (callback) {
    return function (event) {
      event.preventDefault()
      callback()
    }
  }
}

})(jQuery, window.GOVUK.Modules)