/**
 * @licstart The following is the entire license notice for the
 * JavaScript code in this page
 *
 * Copyright 2022 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @licend The above is the entire license notice for the
 * JavaScript code in this page
 */
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.TextAccessibilityManager = void 0;

var _ui_utils = require("./ui_utils.js");

class TextAccessibilityManager {
  #enabled = false;
  #textChildren = null;
  #textNodes = new Map();
  #waitingElements = new Map();

  setTextMapping(textDivs) {
    this.#textChildren = textDivs;
  }

  static #compareElementPositions(e1, e2) {
    const rect1 = e1.getBoundingClientRect();
    const rect2 = e2.getBoundingClientRect();

    if (rect1.width === 0 && rect1.height === 0) {
      return +1;
    }

    if (rect2.width === 0 && rect2.height === 0) {
      return -1;
    }

    const top1 = rect1.y;
    const bot1 = rect1.y + rect1.height;
    const mid1 = rect1.y + rect1.height / 2;
    const top2 = rect2.y;
    const bot2 = rect2.y + rect2.height;
    const mid2 = rect2.y + rect2.height / 2;

    if (mid1 <= top2 && mid2 >= bot1) {
      return -1;
    }

    if (mid2 <= top1 && mid1 >= bot2) {
      return +1;
    }

    const centerX1 = rect1.x + rect1.width / 2;
    const centerX2 = rect2.x + rect2.width / 2;
    return centerX1 - centerX2;
  }

  enable() {
    if (this.#enabled) {
      throw new Error("TextAccessibilityManager is already enabled.");
    }

    if (!this.#textChildren) {
      throw new Error("Text divs and strings have not been set.");
    }

    this.#enabled = true;
    this.#textChildren = this.#textChildren.slice();
    this.#textChildren.sort(TextAccessibilityManager.#compareElementPositions);

    if (this.#textNodes.size > 0) {
      const textChildren = this.#textChildren;

      for (const [id, nodeIndex] of this.#textNodes) {
        const element = document.getElementById(id);

        if (!element) {
          this.#textNodes.delete(id);
          continue;
        }

        this.#addIdToAriaOwns(id, textChildren[nodeIndex]);
      }
    }

    for (const [element, isRemovable] of this.#waitingElements) {
      this.addPointerInTextLayer(element, isRemovable);
    }

    this.#waitingElements.clear();
  }

  disable() {
    if (!this.#enabled) {
      return;
    }

    this.#waitingElements.clear();
    this.#textChildren = null;
    this.#enabled = false;
  }

  removePointerInTextLayer(element) {
    if (!this.#enabled) {
      this.#waitingElements.delete(element);
      return;
    }

    const children = this.#textChildren;

    if (!children || children.length === 0) {
      return;
    }

    const {
      id
    } = element;
    const nodeIndex = this.#textNodes.get(id);

    if (nodeIndex === undefined) {
      return;
    }

    const node = children[nodeIndex];
    this.#textNodes.delete(id);
    let owns = node.getAttribute("aria-owns");

    if (owns?.includes(id)) {
      owns = owns.split(" ").filter(x => x !== id).join(" ");

      if (owns) {
        node.setAttribute("aria-owns", owns);
      } else {
        node.removeAttribute("aria-owns");
        node.setAttribute("role", "presentation");
      }
    }
  }

  #addIdToAriaOwns(id, node) {
    const owns = node.getAttribute("aria-owns");

    if (!owns?.includes(id)) {
      node.setAttribute("aria-owns", owns ? `${owns} ${id}` : id);
    }

    node.removeAttribute("role");
  }

  addPointerInTextLayer(element, isRemovable) {
    const {
      id
    } = element;

    if (!id) {
      return;
    }

    if (!this.#enabled) {
      this.#waitingElements.set(element, isRemovable);
      return;
    }

    if (isRemovable) {
      this.removePointerInTextLayer(element);
    }

    const children = this.#textChildren;

    if (!children || children.length === 0) {
      return;
    }

    const index = (0, _ui_utils.binarySearchFirstItem)(children, node => TextAccessibilityManager.#compareElementPositions(element, node) < 0);
    const nodeIndex = Math.max(0, index - 1);
    this.#addIdToAriaOwns(id, children[nodeIndex]);
    this.#textNodes.set(id, nodeIndex);
  }

  moveElementInDOM(container, element, contentElement, isRemovable) {
    this.addPointerInTextLayer(contentElement, isRemovable);

    if (!container.hasChildNodes()) {
      container.append(element);
      return;
    }

    const children = Array.from(container.childNodes).filter(node => node !== element);

    if (children.length === 0) {
      return;
    }

    const elementToCompare = contentElement || element;
    const index = (0, _ui_utils.binarySearchFirstItem)(children, node => TextAccessibilityManager.#compareElementPositions(elementToCompare, node) < 0);

    if (index === 0) {
      children[0].before(element);
    } else {
      children[index - 1].after(element);
    }
  }

}

exports.TextAccessibilityManager = TextAccessibilityManager;