/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// This file is loaded into the browser window scope.
/* eslint-env mozilla/browser-window */

ChromeUtils.defineESModuleGetters(this, {
  OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs",
});

/**
 * The `unified-extensions-item` custom element is used to manage an extension
 * in the list of extensions, which is displayed when users click the unified
 * extensions (toolbar) button.
 *
 * This custom element must be initialized with `setExtension()`:
 *
 * ```
 * let item = document.createElement("unified-extensions-item");
 * item.setExtension(extension);
 * document.body.appendChild(item);
 * ```
 */
customElements.define(
  "unified-extensions-item",
  class extends HTMLElement {
    /**
     * Set the extension for this item. The item will be populated based on the
     * extension when it is rendered into the DOM.
     *
     * @param {Extension} extension The extension to use.
     */
    setExtension(extension) {
      this.extension = extension;
    }

    connectedCallback() {
      if (this._menuButton) {
        return;
      }

      const template = document.getElementById(
        "unified-extensions-item-template"
      );
      this.appendChild(template.content.cloneNode(true));

      this._actionButton = this.querySelector(
        ".unified-extensions-item-action-button"
      );
      this._menuButton = this.querySelector(
        ".unified-extensions-item-menu-button"
      );
      this._messageDeck = this.querySelector(
        ".unified-extensions-item-message-deck"
      );

      // Focus/blur events are fired on specific elements only.
      this._actionButton.addEventListener("blur", this);
      this._actionButton.addEventListener("focus", this);
      this._menuButton.addEventListener("blur", this);
      this._menuButton.addEventListener("focus", this);

      this.addEventListener("command", this);
      this.addEventListener("mouseout", this);
      this.addEventListener("mouseover", this);

      this.render();
    }

    handleEvent(event) {
      const { target } = event;

      switch (event.type) {
        case "command":
          if (target === this._menuButton) {
            const popup = target.ownerDocument.getElementById(
              "unified-extensions-context-menu"
            );
            // Anchor to the visible part of the button.
            const anchor = target.firstElementChild;
            popup.openPopup(
              anchor,
              "after_end",
              0,
              0,
              true /* isContextMenu */,
              false /* attributesOverride */,
              event
            );
          } else if (target === this._actionButton) {
            const win = event.target.ownerGlobal;
            const tab = win.gBrowser.selectedTab;

            this.extension.tabManager.addActiveTabPermission(tab);
            this.extension.tabManager.activateScripts(tab);
          }
          break;

        case "blur":
        case "mouseout":
          this._messageDeck.selectedIndex =
            gUnifiedExtensions.MESSAGE_DECK_INDEX_DEFAULT;
          break;

        case "focus":
        case "mouseover":
          if (target === this._menuButton) {
            this._messageDeck.selectedIndex =
              gUnifiedExtensions.MESSAGE_DECK_INDEX_MENU_HOVER;
          } else if (target === this._actionButton) {
            this._messageDeck.selectedIndex =
              gUnifiedExtensions.MESSAGE_DECK_INDEX_HOVER;
          }
          break;
      }
    }

    #setStateMessage() {
      const messages = OriginControls.getStateMessageIDs({
        policy: this.extension.policy,
        tab: this.ownerGlobal.gBrowser.selectedTab,
      });

      if (!messages) {
        return;
      }

      const messageDefaultElement = this.querySelector(
        ".unified-extensions-item-message-default"
      );
      this.ownerDocument.l10n.setAttributes(
        messageDefaultElement,
        messages.default
      );

      const messageHoverElement = this.querySelector(
        ".unified-extensions-item-message-hover"
      );
      this.ownerDocument.l10n.setAttributes(
        messageHoverElement,
        messages.onHover || messages.default
      );
    }

    #hasAction() {
      const state = OriginControls.getState(
        this.extension.policy,
        this.ownerGlobal.gBrowser.selectedTab
      );

      return state && state.whenClicked && !state.hasAccess;
    }

    render() {
      if (!this.extension) {
        throw new Error(
          "unified-extensions-item requires an extension, forgot to call setExtension()?"
        );
      }

      this.setAttribute("extension-id", this.extension.id);
      this.classList.add(
        "toolbaritem-combined-buttons",
        "unified-extensions-item"
      );

      // The data-extensionid attribute is used by context menu handlers
      // to identify the extension being manipulated by the context menu.
      this._actionButton.dataset.extensionid = this.extension.id;

      this.toggleAttribute(
        "attention",
        OriginControls.getAttention(this.extension.policy, this.ownerGlobal)
      );

      this.querySelector(".unified-extensions-item-name").textContent =
        this.extension.name;

      AddonManager.getAddonByID(this.extension.id).then(addon => {
        const iconURL = AddonManager.getPreferredIconURL(addon, 32, window);
        if (iconURL) {
          this.querySelector(".unified-extensions-item-icon").setAttribute(
            "src",
            iconURL
          );
        }
      });

      this._actionButton.disabled = !this.#hasAction();

      // The data-extensionid attribute is used by context menu handlers
      // to identify the extension being manipulated by the context menu.
      this._menuButton.dataset.extensionid = this.extension.id;
      this._menuButton.setAttribute(
        "data-l10n-args",
        JSON.stringify({ extensionName: this.extension.name })
      );

      this.#setStateMessage();
    }
  }
);
