'use strict';

const changeManager = require('./change-manager-a297e4d2.js');
const observer = require('./observer-f49483e8.js');
const ui = require('./ui-3727d685.js');

/** The DomNodeSubject class represents a subject related to DOM nodes. */
class DomNodeSubject {
  /**
   * The constructor function takes a SubjectTitle parameter and assigns it to the private title property.
   *
   * @param {SubjectTitle} title - The "title" parameter is a private property of the class that is of type "SubjectTitle".
   * @param {HTMLElement} host - The `host` parameter is an HTMLElement that represents the container or
   * parent element where the subject title will be displayed. It is used to specify the location where
   * the title will be rendered on the web page.
   */
  constructor(title, host) {
    this.title = title;
    this.host = host;
  }
  /**
   * The getDescription function returns the title of an object as a string.
   *
   * @returns {string} The title of the object.
   */
  getDescription() {
    return `, this is a dom nodes subject of ${this.title}.(class name:${this.host.className}, id:${this.host.id})`;
  }
}

/** The `DomNodesSubjectFactory` class is responsible for managing and caching `DomNodeSubject` objects associated with HTML elements. */
class DomNodeSubjectFactory {
  constructor() {
    this.cache = new Map();
  }
  /**
   * The function `getSubject` returns the subject associated with a given node and event ID, either from the cache or by setting it if it doesn't exist.
   *
   * @param {HTMLElement} node - The `node` parameter is an HTMLElement, which represents an element in the HTML document.
   * @param {VegaEventIDInterface} eventId - The `eventId` parameter is of type `VegaEventIDInterface`. It represents the ID of the event for which we want to get the subject.
   * @returns {DomNodeSubject} a `DomNodeSubject` object.
   */
  getSubject(node, eventId) {
    if (this.isExist(node, eventId)) {
      return this.cache.get(node).get(eventId);
    }
    else {
      return this.setSubject(node, eventId);
    }
  }
  /**
   * The function checks if a given node exists in the cache and if it has a specific event ID.
   *
   * @param {HTMLElement} node - The "node" parameter is an HTMLElement, which represents an HTML element in the DOM (Document Object Model). It could be any HTML element such as a div, span, button, etc.
   * @param {VegaEventIDInterface} eventId - The `eventId` parameter is of type `VegaEventIDInterface`. It represents an event ID that is used to identify a specific event.
   * @returns {boolean} a boolean value.
   */
  isExist(node, eventId) {
    if (node) {
      return (this.cache.has(node) &&
        this.cache.get(node) !== undefined &&
        this.cache.get(node).has(eventId));
    }
    return false;
  }
  /**
   * The function find if the parent of a given node exists in the cache and if it has a specific event ID.
   *
   * @param {HTMLElement} childNode - Child node.
   * @param {VegaEventIDInterface} eventId - eventId.
   * @returns {Nullable<DomNodeSubject>} - Parent node subject.
   */
  getSubjectFromParentNodeByEventId(childNode, eventId) {
    let subject;
    for (const entry of this.cache) {
      if (ui.isParent(childNode, entry[0]) && entry[1].has(eventId)) {
        subject = entry[1].get(eventId);
        break;
      }
    }
    return subject;
  }
  /**
   * The function `setSubject` creates a new `DomNodeSubject` and associates it with a given `node` and `eventId`, and then returns the created subject.
   *
   * @param {HTMLElement} node - The `node` parameter is an HTMLElement object representing an HTML element in the DOM (Document Object Model).
   * @param {VegaEventIDInterface} eventId - The `eventId` parameter is of type `VegaEventIDInterface`. It represents the ID of a Vega event.
   * @returns {DomNodeSubject} dom node subject object
   */
  setSubject(node, eventId) {
    const subjectTitle = `${node.tagName}:${eventId.getName()}`;
    const subject = new DomNodeSubject(subjectTitle, node);
    if (!this.cache.get(node)) {
      this.cache.set(node, new Map());
    }
    this.cache.get(node).set(eventId, subject);
    return subject;
  }
}
const domNodeSubjectFactory = new DomNodeSubjectFactory();

/**
 * The function `domAcceptableHandle` always returns `true`.
 *
 * @returns {boolean} true
 */
const domAcceptableHandle = () => {
  return true;
};
/** The `DomNodeSubjectObserverFactory` class provides methods to add and remove observers to HTML element nodes. */
class DomNodeSubjectObserverFactory {
  /**
   * add observer to a given HTML element node
   *
   * @param {HTMLElement} node the node ref
   * @param {VegaEventIDInterface} eventId The `eventId` parameter is of type `VegaEventIDInterface`. It represents the ID of a Vega event.
   * @param {(input?: unknown) => void} callback the callback handle
   * @param {(input?: unknown) => boolean} acceptableHandle the acceptable handle
   */
  static addUniqueObserverToNode(node, eventId, callback, acceptableHandle) {
    if (node) {
      const domNodesObserver = new observer.Observer(typeof acceptableHandle === 'function' ? acceptableHandle.bind(null) : domAcceptableHandle, callback);
      DomNodeSubjectObserverFactory.removeUniqueObserverFromNode(node, eventId);
      changeManager.ChangeManager.register(domNodeSubjectFactory.getSubject(node, eventId), domNodesObserver);
    }
  }
  /**
   * The function removes observers from a given HTML element node.
   *
   * @param {HTMLElement} node - The `node` parameter is an `HTMLElement` object representing an HTML element in the DOM (Document Object Model).
   * @param {VegaEventIDInterface} eventId The `eventId` parameter is of type `VegaEventIDInterface`. It represents the ID of a Vega event.
   */
  static removeUniqueObserverFromNode(node, eventId) {
    if (domNodeSubjectFactory.isExist(node, eventId)) {
      changeManager.ChangeManager.clearObserversBySubject(domNodeSubjectFactory.getSubject(node, eventId));
    }
  }
}

exports.DomNodeSubjectObserverFactory = DomNodeSubjectObserverFactory;
exports.domNodeSubjectFactory = domNodeSubjectFactory;
