function _check_private_redeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _class_private_method_get(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _class_private_method_init(obj, privateSet) {
    _check_private_redeclaration(obj, privateSet);
    privateSet.add(obj);
}
import moment from 'moment';
import Pikaday from '@handsontable/pikaday';
import { EDITOR_STATE } from '../baseEditor/index.mjs';
import { TextEditor } from '../textEditor/index.mjs';
import { addClass, hasClass, outerHeight, outerWidth } from '../../helpers/dom/element.mjs';
import { deepExtend } from '../../helpers/object.mjs';
import { isFunctionKey } from '../../helpers/unicode.mjs';
import { isMobileBrowser } from '../../helpers/browser.mjs';
import { deprecatedWarn } from '../../helpers/console.mjs';
import { throwWithCause } from '../../helpers/errors.mjs';
import { clamp } from '../../helpers/number.mjs';
export const EDITOR_TYPE = 'date';
const SHORTCUTS_GROUP_EDITOR = 'dateEditor';
const DEFAULT_DATE_FORMAT = 'DD/MM/YYYY';
const deprecatedMessageShown = new WeakSet();
var /**
   * Gets the current date format for this cell.
   *
   * @returns {string}
   */ _getDateFormat = /*#__PURE__*/ new WeakSet();
/**
 * @private
 * @class DateEditor
 */ export class DateEditor extends TextEditor {
    static get EDITOR_TYPE() {
        return EDITOR_TYPE;
    }
    init() {
        if (typeof moment !== 'function') {
            throwWithCause('You need to include moment.js to your project.');
        }
        if (typeof Pikaday !== 'function') {
            throwWithCause('You need to include Pikaday to your project.');
        }
        super.init();
        this.hot.addHook('afterDestroy', ()=>{
            this.parentDestroyed = true;
            this.destroyElements();
        });
        this.hot.addHook('afterSetTheme', (themeName, firstRun)=>{
            if (!firstRun) {
                this.close();
            }
        });
    }
    /**
   * Create data picker instance.
   */ createElements() {
        super.createElements();
        this.datePicker = this.hot.rootDocument.createElement('DIV');
        this.datePickerStyle = this.datePicker.style;
        this.datePickerStyle.position = 'absolute';
        this.datePickerStyle.top = 0;
        this.datePickerStyle.left = 0;
        this.datePickerStyle.zIndex = 9999;
        this.datePicker.setAttribute('dir', this.hot.isRtl() ? 'rtl' : 'ltr');
        addClass(this.datePicker, 'htDatepickerHolder');
        this.hot.rootPortalElement.appendChild(this.datePicker);
        /**
     * Prevent recognizing clicking on datepicker as clicking outside of table.
     */ this.eventManager.addEventListener(this.datePicker, 'mousedown', (event)=>{
            if (hasClass(event.target, 'pika-day')) {
                this.hideDatepicker();
            }
            event.stopPropagation();
        });
    }
    /**
   * Destroy data picker instance.
   */ destroyElements() {
        const datePickerParentElement = this.datePicker.parentNode;
        if (this.$datePicker) {
            this.$datePicker.destroy();
        }
        if (datePickerParentElement) {
            datePickerParentElement.removeChild(this.datePicker);
        }
    }
    /**
   * Prepare editor to appear.
   *
   * @param {number} row The visual row index.
   * @param {number} col The visual column index.
   * @param {number|string} prop The column property (passed when datasource is an array of objects).
   * @param {HTMLTableCellElement} td The rendered cell element.
   * @param {*} value The rendered value.
   * @param {object} cellProperties The cell meta object (see {@link Core#getCellMeta}).
   */ prepare(row, col, prop, td, value, cellProperties) {
        super.prepare(row, col, prop, td, value, cellProperties);
    }
    /**
   * Open editor.
   *
   * @param {Event} [event=null] The event object.
   */ open(event = null) {
        if (!deprecatedMessageShown.has(this.cellProperties.instance)) {
            deprecatedMessageShown.add(this.cellProperties.instance);
            deprecatedWarn('The Pikaday-based `date` editor is deprecated and will be removed in the next major release, ' + 'replaced by the native HTML date input.\n\n' + 'Migration guide: https://handsontable.com/docs/migration-from-16.2-to-17.0/\n' + '`date` cell type documentation: https://handsontable.com/docs/date-cell-type/');
        }
        const shortcutManager = this.hot.getShortcutManager();
        const editorContext = shortcutManager.getContext('editor');
        this.showDatepicker(event);
        super.open();
        editorContext.addShortcuts([
            {
                keys: [
                    [
                        'ArrowLeft'
                    ]
                ],
                callback: ()=>{
                    this.$datePicker.adjustDate('subtract', 1);
                }
            },
            {
                keys: [
                    [
                        'ArrowRight'
                    ]
                ],
                callback: ()=>{
                    this.$datePicker.adjustDate('add', 1);
                }
            },
            {
                keys: [
                    [
                        'ArrowUp'
                    ]
                ],
                callback: ()=>{
                    this.$datePicker.adjustDate('subtract', 7);
                }
            },
            {
                keys: [
                    [
                        'ArrowDown'
                    ]
                ],
                callback: ()=>{
                    this.$datePicker.adjustDate('add', 7);
                }
            }
        ], {
            group: SHORTCUTS_GROUP_EDITOR
        });
    }
    /**
   * Close editor.
   */ close() {
        // If the date picker was never initialized (e.g. during autofill), there's nothing to destroy.
        if (this.$datePicker?.destroy) {
            this.$datePicker.destroy();
        }
        this.hot._registerTimeout(()=>{
            const editorManager = this.hot._getEditorManager();
            editorManager.closeEditor();
            this.hot.view.render();
            editorManager.prepareEditor();
        });
        const shortcutManager = this.hot.getShortcutManager();
        const editorContext = shortcutManager.getContext('editor');
        editorContext.removeShortcutsByGroup(SHORTCUTS_GROUP_EDITOR);
        super.close();
    }
    /**
   * Finishes editing and start saving or restoring process for editing cell or last selected range.
   *
   * @param {boolean} restoreOriginalValue If true, then closes editor without saving value from the editor into a cell.
   * @param {boolean} ctrlDown If true, then saveValue will save editor's value to each cell in the last selected range.
   */ finishEditing(restoreOriginalValue = false, ctrlDown = false) {
        super.finishEditing(restoreOriginalValue, ctrlDown);
    }
    /**
   * Show data picker.
   *
   * @param {Event} event The event object.
   */ showDatepicker(event) {
        const dateFormat = _class_private_method_get(this, _getDateFormat, getDateFormat).call(this);
        const isMouseDown = this.hot.view.isMouseDown();
        const isMeta = event ? isFunctionKey(event.keyCode) : false;
        let dateStr;
        this.datePicker.style.display = 'block';
        this.$datePicker = new Pikaday(this.getDatePickerConfig());
        if (typeof this.$datePicker.useMoment === 'function') {
            this.$datePicker.useMoment(moment);
        }
        this.$datePicker._onInputFocus = function() {};
        if (this.originalValue) {
            dateStr = this.originalValue;
            if (moment(dateStr, dateFormat, true).isValid()) {
                this.$datePicker.setMoment(moment(dateStr, dateFormat), true);
            }
            // workaround for date/time cells - pikaday resets the cell value to 12:00 AM by default, this will overwrite the value.
            if (this.getValue() !== this.originalValue) {
                this.setValue(this.originalValue);
            }
            if (!isMeta && !isMouseDown) {
                this.setValue('');
            }
        } else if (this.cellProperties.defaultDate) {
            dateStr = this.cellProperties.defaultDate;
            if (moment(dateStr, dateFormat, true).isValid()) {
                this.$datePicker.setMoment(moment(dateStr, dateFormat), true);
            }
            if (!isMeta && !isMouseDown) {
                this.setValue('');
            }
        } else {
            // if a default date is not defined, set a soft-default-date: display the current day and month in the
            // datepicker, but don't fill the editor input
            this.$datePicker.gotoToday();
        }
    }
    /**
   * Hide data picker.
   */ hideDatepicker() {
        this.datePickerStyle.display = 'none';
        this.$datePicker.hide();
    }
    /**
   * Get date picker options.
   *
   * @returns {object}
   */ getDatePickerConfig() {
        const htInput = this.TEXTAREA;
        const options = {};
        if (this.cellProperties && this.cellProperties.datePickerConfig) {
            deepExtend(options, this.cellProperties.datePickerConfig);
        }
        const origOnSelect = options.onSelect;
        const origOnClose = options.onClose;
        options.field = htInput;
        options.trigger = htInput;
        options.container = this.datePicker;
        options.bound = false;
        options.keyboardInput = false;
        options.format = options.format ?? _class_private_method_get(this, _getDateFormat, getDateFormat).call(this);
        options.reposition = options.reposition || false;
        // Set the RTL to `false`. Due to the https://github.com/Pikaday/Pikaday/issues/647 bug, the layout direction
        // of the date picker is controlled by juggling the "dir" attribute of the root date picker element.
        // See line @64 of this file.
        options.isRTL = false;
        options.onSelect = (value)=>{
            let dateStr = value;
            if (!isNaN(dateStr.getTime())) {
                dateStr = moment(dateStr).format(_class_private_method_get(this, _getDateFormat, getDateFormat).call(this));
            }
            this.setValue(dateStr);
            if (origOnSelect) {
                origOnSelect();
            }
            if (isMobileBrowser()) {
                this.hideDatepicker();
            }
        };
        options.onClose = ()=>{
            if (!this.parentDestroyed) {
                this.finishEditing(false);
            }
            if (origOnClose) {
                origOnClose();
            }
        };
        return options;
    }
    /**
   * Refreshes datepicker's size and position. The method is called internally by Handsontable.
   *
   * @private
   * @param {boolean} force Indicates if the refreshing editor dimensions should be triggered.
   */ refreshDimensions(force) {
        super.refreshDimensions(force);
        if (this.state !== EDITOR_STATE.EDITING) {
            return;
        }
        this.TD = this.getEditedCell();
        if (!this.TD) {
            this.hideDatepicker();
            return;
        }
        const { rowIndexMapper, columnIndexMapper } = this.hot;
        const { wtOverlays } = this.hot.view._wt;
        const { wtTable } = wtOverlays.getParentOverlay(this.TD) ?? this.hot.view._wt;
        const firstVisibleRow = rowIndexMapper.getVisualFromRenderableIndex(wtTable.getFirstPartiallyVisibleRow());
        const lastVisibleRow = rowIndexMapper.getVisualFromRenderableIndex(wtTable.getLastPartiallyVisibleRow());
        const firstVisibleColumn = columnIndexMapper.getVisualFromRenderableIndex(wtTable.getFirstPartiallyVisibleColumn());
        const lastVisibleColumn = columnIndexMapper.getVisualFromRenderableIndex(wtTable.getLastPartiallyVisibleColumn());
        if (this.row >= firstVisibleRow && this.row <= lastVisibleRow && this.col >= firstVisibleColumn && this.col <= lastVisibleColumn) {
            const offset = this.TD.getBoundingClientRect();
            const pickerWidth = outerWidth(this.datePicker);
            const pickerHeight = outerHeight(this.datePicker);
            const cellHeight = outerHeight(this.TD);
            const win = this.hot.rootWindow;
            const doc = this.hot.rootDocument.documentElement;
            const viewportTop = win.pageYOffset;
            const viewportBottom = win.pageYOffset + doc.clientHeight;
            const viewportLeft = win.pageXOffset;
            const viewportRight = win.pageXOffset + doc.clientWidth;
            let top = viewportTop + offset.top + cellHeight;
            if (top + pickerHeight > viewportBottom) {
                const aboveCell = viewportTop + offset.top - pickerHeight;
                top = aboveCell >= viewportTop ? Math.max(viewportTop, aboveCell - 1) : viewportBottom - pickerHeight;
            }
            this.datePickerStyle.top = `${top}px`;
            const cellLeft = viewportLeft + offset.left;
            const cellRight = viewportLeft + offset.right;
            let pickerLeftPosition;
            if (this.hot.isRtl()) {
                pickerLeftPosition = cellRight - pickerWidth;
                if (pickerLeftPosition < viewportLeft) {
                    pickerLeftPosition = Math.min(cellLeft, viewportRight - pickerWidth);
                }
            } else {
                pickerLeftPosition = cellLeft;
                if (pickerLeftPosition + pickerWidth > viewportRight) {
                    pickerLeftPosition = Math.max(cellRight - pickerWidth, viewportLeft);
                }
            }
            pickerLeftPosition = clamp(pickerLeftPosition, viewportLeft, viewportRight - pickerWidth);
            this.datePickerStyle.left = `${pickerLeftPosition}px`;
        } else {
            this.hideDatepicker();
        }
    }
    constructor(...args){
        super(...args), _class_private_method_init(this, _getDateFormat), /**
   * @type {boolean}
   */ this.parentDestroyed = false, /**
   * @type {Pikaday}
   */ this.$datePicker = null;
    }
}
function getDateFormat() {
    return this.cellProperties.dateFormat ?? DEFAULT_DATE_FORMAT;
}
