var __decorate = (this && this.__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;
};
import { Component, Element, h, Host, Method, Prop, State, Watch, Event } from '@stencil/core';
import { SynchronizeTaskQueue } from '../../helpers/queue/synchronize-task-queue';
import { TouchDirection, TouchListener } from '../../helpers/touch-helper/touch-listener';
import { createEnterKeyHandlerToTriggerClick } from '../../utils/accessibility';
import { sanitizeVegaComponent } from '../../utils/component';
import { executeAfterTransition, reflow } from '../../utils/effect';
import ResponsiveFormatFacade from '../../helpers/formatter/responsive-map-formatter/responsive-format-facade';
import { InjectVegaGlobalSlimmer, InjectVegaSlimmer } from 'vega-slimmer/core';
import { PageResizeObserverSlimmer } from '../../helpers/slimmers/page-resize-observer-slimmer';
import { createEventEmitSlimmer, } from '../../helpers/event-manager/slimmers/event-emit-slimmer';
import { VegaPageUpdate } from '../../helpers/event-manager/event-id/vega-event-id';
import { createDeprecatedPropertySlimmer, } from '../../helpers/slimmers/deprecated-property-slimmer';
import { VegaComponentUsageRuntimeMetricsSlimmer } from '../../helpers/slimmers/component-usage-runtime-metrics';
import { VegaCarouselRuntimeMetricsPayloadDefinition } from '../../constants/runtime-metrics-payload-definition/vega-carousel/runtime-metrics-payload-definition';
import { tryGetDocument } from '../../utils/try-get-document';
/**
 * @vegaVersion 1.0.2
 */
export class VegaCarousel {
  constructor() {
    this.globalSlimmers = {};
    this.vegaComponentUsageRuntimeMetricsSlimmer = new VegaComponentUsageRuntimeMetricsSlimmer(VegaCarouselRuntimeMetricsPayloadDefinition);
    this.pageResizeObserverSlimmer = new PageResizeObserverSlimmer({
      callback: /* istanbul ignore next */ () => {
        if (this.getCarouselItemsPerPage() !== this.currentItemsPerPage) {
          this.updatePageLayout();
        }
      },
    });
    this.pageUpdateEventEmitter = createEventEmitSlimmer(VegaCarousel, VegaPageUpdate);
    this.deprecatedPropertySlimmer = createDeprecatedPropertySlimmer(VegaCarousel, 'itemsPerPage', 'perPage', 1);
    this.carouselContentElements = [];
    this.slideTaskQueue = new SynchronizeTaskQueue();
    this.currentItemsPerPage = 1;
    this.page = 1;
    /**
     * Specifies the number of elements displayed per page in the carousel.
     * @deprecated This property will be removed soon and replaced by prop itemsPerPage
     *
     * @vegaVersion 1.0.2
     */
    this.perPage = 1;
    /**
     * Specifies the number of items displayed per page in the carousel.
     *
     * @vegaVersion 2.1.0
     */
    this.itemsPerPage = 1;
    /**
     * Specifies whether to show the navigational buttons
     *    at the bottom of the carousel.
     *
     * @vegaVersion 1.0.2
     */
    this.showSlider = true;
    /**
     * Controls the amount of space between the elements in the carousel
     *    when more than one element is displayed on each page
     *    using the `itemsPerPage` property.
     *
     * @vegaVersion 1.0.2
     */
    this.spacing = 'size-16';
    /**
     * Indicates whether the carousel can be swiped
     *    to navigate between pages on a mobile device.
     *
     * @vegaVersion 1.18.0
     */
    this.canSwipe = true;
    this.onClickIndicators = async (e) => {
      const target = e.currentTarget;
      const targetPage = Number(target.dataset.page);
      await this.goToPage(targetPage);
    };
    /**
     * Get the total page that will be shown in carousel.
     */
    this.getTotalPage = () => {
      const count = this.carouselContentElements.length;
      return Math.ceil(count / this.currentItemsPerPage);
    };
    this.updatePageLayout = () => {
      this.currentItemsPerPage = this.getCarouselItemsPerPage();
      this.totalPages = this.getTotalPage();
      this.page = 1;
      this.wrapChildContentAsCarouselItem();
    };
    /**
     * The below method is e2e-test covered in
     * @see{module:vega-carousel-call-observe-method}
     */
    /* istanbul ignore next */
    this.initMutationObserver = () => {
      this.mutationObserver = new MutationObserver(async () => {
        await this.updateContentByObserverSlotChange();
      });
      this.mutationObserver.observe(this.host, { childList: true });
    };
    /**
     * The below method is e2e-test covered in
     * @see{module:vega-carousel-with-touch-event}
     */
    /* istanbul ignore next */
    this.initTouchEvent = () => {
      this.touchListener = TouchListener.init({
        touchable: this.listContainer,
        onTouchEnd: async (direction) => {
          const pageDelta = direction === TouchDirection.RIGHT ? -1 : direction === TouchDirection.LEFT ? 1 : 0;
          const nextPage = this.page + pageDelta;
          await this.goToPage(nextPage);
        },
      });
    };
  }
  watchPage() {
    this.pageUpdateEventEmitter.emit(this.page);
  }
  watchPerPage() {
    this.updatePageLayout();
  }
  watchItemsPerPage() {
    this.updatePageLayout();
  }
  onSpacingPropsChange() {
    const carouselItems = this.host.querySelectorAll('vega-grid');
    carouselItems.forEach((item) => {
      item.gap = this.spacing;
    });
  }
  disconnectedCallback() {
    if (this.mutationObserver) {
      this.mutationObserver.disconnect();
    }
    if (this.touchListener) {
      this.touchListener.destroy();
    }
  }
  componentDidLoad() {
    this.carouselContentElements = Array.from(this.host.children);
    this.updatePageLayout();
    this.initMutationObserver();
    this.initTouchEvent();
  }
  /**
   * Invoke this method to transition the carousel to the next available page,
   *    if it exists.
   *
   * @vegaVersion 1.0.2
   */
  async nextPage() {
    const nextPage = this.page < this.totalPages ? this.page + 1 : this.page;
    await this.goToPage(nextPage);
  }
  /**
   * Invoke this method to transition the carousel to the previous page,
   *    if it exists.
   *
   * @vegaVersion 1.0.2
   */
  async prevPage() {
    const nextPage = this.page > 1 ? this.page - 1 : this.page;
    await this.goToPage(nextPage);
  }
  /**
   * Invoke this method to navigate the carousel to the specified page number.
   *
   * @param nextPage
   * @returns {Promise<void>}
   * @vegaVersion 1.0.6
   */
  async goToPage(nextPage) {
    await this.goToPageInternal(nextPage);
  }
  render() {
    return sanitizeVegaComponent(h(Host, null,
      h("div", { class: {
          'carousel-inner': true,
          'carousel-stop-swipe': !this.canSwipe,
        }, ref: (el) => (this.listContainer = el) },
        h("slot", null)),
      this.renderIndicatorDom()), this.host);
  }
  /**
   * The function `goToPageInternal` is used to navigate to a specific page in a slideshow, with an optional animation.
   *
   * @param {number} nextPage - The `nextPage` parameter is the page number that you want to navigate to. It should be a number between 1 and the total number of pages (`this.totalPages`).
   * @param {boolean} [needsAnimation=true] - The `needsAnimation` parameter is a boolean value that
   * indicates whether or not the slide animation should be performed when navigating to the next page.
   * If `needsAnimation` is `true`, the slide animation will be performed. If `needsAnimation` is
   * `false`, the slide animation will be disabled
   */
  async goToPageInternal(nextPage, needsAnimation = true) {
    if (nextPage >= 1 && nextPage <= this.totalPages) {
      if (nextPage !== this.page) {
        this.page = nextPage;
        await this.slideTaskQueue.enqueue({
          run: () => {
            return this.doSlide(nextPage, needsAnimation);
          },
        });
      }
    }
  }
  renderIndicatorDom() {
    return (this.showSlider && (h("div", { class: "vega-carousel-indicators-container" }, new Array(this.totalPages).fill('').map((_, index) => {
      return (h("div", { key: index, class: {
          'vega-carousel-indicator-active': index + 1 === this.page,
        }, "data-page": index + 1, role: 'button', "aria-label": "No label defined", tabIndex: 0, onKeyDown: createEnterKeyHandlerToTriggerClick(), onClick: this.onClickIndicators }));
    }))));
  }
  /**
   * The below method is e2e-test covered in
   * @see{module:vega-carousel-call-observe-method}
   */
  /* istanbul ignore next */
  async updateContentByObserverSlotChange() {
    const initPage = this.page;
    const unManagedContentElements = Array.from(this.host.children).filter((element) => !element.classList.contains('carousel-item'));
    const currentCarouselContentElements = Array.from(this.host.querySelectorAll('.carousel-item vega-grid > div > *'));
    if (currentCarouselContentElements.length !== this.carouselContentElements.length ||
      unManagedContentElements.length > 0) {
      this.carouselContentElements = currentCarouselContentElements.concat(unManagedContentElements);
      this.updatePageLayout();
    }
    await this.goToPageInternal(initPage, false);
  }
  wrapChildContentAsCarouselItem() {
    const carouselItemWrapperList = [];
    const carouselContentElementArray = this.carouselContentElements;
    if (tryGetDocument()) {
      for (let j = 0; j < this.totalPages; j++) {
        const carouselItemWrapper = tryGetDocument().createElement('vega-grid');
        carouselItemWrapper.setAttribute('gap', this.spacing);
        carouselItemWrapper.setAttribute('column', this.currentItemsPerPage.toString());
        carouselItemWrapper.setAttribute('row', '1');
        for (let i = j * this.currentItemsPerPage; i < carouselContentElementArray.length && i < this.currentItemsPerPage * (j + 1); i++) {
          const divInner = tryGetDocument().createElement('div');
          divInner.appendChild(carouselContentElementArray[i]);
          carouselItemWrapper.appendChild(divInner);
        }
        const divOuter = tryGetDocument().createElement('div');
        divOuter.classList.add('carousel-item');
        j === 0 && divOuter.classList.add('active');
        divOuter.appendChild(carouselItemWrapper);
        carouselItemWrapperList.push(divOuter);
      }
      this.host.replaceChildren(...carouselItemWrapperList);
    }
  }
  /**
   * 1.make targetItem from translateX(-/+100%) to translateX(0).
   * 2.make activeItem from translateX(0) to translateX(-/+100%).
   * 3.clear up the added class and mark the current visible item as active.
   * The below method is e2e-test covered in
   * @see{module:vega-carousel-do-slide}
   * @see{module:vega-carousel-do-slide-in-order}
   */
  /* istanbul ignore next */
  doSlide(nextPage, needsAnimation) {
    return new Promise((resolve, reject) => {
      const activeItem = this.host.querySelector('.active');
      const isNext = nextPage - 1 > Array.from(this.host.children).indexOf(activeItem);
      const targetItem = this.host.children[nextPage - 1];
      const directionalClassName = isNext ? 'carousel-item-start' : 'carousel-item-end';
      const orderClassName = isNext ? 'carousel-item-next' : 'carousel-item-prev';
      if (activeItem && targetItem) {
        if (needsAnimation) {
          targetItem.classList.add(orderClassName);
          reflow(targetItem);
          targetItem.classList.add(directionalClassName);
          activeItem.classList.add(directionalClassName);
          executeAfterTransition(() => {
            targetItem.classList.remove(directionalClassName, orderClassName);
            activeItem.classList.remove('active', directionalClassName);
            targetItem.classList.add('active');
            resolve();
          }, activeItem, 600);
        }
        else {
          activeItem.classList.remove('active');
          reflow(targetItem);
          targetItem.classList.add('active');
          resolve();
        }
      }
      else {
        reject('Cannot find active and target item in carousel list');
      }
    });
  }
  /**
   * The below method is e2e-test covered in
   * @see{module:vega-carousel-with-screen-switch-mobile}
   */
  /* istanbul ignore next */
  getCarouselItemsPerPage() {
    const itemsPerPage = ResponsiveFormatFacade.formatCustom(this.deprecatedPropertySlimmer.getValue());
    if (itemsPerPage) {
      return Math.max(1, Math.min(4, itemsPerPage, this.carouselContentElements.length));
    }
    else {
      return 1;
    }
  }
  static get is() { return "vega-carousel"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() { return {
    "$": ["vega-carousel.scss"]
  }; }
  static get styleUrls() { return {
    "$": ["vega-carousel.css"]
  }; }
  static get properties() { return {
    "perPage": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "ResponsiveType<number>",
        "resolved": "number | { S?: number; M?: number; L?: number; XL?: number; default?: number; }",
        "references": {
          "ResponsiveType": {
            "location": "import",
            "path": "../../types/ui.type"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [{
            "name": "deprecated",
            "text": "This property will be removed soon and replaced by prop itemsPerPage"
          }, {
            "name": "vegaVersion",
            "text": "1.0.2"
          }],
        "text": "Specifies the number of elements displayed per page in the carousel."
      },
      "attribute": "per-page",
      "reflect": false,
      "defaultValue": "1"
    },
    "itemsPerPage": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "ResponsiveType<number>",
        "resolved": "number | { S?: number; M?: number; L?: number; XL?: number; default?: number; }",
        "references": {
          "ResponsiveType": {
            "location": "import",
            "path": "../../types/ui.type"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [{
            "name": "vegaVersion",
            "text": "2.1.0"
          }],
        "text": "Specifies the number of items displayed per page in the carousel."
      },
      "attribute": "items-per-page",
      "reflect": false,
      "defaultValue": "1"
    },
    "showSlider": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [{
            "name": "vegaVersion",
            "text": "1.0.2"
          }],
        "text": "Specifies whether to show the navigational buttons\n   at the bottom of the carousel."
      },
      "attribute": "show-slider",
      "reflect": false,
      "defaultValue": "true"
    },
    "spacing": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "SpacingTokenType",
        "resolved": "\"0\" | \"size-112\" | \"size-12\" | \"size-16\" | \"size-2\" | \"size-20\" | \"size-24\" | \"size-32\" | \"size-4\" | \"size-40\" | \"size-48\" | \"size-64\" | \"size-72\" | \"size-8\" | \"size-80\"",
        "references": {
          "SpacingTokenType": {
            "location": "import",
            "path": "../../types/design-token.type"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [{
            "name": "vegaVersion",
            "text": "1.0.2"
          }],
        "text": "Controls the amount of space between the elements in the carousel\n   when more than one element is displayed on each page\n   using the `itemsPerPage` property."
      },
      "attribute": "spacing",
      "reflect": false,
      "defaultValue": "'size-16'"
    },
    "canSwipe": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [{
            "name": "vegaVersion",
            "text": "1.18.0"
          }],
        "text": "Indicates whether the carousel can be swiped\n   to navigate between pages on a mobile device."
      },
      "attribute": "can-swipe",
      "reflect": false,
      "defaultValue": "true"
    }
  }; }
  static get states() { return {
    "page": {},
    "totalPages": {}
  }; }
  static get events() { return [{
      "method": "vegaPageUpdate",
      "name": "vegaPageUpdate",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [{
            "name": "vegaVersion",
            "text": "1.3.0"
          }],
        "text": "An event emitter notifying the transition of the carousel to another page,\n   whether triggered programmatically or through user interaction."
      },
      "complexType": {
        "original": "number",
        "resolved": "number",
        "references": {}
      }
    }, {
      "method": "pageUpdate",
      "name": "pageUpdate",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [{
            "name": "eventSemantics",
            "text": "namespace:native"
          }, {
            "name": "vegaVersion",
            "text": "2.0.0"
          }],
        "text": "An event emitter notifying the transition of the carousel to another page,\n   whether triggered programmatically or through user interaction."
      },
      "complexType": {
        "original": "number",
        "resolved": "number",
        "references": {}
      }
    }]; }
  static get methods() { return {
    "nextPage": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Invoke this method to transition the carousel to the next available page,\n   if it exists.",
        "tags": [{
            "name": "vegaVersion",
            "text": "1.0.2"
          }]
      }
    },
    "prevPage": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Invoke this method to transition the carousel to the previous page,\n   if it exists.",
        "tags": [{
            "name": "vegaVersion",
            "text": "1.0.2"
          }]
      }
    },
    "goToPage": {
      "complexType": {
        "signature": "(nextPage: number) => Promise<void>",
        "parameters": [{
            "tags": [{
                "name": "param",
                "text": "nextPage"
              }],
            "text": ""
          }],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Invoke this method to navigate the carousel to the specified page number.",
        "tags": [{
            "name": "param",
            "text": "nextPage"
          }, {
            "name": "returns",
            "text": undefined
          }, {
            "name": "vegaVersion",
            "text": "1.0.6"
          }]
      }
    }
  }; }
  static get elementRef() { return "host"; }
  static get watchers() { return [{
      "propName": "page",
      "methodName": "watchPage"
    }, {
      "propName": "perPage",
      "methodName": "watchPerPage"
    }, {
      "propName": "itemsPerPage",
      "methodName": "watchItemsPerPage"
    }, {
      "propName": "spacing",
      "methodName": "onSpacingPropsChange"
    }]; }
}
__decorate([
  InjectVegaGlobalSlimmer()
], VegaCarousel.prototype, "globalSlimmers", void 0);
__decorate([
  InjectVegaSlimmer()
], VegaCarousel.prototype, "vegaComponentUsageRuntimeMetricsSlimmer", void 0);
__decorate([
  InjectVegaSlimmer()
], VegaCarousel.prototype, "pageResizeObserverSlimmer", void 0);
__decorate([
  InjectVegaSlimmer()
], VegaCarousel.prototype, "pageUpdateEventEmitter", void 0);
__decorate([
  InjectVegaSlimmer()
], VegaCarousel.prototype, "deprecatedPropertySlimmer", void 0);
