/**
 * DevExtreme (esm/ui/date_box/ui.date_box.base.js)
 * Version: 23.2.6 (build 24140-0112)
 * Build date: Sun May 19 2024
 *
 * Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED
 * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
 */
import {
    getWindow,
    hasWindow
} from "../../core/utils/window";
var window = getWindow();
import {
    isDate as isDateType,
    isString,
    isNumeric
} from "../../core/utils/type";
import {
    createTextElementHiddenCopy
} from "../../core/utils/dom";
import {
    each
} from "../../core/utils/iterator";
import {
    extend
} from "../../core/utils/extend";
import {
    inputType
} from "../../core/utils/support";
import devices from "../../core/devices";
import browser from "../../core/utils/browser";
import config from "../../core/config";
import dateUtils from "../../core/utils/date";
import uiDateUtils from "./ui.date_utils";
import dateSerialization from "../../core/utils/date_serialization";
import DropDownEditor from "../drop_down_editor/ui.drop_down_editor";
import dateLocalization from "../../localization/date";
import messageLocalization from "../../localization/message";
import Calendar from "./ui.date_box.strategy.calendar";
import DateView from "./ui.date_box.strategy.date_view";
import Native from "./ui.date_box.strategy.native";
import CalendarWithTime from "./ui.date_box.strategy.calendar_with_time";
import List from "./ui.date_box.strategy.list";
var DATEBOX_CLASS = "dx-datebox";
var DX_AUTO_WIDTH_CLASS = "dx-auto-width";
var DX_INVALID_BADGE_CLASS = "dx-show-invalid-badge";
var DX_CLEAR_BUTTON_CLASS = "dx-clear-button-area";
var DATEBOX_WRAPPER_CLASS = "dx-datebox-wrapper";
var DROPDOWNEDITOR_OVERLAY_CLASS = "dx-dropdowneditor-overlay";
var PICKER_TYPE = {
    calendar: "calendar",
    rollers: "rollers",
    list: "list",
    native: "native"
};
var TYPE = {
    date: "date",
    datetime: "datetime",
    time: "time"
};
var STRATEGY_NAME = {
    calendar: "Calendar",
    dateView: "DateView",
    native: "Native",
    calendarWithTime: "CalendarWithTime",
    list: "List"
};
var STRATEGY_CLASSES = {
    Calendar: Calendar,
    DateView: DateView,
    Native: Native,
    CalendarWithTime: CalendarWithTime,
    List: List
};
var DateBox = DropDownEditor.inherit({
    _supportedKeys: function() {
        return extend(this.callBase(), this._strategy.supportedKeys())
    },
    _renderButtonContainers: function() {
        this.callBase.apply(this, arguments);
        this._strategy.customizeButtons()
    },
    _getDefaultOptions: function() {
        return extend(this.callBase(), {
            type: "date",
            showAnalogClock: true,
            value: null,
            dateSerializationFormat: void 0,
            min: void 0,
            max: void 0,
            displayFormat: null,
            interval: 30,
            disabledDates: null,
            pickerType: PICKER_TYPE.calendar,
            invalidDateMessage: messageLocalization.format("dxDateBox-validation-datetime"),
            dateOutOfRangeMessage: messageLocalization.format("validation-range"),
            applyButtonText: messageLocalization.format("OK"),
            adaptivityEnabled: false,
            calendarOptions: {},
            useHiddenSubmitElement: true,
            _showValidationIcon: true
        })
    },
    _defaultOptionsRules: function() {
        return this.callBase().concat([{
            device: {
                platform: "ios"
            },
            options: {
                "dropDownOptions.showTitle": true
            }
        }, {
            device: {
                platform: "android"
            },
            options: {
                buttonsLocation: "bottom after"
            }
        }, {
            device: function() {
                var realDevice = devices.real();
                var platform = realDevice.platform;
                return "ios" === platform || "android" === platform
            },
            options: {
                pickerType: PICKER_TYPE.native
            }
        }, {
            device: {
                platform: "generic",
                deviceType: "desktop"
            },
            options: {
                buttonsLocation: "bottom after"
            }
        }])
    },
    _initOptions: function(options) {
        this._userOptions = extend({}, options);
        this.callBase(options);
        this._updatePickerOptions()
    },
    _updatePickerOptions: function() {
        var pickerType = this.option("pickerType");
        var type = this.option("type");
        if (pickerType === PICKER_TYPE.list && (type === TYPE.datetime || type === TYPE.date)) {
            pickerType = PICKER_TYPE.calendar
        }
        if (type === TYPE.time && pickerType === PICKER_TYPE.calendar) {
            pickerType = PICKER_TYPE.list
        }
        this._pickerType = pickerType;
        this._setShowDropDownButtonOption()
    },
    _setShowDropDownButtonOption() {
        var platform = devices.real().platform;
        var isMozillaOnAndroid = "android" === platform && browser.mozilla;
        var isNativePickerType = this._isNativeType();
        var showDropDownButton = "generic" !== platform || !isNativePickerType;
        if (isNativePickerType && isMozillaOnAndroid) {
            showDropDownButton = false
        }
        this.option({
            showDropDownButton: showDropDownButton
        })
    },
    _init: function() {
        this._initStrategy();
        this.option(extend({}, this._strategy.getDefaultOptions(), this._userOptions));
        delete this._userOptions;
        this.callBase()
    },
    _toLowerCaseFirstLetter: function(string) {
        return string.charAt(0).toLowerCase() + string.substr(1)
    },
    _initStrategy: function() {
        var strategyName = this._getStrategyName(this._getFormatType());
        var strategy = STRATEGY_CLASSES[strategyName];
        if (!(this._strategy && this._strategy.NAME === strategyName)) {
            this._strategy = new strategy(this)
        }
    },
    _getFormatType: function() {
        var currentType = this.option("type");
        var isTime = /h|m|s/g.test(currentType);
        var isDate = /d|M|Y/g.test(currentType);
        var type = "";
        if (isDate) {
            type += TYPE.date
        }
        if (isTime) {
            type += TYPE.time
        }
        return type
    },
    _getStrategyName: function(type) {
        var pickerType = this._pickerType;
        if (pickerType === PICKER_TYPE.rollers) {
            return STRATEGY_NAME.dateView
        } else if (pickerType === PICKER_TYPE.native) {
            return STRATEGY_NAME.native
        }
        if (type === TYPE.date) {
            return STRATEGY_NAME.calendar
        }
        if (type === TYPE.datetime) {
            return STRATEGY_NAME.calendarWithTime
        }
        return STRATEGY_NAME.list
    },
    _initMarkup: function() {
        this.$element().addClass(DATEBOX_CLASS);
        this.callBase();
        this._refreshFormatClass();
        this._refreshPickerTypeClass();
        this._strategy.renderInputMinMax(this._input())
    },
    _render: function() {
        this.callBase();
        this._formatValidationIcon()
    },
    _renderDimensions: function() {
        this.callBase();
        this.$element().toggleClass(DX_AUTO_WIDTH_CLASS, !this.option("width"));
        this._updatePopupWidth();
        this._updatePopupHeight()
    },
    _dimensionChanged: function() {
        this.callBase();
        this._updatePopupHeight()
    },
    _updatePopupHeight: function() {
        if (this._popup) {
            var _this$_strategy$_upda, _this$_strategy;
            null === (_this$_strategy$_upda = (_this$_strategy = this._strategy)._updatePopupHeight) || void 0 === _this$_strategy$_upda ? void 0 : _this$_strategy$_upda.call(_this$_strategy)
        }
    },
    _refreshFormatClass: function() {
        var $element = this.$element();
        each(TYPE, (function(_, item) {
            $element.removeClass(DATEBOX_CLASS + "-" + item)
        }));
        $element.addClass(DATEBOX_CLASS + "-" + this.option("type"))
    },
    _refreshPickerTypeClass: function() {
        var $element = this.$element();
        each(PICKER_TYPE, (function(_, item) {
            $element.removeClass(DATEBOX_CLASS + "-" + item)
        }));
        $element.addClass(DATEBOX_CLASS + "-" + this._pickerType)
    },
    _formatValidationIcon: function() {
        if (!hasWindow()) {
            return
        }
        var inputElement = this._input().get(0);
        var isRtlEnabled = this.option("rtlEnabled");
        var clearButtonWidth = this._getClearButtonWidth();
        var longestElementDimensions = this._getLongestElementDimensions();
        var curWidth = parseFloat(window.getComputedStyle(inputElement).width) - clearButtonWidth;
        var shouldHideValidationIcon = longestElementDimensions.width > curWidth;
        var style = inputElement.style;
        this.$element().toggleClass(DX_INVALID_BADGE_CLASS, !shouldHideValidationIcon && this.option("_showValidationIcon"));
        if (shouldHideValidationIcon) {
            if (void 0 === this._storedPadding) {
                this._storedPadding = isRtlEnabled ? longestElementDimensions.leftPadding : longestElementDimensions.rightPadding
            }
            isRtlEnabled ? style.paddingLeft = 0 : style.paddingRight = 0
        } else {
            isRtlEnabled ? style.paddingLeft = this._storedPadding + "px" : style.paddingRight = this._storedPadding + "px"
        }
    },
    _getClearButtonWidth: function() {
        var clearButtonWidth = 0;
        if (this._isClearButtonVisible() && "" === this._input().val()) {
            var clearButtonElement = this.$element().find("." + DX_CLEAR_BUTTON_CLASS).get(0);
            clearButtonWidth = parseFloat(window.getComputedStyle(clearButtonElement).width)
        }
        return clearButtonWidth
    },
    _getLongestElementDimensions: function() {
        var format = this._strategy.getDisplayFormat(this.option("displayFormat"));
        var longestValue = dateLocalization.format(uiDateUtils.getLongestDate(format, dateLocalization.getMonthNames(), dateLocalization.getDayNames()), format);
        var $input = this._input();
        var inputElement = $input.get(0);
        var $longestValueElement = createTextElementHiddenCopy($input, longestValue);
        var isPaddingStored = void 0 !== this._storedPadding;
        var storedPadding = !isPaddingStored ? 0 : this._storedPadding;
        $longestValueElement.appendTo(this.$element());
        var elementWidth = parseFloat(window.getComputedStyle($longestValueElement.get(0)).width);
        var rightPadding = parseFloat(window.getComputedStyle(inputElement).paddingRight);
        var leftPadding = parseFloat(window.getComputedStyle(inputElement).paddingLeft);
        var necessaryWidth = elementWidth + leftPadding + rightPadding + storedPadding;
        $longestValueElement.remove();
        return {
            width: necessaryWidth,
            leftPadding: leftPadding,
            rightPadding: rightPadding
        }
    },
    _getKeyboardListeners() {
        return this.callBase().concat([this._strategy && this._strategy.getKeyboardListener()])
    },
    _renderPopup: function() {
        this.callBase();
        this._popup.$wrapper().addClass(DATEBOX_WRAPPER_CLASS);
        this._renderPopupWrapper()
    },
    _getPopupToolbarItems() {
        var _this$_strategy$_getP, _this$_strategy$_getP2, _this$_strategy2;
        var defaultItems = this.callBase();
        return null !== (_this$_strategy$_getP = null === (_this$_strategy$_getP2 = (_this$_strategy2 = this._strategy)._getPopupToolbarItems) || void 0 === _this$_strategy$_getP2 ? void 0 : _this$_strategy$_getP2.call(_this$_strategy2, defaultItems)) && void 0 !== _this$_strategy$_getP ? _this$_strategy$_getP : defaultItems
    },
    _popupConfig: function() {
        var popupConfig = this.callBase();
        return extend(this._strategy.popupConfig(popupConfig), {
            title: this._getPopupTitle(),
            dragEnabled: false
        })
    },
    _renderPopupWrapper: function() {
        if (!this._popup) {
            return
        }
        var $element = this.$element();
        var classPostfixes = extend({}, TYPE, PICKER_TYPE);
        each(classPostfixes, function(_, item) {
            $element.removeClass(DATEBOX_WRAPPER_CLASS + "-" + item)
        }.bind(this));
        this._popup.$wrapper().addClass(DATEBOX_WRAPPER_CLASS + "-" + this.option("type")).addClass(DATEBOX_WRAPPER_CLASS + "-" + this._pickerType).addClass(DROPDOWNEDITOR_OVERLAY_CLASS)
    },
    _renderPopupContent: function() {
        this.callBase();
        this._strategy.renderPopupContent()
    },
    _popupShowingHandler: function() {
        this.callBase();
        this._strategy.popupShowingHandler()
    },
    _popupShownHandler: function() {
        this.callBase();
        this._strategy.renderOpenedState()
    },
    _popupHiddenHandler: function() {
        this.callBase();
        this._strategy.renderOpenedState();
        this._strategy.popupHiddenHandler()
    },
    _visibilityChanged: function(visible) {
        if (visible) {
            this._formatValidationIcon()
        }
    },
    _clearValueHandler: function(e) {
        this.option("text", "");
        this.callBase(e)
    },
    _readOnlyPropValue: function() {
        if (this._pickerType === PICKER_TYPE.rollers) {
            return true
        }
        var platform = devices.real().platform;
        var isCustomValueDisabled = this._isNativeType() && ("ios" === platform || "android" === platform);
        if (isCustomValueDisabled) {
            return this.option("readOnly")
        }
        return this.callBase()
    },
    _isClearButtonVisible: function() {
        return this.callBase() && !this._isNativeType()
    },
    _renderValue: function() {
        var value = this.dateOption("value");
        this.option("text", this._getDisplayedText(value));
        this._strategy.renderValue();
        return this.callBase()
    },
    _setSubmitValue: function() {
        var value = this.dateOption("value");
        var dateSerializationFormat = this.option("dateSerializationFormat");
        var submitFormat = uiDateUtils.SUBMIT_FORMATS_MAP[this.option("type")];
        var submitValue = dateSerializationFormat ? dateSerialization.serializeDate(value, dateSerializationFormat) : uiDateUtils.toStandardDateFormat(value, submitFormat);
        this._getSubmitElement().val(submitValue)
    },
    _getDisplayedText: function(value) {
        var mode = this.option("mode");
        var displayedText;
        if ("text" === mode) {
            var displayFormat = this._strategy.getDisplayFormat(this.option("displayFormat"));
            displayedText = dateLocalization.format(value, displayFormat)
        } else {
            var format = this._getFormatByMode(mode);
            if (format) {
                displayedText = dateLocalization.format(value, format)
            } else {
                displayedText = uiDateUtils.toStandardDateFormat(value, mode)
            }
        }
        return displayedText
    },
    _getFormatByMode: function(mode) {
        return inputType(mode) ? null : uiDateUtils.FORMATS_MAP[mode]
    },
    _valueChangeEventHandler: function(e) {
        var {
            text: text,
            type: type,
            validationError: validationError
        } = this.option();
        var currentValue = this.dateOption("value");
        if (text === this._getDisplayedText(currentValue)) {
            this._recallInternalValidation(currentValue, validationError);
            return
        }
        var parsedDate = this._getParsedDate(text);
        var value = null !== currentValue && void 0 !== currentValue ? currentValue : this._getDateByDefault();
        var newValue = uiDateUtils.mergeDates(value, parsedDate, type);
        var date = parsedDate && "time" === type ? newValue : parsedDate;
        if (this._applyInternalValidation(date).isValid) {
            var displayedText = this._getDisplayedText(newValue);
            if (value && newValue && value.getTime() === newValue.getTime() && displayedText !== text) {
                this._renderValue()
            } else {
                this.dateValue(newValue, e)
            }
        }
    },
    _recallInternalValidation(value, validationError) {
        if (!validationError || validationError.editorSpecific) {
            this._applyInternalValidation(value);
            this._applyCustomValidation(value)
        }
    },
    _getDateByDefault: function() {
        return this._strategy.useCurrentDateByDefault() && this._strategy.getDefaultDate()
    },
    _getParsedDate: function(text) {
        var displayFormat = this._strategy.getDisplayFormat(this.option("displayFormat"));
        var parsedText = this._strategy.getParsedText(text, displayFormat);
        return null !== parsedText && void 0 !== parsedText ? parsedText : void 0
    },
    _applyInternalValidation(value) {
        var text = this.option("text");
        var hasText = !!text && null !== value;
        var isDate = !!value && isDateType(value) && !isNaN(value.getTime());
        var isDateInRange = isDate && dateUtils.dateInRange(value, this.dateOption("min"), this.dateOption("max"), this.option("type"));
        var isValid = !hasText && !value || isDateInRange;
        var validationMessage = "";
        if (!isDate) {
            validationMessage = this.option("invalidDateMessage")
        } else if (!isDateInRange) {
            validationMessage = this.option("dateOutOfRangeMessage")
        }
        this._updateInternalValidationState(isValid, validationMessage);
        return {
            isValid: isValid,
            isDate: isDate
        }
    },
    _updateInternalValidationState(isValid, validationMessage) {
        this.option({
            isValid: isValid,
            validationError: isValid ? null : {
                editorSpecific: true,
                message: validationMessage
            }
        })
    },
    _applyCustomValidation: function(value) {
        this.validationRequest.fire({
            editor: this,
            value: this._serializeDate(value)
        })
    },
    _isValueChanged: function(newValue) {
        var oldValue = this.dateOption("value");
        var oldTime = oldValue && oldValue.getTime();
        var newTime = newValue && newValue.getTime();
        return oldTime !== newTime
    },
    _isTextChanged: function(newValue) {
        var oldText = this.option("text");
        var newText = newValue && this._getDisplayedText(newValue) || "";
        return oldText !== newText
    },
    _renderProps: function() {
        this.callBase();
        this._input().attr("autocomplete", "off")
    },
    _renderOpenedState: function() {
        if (!this._isNativeType()) {
            this.callBase()
        }
        if (this._strategy.isAdaptivityChanged()) {
            this._refreshStrategy()
        }
    },
    _getPopupTitle: function() {
        var placeholder = this.option("placeholder");
        if (placeholder) {
            return placeholder
        }
        var type = this.option("type");
        if (type === TYPE.time) {
            return messageLocalization.format("dxDateBox-simulatedDataPickerTitleTime")
        }
        if (type === TYPE.date || type === TYPE.datetime) {
            return messageLocalization.format("dxDateBox-simulatedDataPickerTitleDate")
        }
        return ""
    },
    _refreshStrategy: function() {
        this._strategy.dispose();
        this._initStrategy();
        this.option(this._strategy.getDefaultOptions());
        this._refresh()
    },
    _applyButtonHandler: function(e) {
        var value = this._strategy.getValue();
        this.dateValue(value, e.event);
        this.callBase()
    },
    _dispose: function() {
        var _this$_strategy3;
        this.callBase();
        null === (_this$_strategy3 = this._strategy) || void 0 === _this$_strategy3 ? void 0 : _this$_strategy3.dispose()
    },
    _isNativeType: function() {
        return this._pickerType === PICKER_TYPE.native
    },
    _updatePopupTitle: function() {
        var _this$_popup;
        null === (_this$_popup = this._popup) || void 0 === _this$_popup ? void 0 : _this$_popup.option("title", this._getPopupTitle())
    },
    _optionChanged: function(args) {
        switch (args.name) {
            case "showClearButton":
            case "buttons":
                this.callBase.apply(this, arguments);
                this._formatValidationIcon();
                break;
            case "pickerType":
                this._updatePickerOptions({
                    pickerType: args.value
                });
                this._refreshStrategy();
                this._refreshPickerTypeClass();
                this._invalidate();
                break;
            case "type":
                this._updatePickerOptions({
                    format: args.value
                });
                this._refreshStrategy();
                this._refreshFormatClass();
                this._renderPopupWrapper();
                this._formatValidationIcon();
                this._updateValue();
                break;
            case "placeholder":
                this.callBase.apply(this, arguments);
                this._updatePopupTitle();
                break;
            case "min":
            case "max":
                var isValid = this.option("isValid");
                this._applyInternalValidation(this.dateOption("value"));
                if (!isValid) {
                    this._applyCustomValidation(this.dateOption("value"))
                }
                this._invalidate();
                break;
            case "dateSerializationFormat":
            case "interval":
            case "disabledDates":
            case "calendarOptions":
                this._invalidate();
                break;
            case "displayFormat":
                this.option("text", this._getDisplayedText(this.dateOption("value")));
                this._renderInputValue();
                break;
            case "text":
                this._strategy.textChangedHandler(args.value);
                this.callBase.apply(this, arguments);
                break;
            case "isValid":
                this.callBase.apply(this, arguments);
                this._formatValidationIcon();
                break;
            case "showDropDownButton":
                this._formatValidationIcon();
                this.callBase.apply(this, arguments);
                break;
            case "readOnly":
                this.callBase.apply(this, arguments);
                this._formatValidationIcon();
                break;
            case "todayButtonText":
                this._setPopupOption("toolbarItems", this._getPopupToolbarItems());
                break;
            case "invalidDateMessage":
            case "dateOutOfRangeMessage":
            case "adaptivityEnabled":
            case "showAnalogClock":
            case "_showValidationIcon":
                break;
            default:
                this.callBase.apply(this, arguments)
        }
    },
    _getSerializationFormat: function() {
        var value = this.option("value");
        if (this.option("dateSerializationFormat") && config().forceIsoDateParsing) {
            return this.option("dateSerializationFormat")
        }
        if (isNumeric(value)) {
            return "number"
        }
        if (!isString(value)) {
            return
        }
        return dateSerialization.getDateSerializationFormat(value)
    },
    _updateValue: function(value) {
        this.callBase();
        this._applyInternalValidation(null !== value && void 0 !== value ? value : this.dateOption("value"))
    },
    dateValue: function(value, dxEvent) {
        var isValueChanged = this._isValueChanged(value);
        if (isValueChanged && dxEvent) {
            this._saveValueChangeEvent(dxEvent)
        }
        if (!isValueChanged) {
            if (this._isTextChanged(value)) {
                this._updateValue(value)
            } else if ("" === this.option("text")) {
                this._applyCustomValidation(value)
            }
        }
        return this.dateOption("value", value)
    },
    dateOption: function(optionName, value) {
        if (1 === arguments.length) {
            return dateSerialization.deserializeDate(this.option(optionName))
        }
        this.option(optionName, this._serializeDate(value))
    },
    _serializeDate: function(date) {
        var serializationFormat = this._getSerializationFormat();
        return dateSerialization.serializeDate(date, serializationFormat)
    },
    _clearValue: function() {
        var value = this.option("value");
        this.callBase();
        if (null === value) {
            this._applyCustomValidation(null)
        }
    },
    clear: function() {
        var value = this.option("value");
        this.callBase();
        if (null === value) {
            this._applyInternalValidation(null)
        }
    }
});
export default DateBox;
