/**
 * DevExtreme (esm/__internal/ui/m_drop_down_box.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 registerComponent from "../../core/component_registrator";
import devices from "../../core/devices";
import domAdapter from "../../core/dom_adapter";
import {
    getPublicElement
} from "../../core/element";
import $ from "../../core/renderer";
import {
    grep,
    noop
} from "../../core/utils/common";
import {
    Deferred,
    when
} from "../../core/utils/deferred";
import {
    extend
} from "../../core/utils/extend";
import {
    map
} from "../../core/utils/iterator";
import {
    isDefined,
    isObject
} from "../../core/utils/type";
import eventsEngine from "../../events/core/events_engine";
import {
    normalizeKeyName
} from "../../events/utils/index";
import DropDownEditor from "../../ui/drop_down_editor/ui.drop_down_editor";
import DataExpressionMixin from "../../ui/editor/ui.data_expression";
import {
    getElementMaxHeightByWindow
} from "../../ui/overlay/utils";
import {
    tabbable
} from "../../ui/widget/selectors";
var {
    getActiveElement: getActiveElement
} = domAdapter;
var DROP_DOWN_BOX_CLASS = "dx-dropdownbox";
var ANONYMOUS_TEMPLATE_NAME = "content";
var realDevice = devices.real();
var DropDownBox = DropDownEditor.inherit({
    _supportedKeys() {
        return extend({}, this.callBase(), {
            tab(e) {
                if (!this.option("opened")) {
                    return
                }
                var $tabbableElements = this._getTabbableElements();
                var $focusableElement = e.shiftKey ? $tabbableElements.last() : $tabbableElements.first();
                $focusableElement && eventsEngine.trigger($focusableElement, "focus");
                e.preventDefault()
            }
        })
    },
    _getTabbableElements() {
        return this._getElements().filter(tabbable)
    },
    _getElements() {
        return $(this.content()).find("*")
    },
    _getDefaultOptions() {
        return extend(this.callBase(), {
            acceptCustomValue: false,
            contentTemplate: ANONYMOUS_TEMPLATE_NAME,
            openOnFieldClick: true,
            displayValueFormatter: value => Array.isArray(value) ? value.join(", ") : value,
            useHiddenSubmitElement: true
        })
    },
    _getAnonymousTemplateName: () => ANONYMOUS_TEMPLATE_NAME,
    _initTemplates() {
        this.callBase()
    },
    _initMarkup() {
        this._initDataExpressions();
        this.$element().addClass(DROP_DOWN_BOX_CLASS);
        this.callBase()
    },
    _setSubmitValue() {
        var value = this.option("value");
        var submitValue = this._shouldUseDisplayValue(value) ? this._displayGetter(value) : value;
        this._getSubmitElement().val(submitValue)
    },
    _shouldUseDisplayValue(value) {
        return "this" === this.option("valueExpr") && isObject(value)
    },
    _sortValuesByKeysOrder(orderedKeys, values) {
        var sortedValues = values.sort((a, b) => orderedKeys.indexOf(a.itemKey) - orderedKeys.indexOf(b.itemKey));
        return sortedValues.map(x => x.itemDisplayValue)
    },
    _renderInputValue() {
        this._rejectValueLoading();
        var values = [];
        if (!this._dataSource) {
            this.callBase(values);
            return (new Deferred).resolve()
        }
        var currentValue = this._getCurrentValue();
        var keys = null !== currentValue && void 0 !== currentValue ? currentValue : [];
        keys = Array.isArray(keys) ? keys : [keys];
        var itemLoadDeferreds = map(keys, key => {
            var deferred = new Deferred;
            this._loadItem(key).always(item => {
                var displayValue = this._displayGetter(item);
                if (isDefined(displayValue)) {
                    values.push({
                        itemKey: key,
                        itemDisplayValue: displayValue
                    })
                } else if (this.option("acceptCustomValue")) {
                    values.push({
                        itemKey: key,
                        itemDisplayValue: key
                    })
                }
                deferred.resolve()
            });
            return deferred
        });
        var callBase = this.callBase.bind(this);
        return when.apply(this, itemLoadDeferreds).always(() => {
            var orderedValues = this._sortValuesByKeysOrder(keys, values);
            this.option("displayValue", orderedValues);
            callBase(values.length && orderedValues)
        })
    },
    _loadItem(value) {
        var deferred = new Deferred;
        var that = this;
        var selectedItem = grep(this.option("items") || [], item => this._isValueEquals(this._valueGetter(item), value))[0];
        if (void 0 !== selectedItem) {
            deferred.resolve(selectedItem)
        } else {
            this._loadValue(value).done(item => {
                deferred.resolve(item)
            }).fail(args => {
                if (null === args || void 0 === args ? void 0 : args.shouldSkipCallback) {
                    return
                }
                if (that.option("acceptCustomValue")) {
                    deferred.resolve(value)
                } else {
                    deferred.reject()
                }
            })
        }
        return deferred.promise()
    },
    _popupTabHandler(e) {
        if ("tab" !== normalizeKeyName(e)) {
            return
        }
        var $firstTabbable = this._getTabbableElements().first().get(0);
        var $lastTabbable = this._getTabbableElements().last().get(0);
        var $target = e.target;
        var moveBackward = !!($target === $firstTabbable && e.shiftKey);
        var moveForward = !!($target === $lastTabbable && !e.shiftKey);
        if (moveBackward || moveForward) {
            this.close();
            eventsEngine.trigger(this._input(), "focus");
            if (moveBackward) {
                e.preventDefault()
            }
        }
    },
    _renderPopupContent() {
        if (this.option("contentTemplate") === ANONYMOUS_TEMPLATE_NAME) {
            return
        }
        var contentTemplate = this._getTemplateByOption("contentTemplate");
        if (!(contentTemplate && this.option("contentTemplate"))) {
            return
        }
        var $popupContent = this._popup.$content();
        var templateData = {
            value: this._fieldRenderData(),
            component: this
        };
        $popupContent.empty();
        contentTemplate.render({
            container: getPublicElement($popupContent),
            model: templateData
        })
    },
    _canShowVirtualKeyboard: () => realDevice.mac,
    _isNestedElementActive() {
        var activeElement = getActiveElement();
        return activeElement && this._popup.$content().get(0).contains(activeElement)
    },
    _shouldHideOnParentScroll() {
        return "desktop" === realDevice.deviceType && this._canShowVirtualKeyboard() && this._isNestedElementActive()
    },
    _popupHiddenHandler() {
        this.callBase();
        this._popupPosition = void 0
    },
    _popupPositionedHandler(e) {
        this.callBase(e);
        this._popupPosition = e.position
    },
    _getDefaultPopupPosition(isRtlEnabled) {
        var {
            my: my,
            at: at
        } = this.callBase(isRtlEnabled);
        return {
            my: my,
            at: at,
            offset: {
                v: -1
            },
            collision: "flipfit"
        }
    },
    _popupConfig() {
        var {
            focusStateEnabled: focusStateEnabled
        } = this.option();
        return extend(this.callBase(), {
            tabIndex: -1,
            dragEnabled: false,
            focusStateEnabled: focusStateEnabled,
            contentTemplate: ANONYMOUS_TEMPLATE_NAME,
            hideOnParentScroll: this._shouldHideOnParentScroll.bind(this),
            position: extend(this.option("popupPosition"), {
                of: this.$element()
            }),
            _ignoreFunctionValueDeprecation: true,
            maxHeight: function() {
                var _a;
                var popupLocation = null === (_a = this._popupPosition) || void 0 === _a ? void 0 : _a.v.location;
                return getElementMaxHeightByWindow(this.$element(), popupLocation)
            }.bind(this)
        })
    },
    _popupShownHandler() {
        this.callBase();
        var $firstElement = this._getTabbableElements().first();
        eventsEngine.trigger($firstElement, "focus")
    },
    _setCollectionWidgetOption: noop,
    _optionChanged(args) {
        this._dataExpressionOptionChanged(args);
        switch (args.name) {
            case "dataSource":
                this._renderInputValue();
                break;
            case "displayValue":
                this.option("text", args.value);
                break;
            case "displayExpr":
                this._renderValue();
                break;
            case "contentTemplate":
                this._invalidate();
                break;
            default:
                this.callBase(args)
        }
    }
}).include(DataExpressionMixin);
registerComponent("dxDropDownBox", DropDownBox);
export default DropDownBox;
