/**
 * DevExtreme (ui/lookup.js)
 * Version: 16.2.15
 * Build date: Tue Mar 12 2019
 *
 * Copyright (c) 2012 - 2019 Developer Express Inc. ALL RIGHTS RESERVED
 * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
 */
"use strict";
var $ = require("jquery"),
    support = require("../core/utils/support"),
    commonUtils = require("../core/utils/common"),
    inkRipple = require("./widget/utils.ink_ripple"),
    messageLocalization = require("../localization/message"),
    devices = require("../core/devices"),
    registerComponent = require("../core/component_registrator"),
    eventUtils = require("../events/utils"),
    DropDownList = require("./drop_down_editor/ui.drop_down_list"),
    themes = require("./themes"),
    clickEvent = require("../events/click"),
    Popover = require("./popover"),
    TextBox = require("./text_box"),
    ChildDefaultTemplate = require("./widget/child_default_template");
var LOOKUP_CLASS = "dx-lookup",
    LOOKUP_SEARCH_CLASS = "dx-lookup-search",
    LOOKUP_SEARCH_WRAPPER_CLASS = "dx-lookup-search-wrapper",
    LOOKUP_FIELD_CLASS = "dx-lookup-field",
    LOOKUP_ARROW_CLASS = "dx-lookup-arrow",
    LOOKUP_FIELD_WRAPPER_CLASS = "dx-lookup-field-wrapper",
    LOOKUP_POPUP_CLASS = "dx-lookup-popup",
    LOOKUP_POPUP_WRAPPER_CLASS = "dx-lookup-popup-wrapper",
    LOOKUP_POPUP_SEARCH_CLASS = "dx-lookup-popup-search",
    LOOKUP_POPOVER_MODE = "dx-lookup-popover-mode",
    LOOKUP_EMPTY_CLASS = "dx-lookup-empty",
    LOOKUP_POPUP_VALIDATION_MESSAGE = "dx-lookup-validation-message",
    LOOKUP_POPUP_INVALID_CLASS = "dx-lookup-invalid";
var POPUP_OPTION_MAP = {
    popupWidth: "width",
    popupHeight: "height"
};
var Lookup = DropDownList.inherit({
    _supportedKeys: function() {
        return $.extend(this.callBase(), {
            space: function(e) {
                e.preventDefault();
                this._validatedOpening()
            },
            enter: function() {
                this._validatedOpening()
            }
        })
    },
    _setDeprecatedOptions: function() {
        this.callBase();
        $.extend(this._deprecatedOptions, {
            showNextButton: {
                since: "15.1",
                message: "Use the 'pageLoadMode' option instead"
            },
            pagingEnabled: {
                since: "15.1",
                message: "Use the 'dataSource.paginate' option instead"
            }
        })
    },
    _getDefaultOptions: function() {
        return $.extend(this.callBase(), {
            title: "",
            titleTemplate: "title",
            onTitleRendered: null,
            placeholder: messageLocalization.format("Select"),
            searchPlaceholder: messageLocalization.format("Search"),
            searchEnabled: true,
            cleanSearchOnOpening: true,
            fullScreen: false,
            showCancelButton: true,
            showClearButton: false,
            clearButtonText: messageLocalization.format("Clear"),
            applyButtonText: messageLocalization.format("Done"),
            popupWidth: function() {
                return .8 * $(window).width()
            },
            popupHeight: function() {
                return .8 * $(window).height()
            },
            shading: true,
            closeOnOutsideClick: false,
            position: void 0,
            animation: {},
            pullRefreshEnabled: false,
            useNativeScrolling: true,
            pullingDownText: messageLocalization.format("dxList-pullingDownText"),
            pulledDownText: messageLocalization.format("dxList-pulledDownText"),
            refreshingText: messageLocalization.format("dxList-refreshingText"),
            pageLoadingText: messageLocalization.format("dxList-pageLoadingText"),
            onScroll: null,
            onPullRefresh: null,
            onPageLoading: null,
            pageLoadMode: "scrollBottom",
            showNextButton: void 0,
            nextButtonText: messageLocalization.format("dxList-nextButtonText"),
            grouped: false,
            groupTemplate: "group",
            usePopover: false,
            showDropButton: false,
            showPopupTitle: true,
            focusStateEnabled: false
        })
    },
    _defaultOptionsRules: function() {
        return this.callBase().concat([{
            device: function() {
                return !support.nativeScrolling
            },
            options: {
                useNativeScrolling: false
            }
        }, {
            device: function(device) {
                return !devices.isSimulator() && "generic" === devices.real().platform && "generic" === device.platform
            },
            options: {
                usePopover: true,
                popupHeight: "auto"
            }
        }, {
            device: function(device) {
                return "win" === device.platform && device.phone && device.version && 8 === device.version[0]
            },
            options: {
                showCancelButton: false,
                fullScreen: true
            }
        }, {
            device: function(device) {
                return "win" === device.platform && !device.phone && device.version && 8 === device.version[0]
            },
            options: {
                popupWidth: function() {
                    return $(window).width()
                }
            }
        }, {
            device: {
                platform: "ios",
                phone: true
            },
            options: {
                fullScreen: true
            }
        }, {
            device: {
                platform: "ios",
                tablet: true
            },
            options: {
                popupWidth: function() {
                    return .4 * Math.min($(window).width(), $(window).height())
                },
                popupHeight: "auto",
                usePopover: true,
                useInkRipple: false
            }
        }, {
            device: function() {
                return "desktop" === devices.real().deviceType && !devices.isSimulator()
            },
            options: {
                focusStateEnabled: true
            }
        }, {
            device: function() {
                return /android5/.test(themes.current())
            },
            options: {
                useInkRipple: true
            }
        }])
    },
    _dataSourceOptions: function() {
        this._suppressDeprecatedWarnings();
        var pagingEnabled = commonUtils.ensureDefined(this.option("pagingEnabled"), true);
        pagingEnabled = commonUtils.isDefined(this.option("showNextButton")) ? pagingEnabled || this.option("showNextButton") : pagingEnabled;
        this._resumeDeprecatedWarnings();
        return $.extend(this.callBase(), {
            paginate: pagingEnabled
        })
    },
    _initTemplates: function() {
        this.callBase();
        this._defaultTemplates.group = new ChildDefaultTemplate("group", this);
        this._defaultTemplates.title = new ChildDefaultTemplate("title", this)
    },
    _inputWrapper: function() {
        return this.element().find("." + LOOKUP_FIELD_WRAPPER_CLASS)
    },
    _render: function() {
        this._renderSubmitElement();
        this.callBase();
        this.element().addClass(LOOKUP_CLASS).toggleClass(LOOKUP_POPOVER_MODE, this.option("usePopover"))
    },
    _renderSubmitElement: function() {
        this._$submitElement = $("<input>").attr("type", "hidden").appendTo(this.element())
    },
    _getSubmitElement: function() {
        return this._$submitElement
    },
    _fireContentReadyAction: $.noop,
    _popupWrapperClass: function() {
        return ""
    },
    _renderInput: function() {
        var fieldClickAction = this._createAction($.proxy(function() {
            this._validatedOpening()
        }, this));
        this._$field = $("<div>").addClass(LOOKUP_FIELD_CLASS).on(eventUtils.addNamespace(clickEvent.name, this.NAME), function(e) {
            fieldClickAction({
                jQueryEvent: e
            })
        });
        var $arrow = $("<div>").addClass(LOOKUP_ARROW_CLASS);
        this._$fieldWrapper = $("<div>").addClass(LOOKUP_FIELD_WRAPPER_CLASS).append(this._$field).append($arrow).appendTo(this.element());
        this.option("useInkRipple") && this._renderInkRipple()
    },
    _renderInkRipple: function() {
        this._inkRipple = inkRipple.render()
    },
    _toggleActiveState: function($element, value, e) {
        this.callBase.apply(this, arguments);
        if (!this._inkRipple) {
            return
        }
        var config = {
            element: this._inputWrapper(),
            jQueryEvent: e
        };
        if (value) {
            this._inkRipple.showWave(config)
        } else {
            this._inkRipple.hideWave(config)
        }
    },
    _renderField: function() {
        var fieldTemplate = this._getTemplateByOption("fieldTemplate");
        if (fieldTemplate && this.option("fieldTemplate")) {
            this._renderFieldTemplate(fieldTemplate);
            return
        }
        this._$field.text(this.option("displayValue") || this.option("placeholder"));
        this.element().toggleClass(LOOKUP_EMPTY_CLASS, !this.option("selectedItem"))
    },
    _renderFieldTemplate: function(template) {
        this._$field.empty();
        var data = this._fieldRenderData();
        template.render({
            model: data,
            container: this._$field
        })
    },
    _fieldRenderData: function() {
        return this.option("selectedItem")
    },
    _popupShowingHandler: function() {
        var validationError;
        if (this._$popupValidationMessage) {
            validationError = this.option("validationError");
            if (validationError && validationError.message) {
                this._$popupValidationMessage.text(validationError.message);
                this._popup.content().addClass(LOOKUP_POPUP_INVALID_CLASS)
            } else {
                this._popup.content().removeClass(LOOKUP_POPUP_INVALID_CLASS)
            }
        }
        this.callBase.apply(this, arguments);
        if (this.option("cleanSearchOnOpening")) {
            if (this.option("searchEnabled") && this._searchBox.option("value")) {
                this._searchBox.option("value", "");
                this._searchCanceled();
                this._searchDataSource()
            }
            this._list && this._list.option("focusedElement", null)
        }
        this._attachSearchChildProcessor()
    },
    _renderPopup: function() {
        if (this.option("usePopover") && !this.option("fullScreen")) {
            this._renderPopover()
        } else {
            this.callBase()
        }
        this._$popup.addClass(LOOKUP_POPUP_CLASS);
        this._popup._wrapper().addClass(LOOKUP_POPUP_WRAPPER_CLASS)
    },
    _popupOptionMap: function(optionName) {
        return POPUP_OPTION_MAP[optionName] || optionName
    },
    _renderPopover: function() {
        this._popup = this._createComponent(this._$popup, Popover, $.extend(this._popupConfig(), {
            showEvent: null,
            hideEvent: null,
            target: this.element(),
            fullScreen: false,
            shading: false,
            closeOnTargetScroll: true,
            closeOnOutsideClick: true,
            width: this._isInitialOptionValue("popupWidth") ? $.proxy(function() {
                return this.element().outerWidth()
            }, this) : this._popupConfig().width
        }));
        this._popup.on({
            showing: $.proxy(this._popupShowingHandler, this),
            shown: $.proxy(this._popupShownHandler, this),
            hiding: $.proxy(this._popupHidingHandler, this),
            hidden: $.proxy(this._popupHiddenHandler, this)
        });
        this._popup.option("onContentReady", $.proxy(this._contentReadyHandler, this));
        this._contentReadyHandler()
    },
    _popupHidingHandler: function() {
        this.callBase();
        this.option("focusStateEnabled") && this.focus()
    },
    _preventFocusOnPopup: $.noop,
    _popupConfig: function() {
        var result = $.extend(this.callBase(), {
            showTitle: this.option("showPopupTitle"),
            title: this.option("title"),
            titleTemplate: this._getTemplateByOption("titleTemplate"),
            onTitleRendered: this.option("onTitleRendered"),
            toolbarItems: this._getPopupToolbarItems(),
            fullScreen: this.option("fullScreen"),
            shading: this.option("shading"),
            closeOnTargetScroll: false,
            closeOnOutsideClick: this.option("closeOnOutsideClick"),
            onPositioned: null
        });
        delete result.animation;
        delete result.position;
        result.maxHeight = function() {
            return $(window).height()
        };
        $.each(["position", "animation", "popupWidth", "popupHeight"], $.proxy(function(_, optionName) {
            if (void 0 !== this.option(optionName)) {
                result[this._popupOptionMap(optionName)] = this.option(optionName)
            }
        }, this));
        return result
    },
    _getPopupToolbarItems: function() {
        var buttonsConfig = "useButtons" === this.option("applyValueMode") ? this._popupToolbarItemsConfig() : [];
        var cancelButton = this._getCancelButtonConfig();
        if (cancelButton) {
            buttonsConfig.push(cancelButton)
        }
        var clearButton = this._getClearButtonConfig();
        if (clearButton) {
            buttonsConfig.push(clearButton)
        }
        return this._applyButtonsLocation(buttonsConfig)
    },
    _popupToolbarItemsConfig: function() {
        return [{
            shortcut: "done",
            options: {
                onClick: $.proxy(this._applyButtonHandler, this),
                text: this.option("applyButtonText")
            }
        }]
    },
    _getCancelButtonConfig: function() {
        return this.option("showCancelButton") ? {
            shortcut: "cancel",
            onClick: $.proxy(this._cancelButtonHandler, this),
            options: {
                text: this.option("cancelButtonText")
            }
        } : null
    },
    _getClearButtonConfig: function() {
        return this.option("showClearButton") ? {
            shortcut: "clear",
            onClick: $.proxy(this._resetValue, this),
            options: {
                text: this.option("clearButtonText")
            }
        } : null
    },
    _applyButtonHandler: function() {
        this.option("value", this._valueGetter(this._currentSelectedItem()));
        this.callBase()
    },
    _cancelButtonHandler: function() {
        this._refreshSelected();
        this.callBase()
    },
    _refreshPopupVisibility: function() {
        if (this.option("opened")) {
            this._updatePopupHeight()
        }
    },
    _dimensionChanged: function() {
        if (this.option("usePopover") && !this.option("popupWidth")) {
            this.option("popupWidth", this.element().width())
        }
        this.callBase()
    },
    _updatePopupDimensions: function() {
        this._updatePopupHeight()
    },
    _input: function() {
        return this._$searchBox || this.callBase()
    },
    _renderPopupContent: function() {
        if ("dxPopup" === this._popup.NAME) {
            this._$popupValidationMessage = $("<div>").addClass(LOOKUP_POPUP_VALIDATION_MESSAGE).appendTo(this._popup.content())
        }
        this.callBase();
        this._renderSearch();
        this._attachSearchChildProcessor()
    },
    _attachSearchChildProcessor: function() {
        if (this.option("searchEnabled") && this._searchBox) {
            this._listKeyboardProcessor = this._searchBox._keyboardProcessor.attachChildProcessor();
            this._setListOption("_keyboardProcessor", this._listKeyboardProcessor)
        } else {
            this._setListOption("_keyboardProcessor", void 0)
        }
    },
    _renderSearch: function() {
        this._$searchWrapper && this._$searchWrapper.remove();
        delete this._$searchWrapper;
        this._$searchBox && this._$searchBox.remove();
        delete this._$searchBox;
        delete this._searchBox;
        if (this.option("searchEnabled")) {
            var $searchWrapper = this._$searchWrapper = $("<div>").addClass(LOOKUP_SEARCH_WRAPPER_CLASS);
            var $searchBox = this._$searchBox = $("<div>").addClass(LOOKUP_SEARCH_CLASS).appendTo($searchWrapper);
            var currentDevice = devices.current(),
                searchMode = currentDevice.android && currentDevice.version[0] >= 5 ? "text" : "search";
            this._searchBox = this._createComponent($searchBox, TextBox, {
                mode: searchMode,
                showClearButton: true,
                valueChangeEvent: this.option("valueChangeEvent"),
                onValueChanged: $.proxy(this._searchHandler, this)
            });
            this._registerSearchKeyHandlers();
            $searchWrapper.insertBefore(this._$list)
        }
        this._renderSearchVisibility();
        this._setSearchPlaceholder()
    },
    _selectListItemHandler: function(e) {
        var $itemElement = this._list.option("focusedElement");
        if (!$itemElement) {
            return
        }
        e.preventDefault();
        this._selectListItem(e.itemData, $itemElement)
    },
    _registerSearchKeyHandlers: function() {
        this._searchBox.registerKeyHandler("escape", $.proxy(this.close, this));
        this._searchBox.registerKeyHandler("enter", $.proxy(this._selectListItemHandler, this));
        this._searchBox.registerKeyHandler("space", $.proxy(this._selectListItemHandler, this));
        this._searchBox.registerKeyHandler("end", $.noop);
        this._searchBox.registerKeyHandler("home", $.noop)
    },
    _renderSearchVisibility: function() {
        if (this._popup) {
            this._popup._wrapper().toggleClass(LOOKUP_POPUP_SEARCH_CLASS, this.option("searchEnabled"))
        }
    },
    _setSearchPlaceholder: function() {
        if (!this._$searchBox) {
            return
        }
        var minSearchLength = this.option("minSearchLength");
        var placeholder = this.option("searchPlaceholder");
        if (minSearchLength && placeholder === messageLocalization.format("Search")) {
            placeholder = messageLocalization.getFormatter("dxLookup-searchPlaceholder")(minSearchLength)
        }
        this._searchBox.option("placeholder", placeholder)
    },
    _setAriaTargetForList: $.noop,
    _renderList: function() {
        this.callBase();
        this._list.registerKeyHandler("escape", $.proxy(function() {
            this.close()
        }, this))
    },
    _listConfig: function() {
        return $.extend(this.callBase(), {
            tabIndex: 0,
            grouped: this.option("grouped"),
            groupTemplate: this._getTemplateByOption("groupTemplate"),
            pullRefreshEnabled: this.option("pullRefreshEnabled"),
            useNativeScrolling: this.option("useNativeScrolling"),
            pullingDownText: this.option("pullingDownText"),
            pulledDownText: this.option("pulledDownText"),
            refreshingText: this.option("refreshingText"),
            pageLoadingText: this.option("pageLoadingText"),
            onScroll: this.option("onScroll"),
            onPullRefresh: this.option("onPullRefresh"),
            onPageLoading: this.option("onPageLoading"),
            pageLoadMode: this._getPageLoadMode(),
            nextButtonText: this.option("nextButtonText"),
            _keyboardProcessor: this._listKeyboardProcessor,
            onFocusIn: $.proxy(this._onFocusInHandler, this),
            onSelectionChanged: this._getSelectionChangedHandler()
        })
    },
    _getSelectionChangedHandler: function() {
        return this.option("showSelectionControls") ? $.proxy(this._selectionChangeHandler, this) : $.noop
    },
    _onFocusInHandler: function() {
        this._setListOption("_keyboardProcessor", void 0)
    },
    _listContentReadyHandler: function() {
        this.callBase.apply(this, arguments);
        this._refreshSelected()
    },
    _getPageLoadMode: function() {
        this._suppressDeprecatedWarnings();
        var result = commonUtils.isDefined(this.option("showNextButton")) ? "nextButton" : this.option("pageLoadMode");
        this._resumeDeprecatedWarnings();
        return result
    },
    _setFocusPolicy: function() {
        if (!this.option("focusStateEnabled")) {
            return
        }
        if (this.option("searchEnabled")) {
            this._searchBox.focus()
        } else {
            this._$list.focus()
        }
    },
    _attachChildKeyboardEvents: $.noop,
    _focusTarget: function() {
        return this._$field
    },
    _keyboardEventBindingTarget: function() {
        return this._$field
    },
    _listItemClickHandler: function(e) {
        this._selectListItem(e.itemData, e.jQueryEvent.currentTarget)
    },
    _selectListItem: function(itemData, target) {
        this._list.selectItem(target);
        if ("instantly" === this.option("applyValueMode")) {
            this._applyButtonHandler()
        }
    },
    _currentSelectedItem: function() {
        return this.option("grouped") ? this._list.option("selectedItems[0]").items[0] : this._list.option("selectedItems[0]")
    },
    _resetValue: function() {
        this.option("value", null);
        this.option("opened", false)
    },
    _searchValue: function() {
        return this.option("searchEnabled") && this._searchBox ? this._searchBox.option("value") : ""
    },
    _renderInputValue: function() {
        return this.callBase().always($.proxy(function() {
            this._renderField();
            this._refreshSelected();
            this._setSubmitValue()
        }, this))
    },
    _setSubmitValue: function() {
        var value = this.option("value"),
            submitValue = "this" === this.option("valueExpr") ? this._displayGetter(value) : value;
        this._$submitElement.val(submitValue)
    },
    _renderPlaceholder: function() {
        if (0 === this.element().find("input").length) {
            return
        }
        this.callBase()
    },
    _clean: function() {
        this._$fieldWrapper.remove();
        this._$searchBox = null;
        this.callBase()
    },
    _optionChanged: function(args) {
        var name = args.name;
        var value = args.value;
        switch (name) {
            case "searchEnabled":
                this._popup && this._renderSearch();
                this._attachSearchChildProcessor();
                break;
            case "searchPlaceholder":
                this._setSearchPlaceholder();
                break;
            case "minSearchLength":
                this._setSearchPlaceholder();
                this.callBase.apply(this, arguments);
                break;
            case "title":
            case "titleTemplate":
            case "onTitleRendered":
            case "shading":
            case "animation":
            case "position":
            case "closeOnOutsideClick":
                this._setPopupOption(name);
                break;
            case "fullScreen":
            case "usePopover":
            case "placeholder":
                this._invalidate();
                break;
            case "clearButtonText":
            case "showClearButton":
            case "showCancelButton":
                this._setPopupOption("toolbarItems", this._getPopupToolbarItems());
                break;
            case "applyValueMode":
                this.callBase.apply(this, arguments);
                break;
            case "popupWidth":
                this._setPopupOption("popupWidth", "auto" === value ? this.initialOption("popupWidth") : value);
                break;
            case "popupHeight":
                this._setPopupOption("popupHeight", "auto" === value ? this.initialOption("popupHeight") : value);
                break;
            case "pullRefreshEnabled":
            case "useNativeScrolling":
            case "pullingDownText":
            case "pulledDownText":
            case "refreshingText":
            case "pageLoadingText":
            case "onScroll":
            case "onPullRefresh":
            case "onPageLoading":
            case "nextButtonText":
            case "grouped":
            case "groupTemplate":
                this._setListOption(name);
                break;
            case "showNextButton":
            case "pageLoadMode":
                this._setListOption("pageLoadMode", this._getPageLoadMode());
                break;
            case "cleanSearchOnOpening":
                break;
            default:
                this.callBase.apply(this, arguments)
        }
    },
    focus: function() {
        this.option("opened") ? this._setFocusPolicy() : this._focusTarget().focus()
    },
    field: function() {
        return this._$field
    }
});
registerComponent("dxLookup", Lookup);
module.exports = Lookup;
module.exports.default = module.exports;
