/**
 * Site-wide JS that sets up:
 *
 * [1] MathJax rendering on navigation
 * [2] Sidebar toggling
 * [3] Sidebar scroll preserving
 * [4] Keyboard navigation
 * [5] Right sidebar scroll highlighting / navbar show
 */

const togglerId = 'js-sidebar-toggle'
const textbookId = 'js-textbook'
const togglerActiveClass = 'is-active'
const textbookActiveClass = 'js-show-sidebar'
const mathRenderedClass = 'js-mathjax-rendered'
const icon_path = document.location.origin + `${site_basename}assets`;

const getToggler = () => document.getElementById(togglerId)
const getTextbook = () => document.getElementById(textbookId)

// [1] Run MathJax when Turbolinks navigates to a page.
// When Turbolinks caches a page, it also saves the MathJax rendering. We mark
// each page with a CSS class after rendering to prevent double renders when
// navigating back to a cached page.
document.addEventListener('turbolinks:load', () => {
  const textbook = getTextbook()
  if (window.MathJax && !textbook.classList.contains(mathRenderedClass)) {
    MathJax.Hub.Queue(['Typeset', MathJax.Hub])
    textbook.classList.add(mathRenderedClass)
  }
})

/**
 * [2] Toggles sidebar and menu icon
 */
const toggleSidebar = () => {
  const toggler = getToggler()
  const textbook = getTextbook()

  if (textbook.classList.contains(textbookActiveClass)) {
    textbook.classList.remove(textbookActiveClass)
    toggler.classList.remove(togglerActiveClass)
  } else {
    textbook.classList.add(textbookActiveClass)
    toggler.classList.add(togglerActiveClass)
  }
}

/**
 * Keep the variable below in sync with the tablet breakpoint value in
 * _sass/inuitcss/tools/_tools.mq.scss
 *
 */
const autoCloseSidebarBreakpoint = 769

// Set up event listener for sidebar toggle button
const sidebarButtonHandler = () => {
  getToggler().addEventListener('click', toggleSidebar)

  /**
   * Auto-close sidebar on smaller screens after page load.
   *
   * Having the sidebar be open by default then closing it on page load for
   * small screens gives the illusion that the sidebar closes in response
   * to selecting a page in the sidebar. However, it does cause a bit of jank
   * on the first page load.
   *
   * Since we don't want to persist state in between page navigation, this is
   * the best we can do while optimizing for larger screens where most
   * viewers will read the textbook.
   *
   * The code below assumes that the sidebar is open by default.
   */
  if (window.innerWidth < autoCloseSidebarBreakpoint) toggleSidebar()
}

initFunction(sidebarButtonHandler);

/**
 * [3] Preserve sidebar scroll when navigating between pages
 */
let sidebarScrollTop = 0
const getSidebar = () => document.getElementById('js-sidebar')

document.addEventListener('turbolinks:before-visit', () => {
  sidebarScrollTop = getSidebar().scrollTop
})

document.addEventListener('turbolinks:load', () => {
  getSidebar().scrollTop = sidebarScrollTop
})

/**
 * Focus textbook page by default so that user can scroll with spacebar
 */
const focusPage = () => {
  document.querySelector('.c-textbook__page').focus()
}

initFunction(focusPage);

/**
 * [4] Use left and right arrow keys to navigate forward and backwards.
 */
const LEFT_ARROW_KEYCODE = 37
const RIGHT_ARROW_KEYCODE = 39

const getPrevUrl = () => document.getElementById('js-page__nav__prev').href
const getNextUrl = () => document.getElementById('js-page__nav__next').href
const initPageNav = (event) => {
  const keycode = event.which

  if (keycode === LEFT_ARROW_KEYCODE) {
    Turbolinks.visit(getPrevUrl())
  } else if (keycode === RIGHT_ARROW_KEYCODE) {
    Turbolinks.visit(getNextUrl())
  }
};

var keyboardListener = false;
const initListener = () => {
  if (keyboardListener === false) {
    document.addEventListener('keydown', initPageNav)
    keyboardListener = true;
  }
}
initFunction(initListener);

/**
 * [5] Scrolling functions:
 *   * Right sidebar scroll highlighting
 *   * Top navbar hiding for scrolling
 */

var didScroll;

initScrollFunc = function() {
  var content = document.querySelector('.c-textbook__page');
  var topbar = document.getElementById("top-navbar");
  var prevScrollpos = content.scrollTop; // Initializing

  scrollFunc = function() {
    // This is the function that does all the stuff when scrolling happens

    var position = content.scrollTop; // Because we use this differently for sidebar

    // Decide to show the navbar
    var currentScrollPos = content.scrollTop;
    var delta = 10;
    var scrollDiff = prevScrollpos - currentScrollPos;
    if (scrollDiff >= delta) {
      // If we scrolled down, consider showing the menu
      topbar.classList.remove("hidetop")
    } else if (Math.abs(scrollDiff) >= delta) {
      // If we scrolled up, consider hiding the menu
      topbar.classList.add("hidetop")
    } else {
      // Do nothing because we didn't scroll enough
    }
    prevScrollpos = currentScrollPos;

    // Highlight the right sidebar section
    position = position + (window.innerHeight / 4);  // + Manual offset

    content.querySelectorAll('h2, h3').forEach((header, index) => {
      // Highlight based on location from the top of the screen
      var target = header.getBoundingClientRect().top
      var pixelOffset = 300;  // Number of pixels from top to be highlighted
      var id = header.id;
      if (target < pixelOffset) {
        var query = 'ul.toc__menu a[href="#' + id + '"]';
        document.querySelectorAll('ul.toc__menu li').forEach((item) => {item.classList.remove('active')});
        document.querySelectorAll(query).forEach((item) => {item.parentElement.classList.add('active')});
      }
    });
  }

  // Our event listener just sets "yep, I scrolled" to true.
  // The interval function will set it to false after it runs.
  content.addEventListener('scroll', () => {didScroll = true;});
  scrollWait = 250;
  setInterval(() => {
    if (didScroll) {
      scrollFunc();
      didScroll = false;
    }
  }, scrollWait)
}

initFunction(initScrollFunc);
