'use strict';

const globalSlimmerRegistry = require('./global-slimmer-registry-b3bce7e0.js');
const internalVegaEventManager = require('./internal-vega-event-manager-fef893bf.js');
const vegaEnvManager = require('./vega-env-manager-23b8b23c.js');
const featureFlagController = require('./feature-flag-controller-9129ef52.js');

var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
/** The ChildNodesEventPreventSlimmer class prevents specified events from propagating to parent elements. */
class ChildNodesEventPreventSlimmer extends globalSlimmerRegistry.VegaSlimmer {
  /**
   * The constructor function takes in an array of event names and a function to get the parent element, and assigns them to the corresponding properties of the class.
   *
   * @param {VegaEventID[]} eventIds - The eventNames parameter is an array of VegaEventID that represents the names of the events that will be handled by the constructor.
   * @param {HTMLElement} getHostElement - The `getHostElement` parameter is a function that returns an `HTMLElement`. It is used to get the parent element where the events will be attached.
   * @param {boolean | EventPreventOptions} options - add event listener in capture or bubbles.
   * @param {boolean | EventPreventOptions} needSkipByDefault - should skip event prevent by default
   */
  constructor(eventIds, getHostElement, options, needSkipByDefault) {
    super();
    // the event names need prevent from child nodes
    this.eventIds = [];
    this.useCapture = false;
    this.isEventListenerAdded = false;
    this.disabled = false;
    /**
     * prevent the child event
     *
     * @param {CustomEvent} event event object
     */
    this.preventChildEvent = (event) => {
      const hostElement = this.getHostElement();
      if (this.shouldSkipEventPrevent()) {
        return;
      }
      if (typeof this.customPreventHandle === 'function') {
        this.customPreventHandle(event);
      }
      else {
        const composed = event.composedPath();
        if (hostElement !== event.target || hostElement !== composed[0]) {
          event.stopImmediatePropagation();
        }
      }
    };
    this.eventIds = eventIds;
    this.getHostElement = getHostElement;
    if (options === true) {
      this.useCapture = true;
    }
    else if (options) {
      const { useCapture = false, customPreventHandle } = options;
      this.useCapture = useCapture;
      this.customPreventHandle = customPreventHandle;
    }
    this.disabled = needSkipByDefault === true ? true : false;
  }
  /**
   * add event listener when component connected, we can call the method manually if the host element not ready when connectedCallback
   */
  setup() {
    this.addOrRemoveEventListener('add');
  }
  /**
   * if the host element ready after component did load, then add the event listener again.
   */
  checkEventListenerStatus() {
    if (!this.isEventListenerAdded) {
      this.setup();
    }
    this.setSkipEventPreventFlag();
  }
  /**
   * remove the event listener when component disconnect
   */
  destroy() {
    this.addOrRemoveEventListener('remove');
  }
  /**
   * The function `setSkipEventPreventFlag` sets a flag on a host element to skip event prevention under certain conditions.
   */
  setSkipEventPreventFlag() {
    if (featureFlagController.FeatureFlag.isEnabled('VEGA_REACT.SKIP_NATIVE_EVENT_PREVENT_BY_DEFAULT') &&
      this.disabled &&
      this.host &&
      vegaEnvManager.vegaEnvManager.getVegaEnv().framework === 'react' &&
      internalVegaEventManager.internalVegaEventManager.getSemantics(this.host).namespace === 'native') {
      const el = this.getHostElement();
      el.setAttribute('data-vega-no-event-prevent', 'true');
    }
  }
  /**
   * add or remove the event from the parent element
   *
   * @param {'add'|'remove'} actionType add or remove
   */
  addOrRemoveEventListener(actionType) {
    const hostElement = this.getHostElement();
    if (this.eventIds && this.eventIds.length && hostElement) {
      this.eventIds
        .filter((eventID) => this.shouldPrevent(eventID))
        .forEach((eventID) => {
        hostElement[actionType === 'add' ? 'addEventListener' : 'removeEventListener'](this.getCurrentEventName(eventID), this.preventChildEvent, this.useCapture);
      });
      this.isEventListenerAdded = actionType === 'add' ? true : false;
    }
  }
  /**
   * get the current event name
   *
   * @param {VegaEventID} eventId event id class
   * @returns {string} native or vega event name string
   */
  getCurrentEventName(eventId) {
    return eventId.getCurrentName(internalVegaEventManager.internalVegaEventManager.getSemantics(this.host));
  }
  /**
   * The function shouldPrevent checks if a given event ID should be prevented based on whether it is a
   * native event and if it is enabled for the host.
   *
   * @param {VegaEventID} eventId - The `eventId` parameter is of type `VegaEventID`. It represents the ID of an event.
   * @returns {boolean} a boolean value.
   */
  shouldPrevent(eventId) {
    const { namespace, jqueryDelegatedEvent } = internalVegaEventManager.internalVegaEventManager.getSemantics(this.host);
    return !(namespace === 'native' &&
      !!jqueryDelegatedEvent &&
      internalVegaEventManager.jqueryDelegatedStrategyController.isSupportDelegated(this.host, eventId));
  }
  /**
   * The function `shouldSkipEventPrevent` checks if a host element has a specific dataset value to determine whether event prevention should be skipped.
   *
   * @returns {boolean} If the `hostElement` exists and has a `dataset.vegaNoEventPrevent` attribute with a value of `'true'`, then the function returns `true`. Otherwise, it returns `false`.
   */
  shouldSkipEventPrevent() {
    const hostElement = this.getHostElement();
    return hostElement && hostElement.dataset.vegaNoEventPrevent === 'true';
  }
}
__decorate([
  globalSlimmerRegistry.MapToComponentField()
], ChildNodesEventPreventSlimmer.prototype, "host", void 0);
__decorate([
  globalSlimmerRegistry.MapToComponentMethod('connectedCallback')
], ChildNodesEventPreventSlimmer.prototype, "setup", null);
__decorate([
  globalSlimmerRegistry.MapToComponentMethod('componentDidLoad')
], ChildNodesEventPreventSlimmer.prototype, "checkEventListenerStatus", null);
__decorate([
  globalSlimmerRegistry.MapToComponentMethod('disconnectedCallback')
], ChildNodesEventPreventSlimmer.prototype, "destroy", null);

exports.ChildNodesEventPreventSlimmer = ChildNodesEventPreventSlimmer;
