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 } from 'vega-slimmer/core';
import { isArrayEqual } from '../../../../../utils/array';
import { VegaDatePickerCalendarStateBaseAbstract } from './vega-date-picker-calendar-state-base.abstract';
import { CalendarSelection } from '../../dto/calendar-selection';
import changeManager from '../../../../../helpers/change-manager/change-manager';
import domNodeSubjectFactory from '../../../../../helpers/change-manager/subject/dom-node-subject/dom-node-subject-factory';
import { VegaInternalDatePickerCalendarUpdatePeriodByUser } from '../../../../../helpers/event-manager/event-id/vega-internal-event-id';
/** Selection controller */
export class VegaDatePickerCalendarSelectionController extends VegaDatePickerCalendarStateBaseAbstract {
  /** componentWillLoad */
  componentWillLoad() {
    this.setCalendarSelectionBySelection(this.selection);
  }
  /**
   * Listen selection changed
   *
   * @param {DatePickerValueType<DatePickerModeType>} newSelection - newSelection.
   */
  watchSelection(newSelection) {
    const isChangeByUser = !this.isSameSelection(newSelection, this.calendarSelection.toSelection(this.format));
    // If the user changes the selection via property, we need to update the current period and set the calendar selection.
    //   otherwise, we don't need to update.
    if (isChangeByUser) {
      this.setCalendarSelectionBySelection(newSelection);
      this.notifyPeriodChange();
    }
  }
  /** Reset selecting range date */
  resetRange() {
    const usePrevious = !this.calendarSelection.isCompleted() &&
      !this.calendarSelection.isEmpty() &&
      !!this.previousCalendarSelection;
    this.setCalendarSelectionBySelection(usePrevious ? this.previousCalendarSelection.toSelection(this.format) : this.selection);
    this.hoverDate = null;
  }
  /** Listen calendarSelection changed */
  watchCalendarSelection() {
    if (this.calendarSelection.isCompleted() || this.calendarSelection.isEmpty()) {
      this.setSelection(this.calendarSelection.toSelection(this.format));
    }
  }
  /** Clear the current selection */
  clear() {
    this.setCalendarSelectionByRange(null, null);
    this.hoverDate = null;
  }
  /**
   * Listen the day be clicked.
   *
   * @param {CalendarDate} day - clicked day.
   */
  onDayClick(day) {
    if (this.mode === 'single') {
      this.setCalendarSelectionByRange(day, day);
    }
    else if (this.mode === 'range') {
      if (this.calendarSelection.startDate && !this.calendarSelection.endDate) {
        // It second click of range mode, we should set min date as start and max date as end.
        // As also, the select action have completed, we should set the value same time.
        this.setCalendarSelectionByRange(this.calendarSelection.startDate, day);
      }
      else if (!this.calendarSelection.startDate && this.calendarSelection.endDate) {
        this.setCalendarSelectionByRange(this.calendarSelection.endDate, day);
      }
      else {
        // It first click of range mode, we only set start date.
        this.setCalendarSelectionByRange(day, null);
      }
      this.hoverDate = null;
    }
  }
  /**
   * Listen the day be hovered.
   * Need set the hoverDate after the first click in range mode.
   * For repick, we should clear start or end date according the input which have been clicked.
   * Note: repick is working at hover any day in range.
   *
   * @param {CalendarDate} day - hovered day.
   */
  onDayHover(day) {
    const clickedInputType = this.allowRepickController.getRepickType();
    if (clickedInputType && this.mode === 'range' && this.calendarSelection.isCompleted()) {
      clickedInputType === 'start'
        ? this.setCalendarSelectionByRange(null, this.calendarSelection.endDate)
        : this.setCalendarSelectionByRange(this.calendarSelection.startDate, null);
    }
    if (!this.calendarSelection.isEmpty() && !this.calendarSelection.isCompleted()) {
      this.hoverDate = day;
    }
  }
  /**
   * Sets calendar selection for date picker calendar based on selection value.
   *
   * @param {DatePickerValueType<DatePickerModeType>} selection - selection.
   */
  setCalendarSelectionBySelection(selection) {
    const calendarSelection = CalendarSelection.fromSelection(selection, this.mode, this.format);
    if (this.calendarSelection &&
      (this.calendarSelection.isCompleted() || this.calendarSelection.isEmpty())) {
      this.previousCalendarSelection = this.calendarSelection;
    }
    if (!calendarSelection.equals(this.calendarSelection)) {
      this.calendarSelection = calendarSelection;
    }
    // we should reset the selection while calendarSelection changed from inner,
    //     such as reversed range correction.
    this.setSelection(calendarSelection.toSelection(this.format));
  }
  /**
   * Sets calendar selection for date picker calendar based on range dates.
   *
   * @param {Nullable<CalendarDate>} startDate - startDate.
   * @param {Nullable<CalendarDate>} endDate - endDate.
   */
  setCalendarSelectionByRange(startDate, endDate) {
    this.calendarSelection = new CalendarSelection(startDate, endDate, this.mode);
  }
  /**
   * Sets selection for date picker calendar and emits a change event with the new value.
   *
   * @param {DatePickerValueType<DatePickerModeType>} selection - selection.
   */
  setSelection(selection) {
    if (!this.isSameSelection(selection, this.selection)) {
      this.selection = selection;
      this.vegaSelectionChangeEventEmitter.emit(this.selection);
    }
  }
  /**
   * Check the previous selection and current selection is same.
   *
   * @param {DatePickerValueType<DatePickerModeType>} previous - New selection.
   * @param {DatePickerValueType<DatePickerModeType>} current - Old selection.
   * @returns {boolean} -
   */
  isSameSelection(previous, current) {
    if (this.mode === 'range' && Array.isArray(previous) && Array.isArray(current)) {
      return isArrayEqual(previous, current);
    }
    return previous === current;
  }
  /** Notify to update current period */
  notifyPeriodChange() {
    changeManager.notify(domNodeSubjectFactory.getSubject(this.host, VegaInternalDatePickerCalendarUpdatePeriodByUser), {});
  }
}
__decorate([
  MapToComponentField()
], VegaDatePickerCalendarSelectionController.prototype, "host", void 0);
__decorate([
  MapToComponentField()
], VegaDatePickerCalendarSelectionController.prototype, "mode", void 0);
__decorate([
  MapToComponentField()
], VegaDatePickerCalendarSelectionController.prototype, "format", void 0);
__decorate([
  MapToComponentField({ writable: true })
], VegaDatePickerCalendarSelectionController.prototype, "selection", void 0);
__decorate([
  MapToComponentField({ writable: true })
], VegaDatePickerCalendarSelectionController.prototype, "calendarSelection", void 0);
__decorate([
  MapToComponentField({ writable: true })
], VegaDatePickerCalendarSelectionController.prototype, "hoverDate", void 0);
__decorate([
  MapToComponentField()
], VegaDatePickerCalendarSelectionController.prototype, "clearEventEmitter", void 0);
__decorate([
  MapToComponentField()
], VegaDatePickerCalendarSelectionController.prototype, "vegaSelectionChangeEventEmitter", void 0);
__decorate([
  MapToComponentField()
], VegaDatePickerCalendarSelectionController.prototype, "allowRepickController", void 0);
__decorate([
  MapToComponentField()
], VegaDatePickerCalendarSelectionController.prototype, "translationSlimmer", void 0);
__decorate([
  MapToComponentMethod('componentWillLoad')
], VegaDatePickerCalendarSelectionController.prototype, "componentWillLoad", null);
__decorate([
  MapToComponentMethod('watchSelection')
], VegaDatePickerCalendarSelectionController.prototype, "watchSelection", null);
__decorate([
  MapToComponentMethod('reset')
], VegaDatePickerCalendarSelectionController.prototype, "resetRange", null);
__decorate([
  MapToComponentMethod('watchCalendarSelection')
], VegaDatePickerCalendarSelectionController.prototype, "watchCalendarSelection", null);
