app.views.EntryPage = class EntryPage extends app.View {
  static className = "_page";
  static errorClass = "_page-error";

  static events = { click: "onClick" };

  static shortcuts = {
    altC: "onAltC",
    altO: "onAltO",
  };

  static routes = { before: "beforeRoute" };

  static LINKS = {
    home: "Homepage",
    code: "Source code",
  };

  init() {
    this.cacheMap = {};
    this.cacheStack = [];
  }

  deactivate() {
    if (super.deactivate(...arguments)) {
      this.empty();
      this.entry = null;
    }
  }

  loading() {
    this.empty();
    this.trigger("loading");
  }

  render(content, fromCache) {
    if (content == null) {
      content = "";
    }
    if (fromCache == null) {
      fromCache = false;
    }
    if (!this.activated) {
      return;
    }
    this.empty();
    this.subview = new (this.subViewClass())(this.el, this.entry);

    $.batchUpdate(this.el, () => {
      this.subview.render(content, fromCache);
      if (!fromCache) {
        this.addCopyButtons();
      }
    });

    if (app.disabledDocs.findBy("slug", this.entry.doc.slug)) {
      this.hiddenView = new app.views.HiddenPage(this.el, this.entry);
    }

    setFaviconForDoc(this.entry.doc);
    this.delay(this.polyfillMathML);
    this.trigger("loaded");
  }

  addCopyButtons() {
    if (!this.copyButton) {
      this.copyButton = document.createElement("button");
      this.copyButton.innerHTML = '<svg><use xlink:href="#icon-copy"/></svg>';
      this.copyButton.type = "button";
      this.copyButton.className = "_pre-clip";
      this.copyButton.title = "Copy to clipboard";
      this.copyButton.setAttribute("aria-label", "Copy to clipboard");
    }
    for (var el of this.findAllByTag("pre")) {
      el.appendChild(this.copyButton.cloneNode(true));
    }
  }

  polyfillMathML() {
    if (
      window.supportsMathML !== false ||
      !!this.polyfilledMathML ||
      !this.findByTag("math")
    ) {
      return;
    }
    this.polyfilledMathML = true;
    $.append(
      document.head,
      `<link rel="stylesheet" href="${app.config.mathml_stylesheet}">`,
    );
  }

  prepareContent(content) {
    if (!this.entry.isIndex() || !this.entry.doc.links) {
      return content;
    }

    const links = (() => {
      const result = [];
      for (var link in this.entry.doc.links) {
        var url = this.entry.doc.links[link];
        result.push(
          `<a href="${url}" class="_links-link">${EntryPage.LINKS[link]}</a>`,
        );
      }
      return result;
    })();

    return `<p class="_links">${links.join("")}</p>${content}`;
  }

  empty() {
    if (this.subview != null) {
      this.subview.deactivate();
    }
    this.subview = null;

    if (this.hiddenView != null) {
      this.hiddenView.deactivate();
    }
    this.hiddenView = null;

    this.resetClass();
    super.empty(...arguments);
  }

  subViewClass() {
    return (
      app.views[`${$.classify(this.entry.doc.type)}Page`] || app.views.BasePage
    );
  }

  getTitle() {
    return (
      this.entry.doc.fullName +
      (this.entry.isIndex() ? " documentation" : ` / ${this.entry.name}`)
    );
  }

  beforeRoute() {
    this.cache();
    this.abort();
  }

  onRoute(context) {
    const isSameFile =
      context.entry.filePath() ===
      (this.entry != null ? this.entry.filePath() : undefined);
    this.entry = context.entry;
    if (!isSameFile) {
      this.restore() || this.load();
    }
  }

  load() {
    this.loading();
    this.xhr = this.entry.loadFile(
      (response) => this.onSuccess(response),
      () => this.onError(),
    );
  }

  abort() {
    if (this.xhr) {
      this.xhr.abort();
      this.xhr = this.entry = null;
    }
  }

  onSuccess(response) {
    if (!this.activated) {
      return;
    }
    this.xhr = null;
    this.render(this.prepareContent(response));
  }

  onError() {
    this.xhr = null;
    this.render(this.tmpl("pageLoadError"));
    this.resetClass();
    this.addClass(this.constructor.errorClass);
    if (app.serviceWorker != null) {
      app.serviceWorker.update();
    }
  }

  cache() {
    let path;
    if (
      this.xhr ||
      !this.entry ||
      this.cacheMap[(path = this.entry.filePath())]
    ) {
      return;
    }

    this.cacheMap[path] = this.el.innerHTML;
    this.cacheStack.push(path);

    while (this.cacheStack.length > app.config.history_cache_size) {
      delete this.cacheMap[this.cacheStack.shift()];
    }
  }

  restore() {
    let path;
    if (this.cacheMap[(path = this.entry.filePath())]) {
      this.render(this.cacheMap[path], true);
      return true;
    }
  }

  onClick(event) {
    const target = $.eventTarget(event);
    if (target.hasAttribute("data-retry")) {
      $.stopEvent(event);
      this.load();
    } else if (target.classList.contains("_pre-clip")) {
      $.stopEvent(event);
      target.classList.add(
        $.copyToClipboard(target.parentNode.textContent)
          ? "_pre-clip-success"
          : "_pre-clip-error",
      );
      setTimeout(() => (target.className = "_pre-clip"), 2000);
    }
  }

  onAltC() {
    let link;
    if (!(link = this.find("._attribution:last-child ._attribution-link"))) {
      return;
    }
    console.log(link.href + location.hash);
    navigator.clipboard.writeText(link.href + location.hash);
  }

  onAltO() {
    let link;
    if (!(link = this.find("._attribution:last-child ._attribution-link"))) {
      return;
    }
    this.delay(() => $.popup(link.href + location.hash));
  }
};