(function () {

const HEADER_TAGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
const IN_PAGE_NAV_HTML_CLASS = 'in-page-toc';
const SCROLLABLE_NAV_CONTAINER_SELECTOR = 'ul.nav-items';

/* Given a container of AsciiDoc .sectN elementss,
 * returns an object containing navigation structure like this:
 * { items: [ { title: "Some title", path: "./#some-title", items: [ ...subitems ] }, ... }
 * Works recursively through nested sections.
 */
function getAdocTocItems(containerEl, sectLvl) {
  sectLvl = sectLvl || 1;
  var items = [];

  const topLevelSections = Array.from(containerEl.children).filter((el) => {
    return el.matches(`div.sect${sectLvl}`);
  });

  for (let sectionEl of topLevelSections) {
    const headerEl = Array.from(sectionEl.children).filter((el) => {
      for (let hTagName of HEADER_TAGS) {
        if (el.matches(hTagName)) { return true; }
      }
      return false;
    })[0];
    const headerId = headerEl.getAttribute('id');

    var subItems = [];
    const sectionBody = sectionEl.querySelector('div.sectionbody');
    if (sectionBody) {
      subItems = getAdocTocItems(sectionBody, sectLvl + 1);
    } else {
      subItems = getAdocTocItems(sectionEl, sectLvl + 1);
    }

    items.push({
      title: headerEl.innerText,
      description: headerEl.innerText,
      path: `./#${headerId}`,
      items: subItems,

      id: headerId,
    });
  }

  return items;
}

function highlightSelected(headerId, itemPath) {
  let selectedItemEl;

  for (const itemEl of document.querySelectorAll(`.${IN_PAGE_NAV_HTML_CLASS} li`)) {
    const link = (itemEl.firstChild || {}).firstChild;
    if (link && link.getAttribute('href') == itemPath) {
      itemEl.classList.add('highlighted');
      selectedItemEl = itemEl;
    } else {
      itemEl.classList.remove('highlighted');
    }
  }
  for (const hTag of HEADER_TAGS) {
    for (const headerEl of document.querySelectorAll(hTag)) {
      headerEl.classList.remove('highlighted');
    }
  }
  const selectedHeaderEl = document.getElementById(headerId);
  selectedHeaderEl.classList.add('highlighted');

  return selectedItemEl;
}

/* Given a list of navigation items, returns an <ul> containing items recursively
 * with CSS classes and layout consistent with docs navigation markup expected by the theme.
 */
function formatSubItems(tocItems) {
  const subItemContainer = document.createElement('ul');

  subItemContainer.classList.add('nav-items');
  subItemContainer.classList.add('subitems');

  for (let item of tocItems) {
    let itemEl, itemTitleEl, itemLinkEl;

    itemEl = document.createElement('li');
    itemEl.classList.add('item');

    itemTitleEl = document.createElement('div');
    itemTitleEl.classList.add('item-title');

    itemLinkEl = document.createElement('a');
    itemLinkEl.setAttribute('href', item.path);
    itemLinkEl.setAttribute('title', item.title);
    itemLinkEl.innerText = item.title;

    itemTitleEl.appendChild(itemLinkEl);
    itemEl.appendChild(itemTitleEl);

    if (item.items.length > 0) {
      itemEl.appendChild(formatSubItems(item.items));
    }

    itemLinkEl.addEventListener('click', () => highlightSelected(item.id, item.path));

    subItemContainer.appendChild(itemEl);
  }

  return subItemContainer;
}

const articleBody = document.querySelector('main section article .body');
const selectedItem = document.querySelector('main .docs-nav .nav-items li.selected');

if (articleBody && selectedItem) {
  const items = getAdocTocItems(articleBody);

  if (items.length > 0) {
    const ulEl = formatSubItems(items);
    ulEl.classList.add(IN_PAGE_NAV_HTML_CLASS);

    const existingSubItems = selectedItem.querySelector('ul.nav-items');
    if (existingSubItems) {
      selectedItem.insertBefore(ulEl, existingSubItems);
    } else {
      selectedItem.appendChild(ulEl);
    }
  }
}

if (articleBody && window.location.hash) {
  // Do things that need to be done if the page was opened
  // with hash component in address bar.
  // - After initial scroll to anchor, scroll up a bit
  //   to ensure header is in view accounting for top bar.
  // - Select in-page doc nav item corresponding to the hash.

  const SCROLL_COMPENSATION_AMOUNT_PX = 0 - document.querySelector('body > .underlay.header > header').offsetHeight - 10;

  function _scrollUp(evt) {
    window.scrollBy(0, SCROLL_COMPENSATION_AMOUNT_PX);
    window.removeEventListener('scroll', _scrollUp);
  };

  function _selectInitialItem() {
    const hash = window.location.hash.substring(1);
    const anchorEl = document.getElementById(hash);

    var selectedLinkId;

    if (anchorEl.tagName === 'A') {
      // We were selected by <a> anchor, not by <hX[id]>.
      // We want to highlight selected item in the nav
      // according to the nearest header upwards from anchor.
      var curEl = anchorEl;
      while (true) {
        var curEl = curEl.parentNode;
        var nearestHeaderEl = curEl.querySelector('h2');
        if (nearestHeaderEl && nearestHeaderEl.hasAttribute('id')) {
          selectedLinkId = nearestHeaderEl.getAttribute('id');
          break;
        }
      }
    } else {
      selectedLinkId = hash;
    }

    const selectedItemEl = highlightSelected(selectedLinkId, `./#${selectedLinkId}`);
    window.setTimeout(function () { selectedItemEl.scrollIntoView(); }, 200);
  };

  _selectInitialItem();
  window.addEventListener('scroll', _scrollUp);
}

}());