function search(data) {
  let text = new URL(location.href).searchParams.get("q");
  let lang = new URL(location.href).searchParams.get("lang") || ui.lang;

  $("input[name='q']").val(text);

  let results = [];
  let regexp = new RegExp();
  try {
    regexp = new RegExp(text, "im");
  } catch (e) {
    $(".search-results .content").empty();
    $(".search-results .summary").html(ui.i18n.search_results_not_found);
    $(".search-results h2").html(ui.i18n.search_results);
    return debug(e.message);
  }

  function slice(content, min, max) {
    return content
      .slice(min, max)
      .replace(regexp, (match) => `<span class="bg-yellow">${match}</span>`);
  }
  for (page of data) {
    let [title, content] = [null, null];
    try {
      if (page.title) {
        title = page.title.match(regexp);
      } else {
        if (page.url == "/") {
          page.title = ui.title;
        } else {
          page.title = page.url;
        }
      }
    } catch (e) {
      debug(e.message);
    }
    try {
      if (page.content) {
        page.content = $("<div/>").html(page.content).text();
        content = page.content.match(regexp);
      }
    } catch (e) {
      debug(e.message);
    }
    if (title || content) {
      let result = [
        `<a href="${ui.baseurl}${page.url}?highlight=${text}">${page.title}</a>`,
      ];
      if (content) {
        let [min, max] = [content.index - 100, content.index + 100];
        let [prefix, suffix] = ["...", "..."];

        if (min < 0) {
          prefix = "";
          min = 0;
        }
        if (max > page.content.length) {
          suffix = "";
          max = page.content.length;
        }
        result.push(
          `<p class="text-gray">${prefix}${slice(
            page.content,
            min,
            max
          )}${suffix}</p>`
        );
      }
      results.push(`<li class="border-top py-4">${result.join("")}</li>`);
    }
  }
  if (results.length > 0 && text.length > 0) {
    $(".search-results .content").html(results.join(""));
    $(".search-results .summary").html(
      ui.i18n.search_results_found.replace("#", results.length)
    );
  } else {
    $(".search-results .content").empty();
    $(".search-results .summary").html(ui.i18n.search_results_not_found);
  }
  $(".search-results h2").html(ui.i18n.search_results);
}

function initialize(name) {
  let link = $(".toctree").find(`[href="${decodeURI(name)}"]`);

  if (link.length > 0) {
    $(".toctree .current").removeClass("current");
    link.addClass("current");
    link.closest(".level-1").parent().addClass("current");
    for (let i = 1; i <= 11; i++) {
      link.closest(`.level-${i}`).addClass("current");
    }
  }
}

function toggleCurrent(link) {
  let closest = link.closest("li");
  closest.siblings("li.current").removeClass("current");
  closest.siblings().find("li.current").removeClass("current");
  closest.find("> ul li.current").removeClass("current");
  closest.toggleClass("current");
}

function toc() {
  $(".toctree li.current")
    .append('<ul class="content-toc"></ul>')
    .html(function () {
      let level = parseInt(this.dataset.level);
      let temp = 0;
      let stack = [$(this).find(".content-toc")];

      $(".markdown-body")
        .find("h2,h3,h4,h5,h6")
        .each(function () {
          let anchor = $("<a/>")
            .addClass("d-flex flex-items-baseline")
            .text($(this).text())
            .attr("href", `#${this.id}`);
          let tagLevel = parseInt(this.tagName.slice(1)) - 1;

          if (tagLevel > temp) {
            let parent = stack[0].children("li:last")[0];
            if (parent) {
              stack.unshift($("<ul/>").appendTo(parent));
            }
          } else {
            stack.splice(
              0,
              Math.min(temp - tagLevel, Math.max(stack.length - 1, 0))
            );
          }
          temp = tagLevel;

          $("<li/>")
            .addClass(`toc level-${level + tagLevel}`)
            .append(anchor)
            .appendTo(stack[0]);
        });
      if (!stack[0].html()) {
        stack[0].remove();
      }
    });
}

function set(name, value) {
  return localStorage.setItem(name, value);
}

function get(name) {
  return localStorage.getItem(name) || false;
}

function debug() {
  console.debug.apply(console, arguments);
}

function restore() {
  let scroll = get("scroll");
  let scrollTime = get("scrollTime");
  let scrollHost = get("scrollHost");

  if (scroll && scrollTime && scrollHost) {
    if (scrollHost == location.host && Date.now() - scrollTime < 6e5) {
      $(".sidebar").scrollTop(scroll);
    }
  }
  $(".sidebar").scroll(function () {
    set("scroll", this.scrollTop);
    set("scrollTime", Date.now());
    set("scrollHost", location.host);
  });
}

function highlight() {
  let text = new URL(location.href).searchParams.get("highlight");

  if (text) {
    $(".markdown-body")
      .find("*")
      .each(function () {
        try {
          if (this.outerHTML.match(new RegExp(text, "im"))) {
            $(this).addClass("search-result");
            $(this).parentsUntil(".markdown-body").removeClass("search-result");
          }
        } catch (e) {
          debug(e.message);
        }
      });
    // last node
    $(".search-result").each(function () {
      $(this).html(function (i, html) {
        return html.replace(text, `<span class="bg-yellow">${text}</span>`);
      });
    });
    $(".search input").val(text);
  }
}

$(window).bind("hashchange", () =>
  initialize(location.hash || location.pathname)
);

$(document).on("scroll", function () {
  let start = $(this).scrollTop() + 5;
  let items = [];

  $(".markdown-body")
    .find("h1,h2,h3,h4,h5,h6")
    .each(function () {
      items.push({
        offset: $(this).offset().top,
        id: this.id,
        level: parseInt(this.tagName.slice(1)),
      });
    });
  for (let i = 0; i < items.length; i++) {
    if (start > items[i].offset) {
      if (i < items.length - 1) {
        if (start < items[i + 1].offset) {
          if (items[i].level == 1) {
            initialize(location.pathname);
          } else {
            initialize("#" + items[i].id);
          }
        }
      } else {
        initialize("#" + items[i].id);
      }
    }
  }
});

$("#toggle").click(function () {
  $(".sidebar-wrap,.content-wrap,.addons-wrap").toggleClass("shift");
});
$(".status").click(function () {
  $(".addons").toggleClass("d-none");
});

if (location.pathname == `${ui.baseurl}/search.html`) {
  $.ajax(`${ui.baseurl}/data.json`)
    .done(search)
    .fail((xhr, message) => debug(message));
}

toc();
initialize(location.pathname);
initialize(location.hash);
restore();
highlight();

/* nested ul */
$(".toc ul")
  .siblings("a")
  .each(function () {
    let link = $(this);
    let expand = $('<i class="fa fa-plus-square-o"></i>');

    expand.on("click", function (e) {
      e.stopPropagation();
      toggleCurrent(link);
      return false;
    });
    link.prepend(expand);
  });

$(".markdown-body :header").append(function () {
  return `<a href="#${this.id}" class="anchor"><i class="octicon-link fa fa-link text-blue"></i></a>`;
});

$("div.highlighter-rouge").each(function () {
  const match = $(this)
    .attr("class")
    .match(/language-(\w+)/);
  if (match) {
    $(this).attr("data-lang", match[1]);
  }
});

if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register(`${ui.baseurl}/sw.caches.js`);
} else {
  debug("Service Worker not supported!");
}