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 { MapToComponentField, MapToComponentMethod, VegaSlimmer } from 'vega-slimmer/core';
/**
 * The `VegaVirtualScrollPositionController` class in TypeScript implements virtual scrolling functionality
 * by managing source data, item heights, viewport settings, and scroll positions.
 */
export class VegaVirtualScrollPositionController extends VegaSlimmer {
  constructor() {
    super(...arguments);
    this.extendItemsCount = 10;
    this.totalCount = 0;
    this.viewportItemsCount = 0;
  }
  /**
   * The componentWillLoad function is used to initialize virtual scrolling in a TypeScript component.
   */
  componentWillLoad() {
    this.initVirtualScroll();
    this.initPositionConfig();
  }
  /**
   * The function `watchSourceChange` initializes virtual scrolling if the source items have changed.
   *
   * @param {SourceItemType[]} newValue - newValue is an array of items of type SourceItemType that
   * represents the new source data.
   * @param {SourceItemType[]} oldValue - The `oldValue` parameter in the `watchSourceChange` function
   * represents the previous value of the source items before the change occurred. It is used to compare
   * with the new value (`newValue`) to determine if there has been a change in the source items.
   */
  watchSourceChange(newValue, oldValue) {
    if (!this.isSameSource(newValue, oldValue)) {
      this.initVirtualScroll();
    }
  }
  /**
   * The function `watchApproxItemHeight` initializes virtual scrolling.
   */
  watchApproxItemHeight() {
    this.initVirtualScroll();
  }
  /**
   * The function `watchViewportMaxHeight` initializes virtual scrolling.
   */
  watchViewportMaxHeight() {
    this.initVirtualScroll();
  }
  /**
   * Get maxStartIndex
   *
   * @returns {number} - maxStartIndex
   */
  getMaxStartIndex() {
    return this.maxStartIndex;
  }
  /**
   * While scrollTop of container change, the startIndex, endIndex, viewPortStartIndex and transformY will be change.
   * The following is the process of change:
   *
   *---scrollTop---startIndex---viewportStartIndex---endIndex---transformY
   *---30----------0------------0--------------------18---------0
   *---40----------0------------1--------------------19---------0
   *---320---------0------------8--------------------26---------0
   *---400---------0------------10-------------------28---------0
   *---480---------2------------12-------------------30---------80
   *---800---------10-----------20-------------------38---------400
   */
  setPositionByScrollTop() {
    if (this.modeController.getMode() === 'virtual') {
      const currentIndex = Math.floor(this.scrollTop / this.approxItemHeight);
      const startIndex = Math.min(Math.max(currentIndex - this.extendItemsCount, 0), this.maxStartIndex);
      const viewportStartIndex = startIndex === 0 ? currentIndex : startIndex + this.extendItemsCount;
      const endIndex = viewportStartIndex + this.viewportItemsCount + this.extendItemsCount;
      const transformY = Math.min(Math.max(this.scrollTop - this.extendItemsCount * this.approxItemHeight, 0), this.maxStartIndex * this.approxItemHeight);
      this.positionConfig = { startIndex, viewportStartIndex, endIndex, transformY };
    }
  }
  /**
   * While mode change from `normal` to `virtual`, we should init virtual scroll and set the position.
   */
  changeModeFromNormalToVirtual() {
    this.initVirtualScroll();
    this.setPositionByScrollTop();
  }
  /**
   * The function `initVirtualScroll` initializes variables for a virtual scrolling feature in a
   * TypeScript component.
   */
  initVirtualScroll() {
    if (this.modeController.getMode() === 'virtual') {
      this.totalCount = this.source.length;
      this.viewportItemsCount = Math.ceil(this.viewportMaxHeight / this.approxItemHeight);
      this.maxStartIndex = this.totalCount - this.viewportItemsCount - this.extendItemsCount;
    }
  }
  /**
   * Init positionConfig while componentWillLoad
   */
  initPositionConfig() {
    this.positionConfig = {
      startIndex: 0,
      viewportStartIndex: 0,
      endIndex: this.viewportItemsCount + this.extendItemsCount,
      transformY: 0,
    };
    this.scrollableController.resetScrollTop();
  }
  /**
   * The function `isSameSource` compares two arrays of objects based on a specific identifier and
   * returns true if they are the same.
   *
   * @param {SourceItemType[]} first - `first` is an array of `SourceItemType` elements.
   * @param {SourceItemType[]} second - The `second` parameter in the `isSameSource` method is an array
   * of `SourceItemType` elements.
   * @returns {boolean} The `isSameSource` method is returning a boolean value, either `true` or `false`. It checks
   * if the `first` and `second` arrays of `SourceItemType` objects have the same length and if the
   * `sourceItemIdentifier` property of each object at the same index in both arrays is equal. If all
   * conditions are met, it returns `true`, otherwise it returns `
   */
  isSameSource(first, second) {
    if (first.length !== second.length)
      return false;
    for (let i = 0; i < first.length; i++) {
      if (first[i][this.sourceItemIdentifier] !== second[i][this.sourceItemIdentifier]) {
        return false;
      }
    }
    /* istanbul ignore next */
    return true;
  }
}
__decorate([
  MapToComponentField()
], VegaVirtualScrollPositionController.prototype, "sourceItemIdentifier", void 0);
__decorate([
  MapToComponentField()
], VegaVirtualScrollPositionController.prototype, "source", void 0);
__decorate([
  MapToComponentField()
], VegaVirtualScrollPositionController.prototype, "approxItemHeight", void 0);
__decorate([
  MapToComponentField()
], VegaVirtualScrollPositionController.prototype, "viewportMaxHeight", void 0);
__decorate([
  MapToComponentField({ writable: true })
], VegaVirtualScrollPositionController.prototype, "positionConfig", void 0);
__decorate([
  MapToComponentField()
], VegaVirtualScrollPositionController.prototype, "scrollTop", void 0);
__decorate([
  MapToComponentField()
], VegaVirtualScrollPositionController.prototype, "scrollableController", void 0);
__decorate([
  MapToComponentField()
], VegaVirtualScrollPositionController.prototype, "modeController", void 0);
__decorate([
  MapToComponentMethod('componentWillLoad')
], VegaVirtualScrollPositionController.prototype, "componentWillLoad", null);
__decorate([
  MapToComponentMethod('watchSourceChange')
], VegaVirtualScrollPositionController.prototype, "watchSourceChange", null);
__decorate([
  MapToComponentMethod('watchApproxItemHeight')
], VegaVirtualScrollPositionController.prototype, "watchApproxItemHeight", null);
__decorate([
  MapToComponentMethod('watchViewportMaxHeight')
], VegaVirtualScrollPositionController.prototype, "watchViewportMaxHeight", null);
