/**
 * DevExtreme (ui/date_box/ui.date_box.mask.js)
 * Version: 18.2.3 (build 18323)
 * Build date: Mon Nov 19 2018
 *
 * Copyright (c) 2012 - 2018 Developer Express Inc. ALL RIGHTS RESERVED
 * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
 */
"use strict";
var _utils = require("../../events/utils");
var _utils2 = _interopRequireDefault(_utils);
var _type = require("../../core/utils/type");
var _dom = require("../../core/utils/dom");
var _extend = require("../../core/utils/extend");
var _math = require("../../core/utils/math");
var _events_engine = require("../../events/core/events_engine");
var _events_engine2 = _interopRequireDefault(_events_engine);
var _wheel = require("../../events/core/wheel");
var _wheel2 = _interopRequireDefault(_wheel);
var _uiDate_boxMask = require("./ui.date_box.mask.parts");
var _date = require("../../localization/date");
var _date2 = _interopRequireDefault(_date);
var _date3 = require("../../localization/ldml/date.format");
var _uiDate_box = require("./ui.date_box.base");
var _uiDate_box2 = _interopRequireDefault(_uiDate_box);

function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        "default": obj
    }
}
var MASK_EVENT_NAMESPACE = "dateBoxMask",
    FORWARD = 1,
    BACKWARD = -1;
var DateBoxMask = _uiDate_box2.default.inherit({
    _supportedKeys: function(e) {
        if (!this._useMaskBehavior() || this.option("opened") || e && e.altKey) {
            return this.callBase(e)
        }
        var that = this;
        return (0, _extend.extend)(this.callBase(e), {
            del: that._revertPart.bind(that, FORWARD),
            backspace: that._revertPart.bind(that, BACKWARD),
            home: that._selectFirstPart.bind(that),
            end: that._selectLastPart.bind(that),
            escape: that._revertChanges.bind(that),
            enter: that._enterHandler.bind(that),
            leftArrow: that._selectNextPart.bind(that, BACKWARD),
            rightArrow: that._selectNextPart.bind(that, FORWARD),
            upArrow: that._partIncrease.bind(that, FORWARD),
            downArrow: that._partIncrease.bind(that, BACKWARD)
        })
    },
    _getDefaultOptions: function() {
        return (0, _extend.extend)(this.callBase(), {
            useMaskBehavior: false,
            advanceCaret: true
        })
    },
    _isSingleCharKey: function(e) {
        var key = e.originalEvent.key;
        return "string" === typeof key && 1 === key.length && !e.ctrl && !e.alt
    },
    _keyboardHandler: function(e) {
        var key = e.originalEvent.key;
        var result = this.callBase(e);
        if (!this._useMaskBehavior() || !this._isSingleCharKey(e)) {
            return result
        }
        this._setNewDateIfEmpty();
        isNaN(parseInt(key)) ? this._searchString(key) : this._searchNumber(key);
        e.originalEvent.preventDefault();
        return result
    },
    _getFormatPattern: function() {
        var format = this._strategy.getDisplayFormat(this.option("displayFormat")),
            isLDMLPattern = "string" === typeof format && (format.indexOf("0") >= 0 || format.indexOf("#") >= 0);
        if (isLDMLPattern) {
            return format
        } else {
            return (0, _date3.getFormat)(function(value) {
                return _date2.default.format(value, format)
            })
        }
    },
    _setNewDateIfEmpty: function() {
        if (!this._maskValue) {
            this._maskValue = new Date;
            this._renderDateParts()
        }
    },
    _searchNumber: function(char) {
        this._searchValue += char;
        var limits = this._getActivePartLimits(),
            getter = this._getActivePartProp("getter"),
            newValue = parseInt(this._searchValue);
        if ("getMonth" === getter) {
            newValue--
        }
        if (!(0, _math.inRange)(newValue, limits.min, limits.max)) {
            this._searchValue = char;
            newValue = parseInt(char)
        }
        this._setActivePartValue(newValue);
        if (this.option("advanceCaret")) {
            if (parseInt(this._searchValue + "0") > limits.max) {
                this._selectNextPart(FORWARD)
            }
        }
    },
    _searchString: function(char) {
        if (!isNaN(parseInt(this._getActivePartProp("text")))) {
            return
        }
        var limits = this._getActivePartProp("limits")(this._maskValue),
            startString = this._searchValue + char.toLowerCase(),
            endLimit = limits.max - limits.min;
        for (var i = 0; i <= endLimit; i++) {
            this._partIncrease(1);
            if (0 === this._getActivePartProp("text").toLowerCase().indexOf(startString)) {
                this._searchValue = startString;
                return
            }
        }
        this._revertPart(0);
        if (this._searchValue) {
            this._clearSearchValue();
            this._searchString(char)
        }
    },
    _clearSearchValue: function() {
        this._searchValue = ""
    },
    _revertPart: function(direction, e) {
        var value = this.dateOption("value");
        var caret = this._caret();
        var isAllSelected = caret.end - caret.start === this.option("text").length;
        if (!isAllSelected) {
            if (value) {
                var actual = this._getActivePartValue(value);
                this._setActivePartValue(actual)
            }
            this._selectNextPart(direction, e)
        }
    },
    _useMaskBehavior: function() {
        return this.option("useMaskBehavior") && "text" === this.option("mode")
    },
    _renderMask: function() {
        this.callBase();
        this._detachMaskEvents();
        this._clearState();
        if (this._useMaskBehavior()) {
            this._activePartIndex = 0;
            this._attachMaskEvents();
            this._loadMaskValue();
            this._renderDateParts()
        }
    },
    _renderDateParts: function() {
        if (!this._useMaskBehavior()) {
            return
        }
        var text = this.option("text") || this._getDisplayedText(this._maskValue);
        if (text) {
            this._dateParts = (0, _uiDate_boxMask.renderDateParts)(text, this._getFormatPattern());
            this._selectNextPart(0)
        }
    },
    _detachMaskEvents: function() {
        _events_engine2.default.off(this._input(), "." + MASK_EVENT_NAMESPACE)
    },
    _attachMaskEvents: function() {
        var _this = this;
        _events_engine2.default.on(this._input(), _utils2.default.addNamespace("dxclick", MASK_EVENT_NAMESPACE), this._maskClickHandler.bind(this));
        _events_engine2.default.on(this._input(), _utils2.default.addNamespace("paste", MASK_EVENT_NAMESPACE), this._maskPasteHandler.bind(this));
        _events_engine2.default.on(this._input(), _utils2.default.addNamespace("drop", MASK_EVENT_NAMESPACE), function(e) {
            _this._renderDisplayText(_this._getDisplayedText(_this._maskValue));
            _this._selectNextPart(0, e)
        });
        _events_engine2.default.on(this._input(), _utils2.default.addNamespace(_wheel2.default.name, MASK_EVENT_NAMESPACE), this._mouseWheelHandler.bind(this))
    },
    _selectLastPart: function(e) {
        if (this.option("text")) {
            this._activePartIndex = this._dateParts.length;
            this._selectNextPart(BACKWARD, e)
        }
    },
    _selectFirstPart: function(e) {
        if (this.option("text")) {
            this._activePartIndex = -1;
            this._selectNextPart(FORWARD, e)
        }
    },
    _mouseWheelHandler: function(e) {
        this._partIncrease(e.delta > 0 ? FORWARD : BACKWARD, e)
    },
    _selectNextPart: function(step, e) {
        if (!this.option("text")) {
            return
        }
        var index = (0, _math.fitIntoRange)(this._activePartIndex + step, 0, this._dateParts.length - 1);
        if (this._dateParts[index].isStub) {
            var isBoundaryIndex = 0 === index && step < 0 || index === this._dateParts.length - 1 && step > 0;
            if (!isBoundaryIndex) {
                this._selectNextPart(step >= 0 ? step + 1 : step - 1, e);
                return
            } else {
                index = this._activePartIndex
            }
        }
        this._activePartIndex = index;
        this._caret(this._getActivePartProp("caret"));
        if (0 !== step) {
            this._clearSearchValue()
        }
        e && e.preventDefault()
    },
    _getActivePartLimits: function() {
        var limitFunction = this._getActivePartProp("limits");
        return limitFunction(this._maskValue)
    },
    _getActivePartValue: function(dateValue) {
        dateValue = dateValue || this._maskValue;
        var getter = this._getActivePartProp("getter");
        return (0, _type.isFunction)(getter) ? getter(dateValue) : dateValue[getter]()
    },
    _setActivePartValue: function(value, dateValue) {
        dateValue = dateValue || this._maskValue;
        var setter = this._getActivePartProp("setter"),
            limits = this._getActivePartLimits();
        value = (0, _math.fitIntoRange)(value, limits.min, limits.max);
        (0, _type.isFunction)(setter) ? setter(dateValue, value): dateValue[setter](value);
        this._renderDisplayText(this._getDisplayedText(dateValue));
        this._renderDateParts()
    },
    _getActivePartProp: function(property) {
        if (!this._dateParts || !this._dateParts[this._activePartIndex]) {
            return
        }
        return this._dateParts[this._activePartIndex][property]
    },
    _loadMaskValue: function() {
        var value = this.dateOption("value");
        this._maskValue = value && new Date(value)
    },
    _saveMaskValue: function() {
        var value = this._maskValue && new Date(this._maskValue);
        this.dateOption("value", value)
    },
    _revertChanges: function() {
        this._loadMaskValue();
        this._renderDisplayText(this._getDisplayedText(this._maskValue));
        this._renderDateParts()
    },
    _renderDisplayText: function(text) {
        this.callBase(text);
        if (this._useMaskBehavior()) {
            this.option("text", text)
        }
    },
    _partIncrease: function(step, e) {
        this._setNewDateIfEmpty();
        var limits = this._getActivePartLimits(),
            newValue = step + this._getActivePartValue();
        newValue = newValue > limits.max ? limits.min : newValue;
        newValue = newValue < limits.min ? limits.max : newValue;
        this._setActivePartValue(newValue);
        e && e.preventDefault()
    },
    _maskClickHandler: function() {
        if (this.option("text")) {
            this._activePartIndex = (0, _uiDate_boxMask.getDatePartIndexByPosition)(this._dateParts, this._caret().start);
            this._caret(this._getActivePartProp("caret"))
        }
    },
    _maskPasteHandler: function(e) {
        var newText = this._replaceSelectedText(this.option("text"), this._caret(), (0, _dom.clipboardText)(e));
        var date = _date2.default.parse(newText, this._getFormatPattern());
        if (date) {
            this._renderDateParts();
            this._maskValue = date;
            this._renderDisplayText(this._getDisplayedText(this._maskValue));
            this._selectNextPart(0, e)
        } else {
            e.preventDefault()
        }
    },
    _isValueDirty: function() {
        var value = this.dateOption("value");
        return (this._maskValue && this._maskValue.getTime()) !== (value && value.getTime())
    },
    _fireChangeEvent: function() {
        this._clearSearchValue();
        if (this._isValueDirty()) {
            _events_engine2.default.trigger(this._input(), "change")
        }
    },
    _enterHandler: function(e) {
        this._fireChangeEvent();
        this._selectNextPart(FORWARD, e)
    },
    _focusOutHandler: function(e) {
        this.callBase(e);
        if (this._useMaskBehavior()) {
            this._fireChangeEvent();
            this._selectFirstPart(e)
        }
    },
    _valueChangeEventHandler: function(e) {
        if (this._useMaskBehavior()) {
            this._saveValueChangeEvent(e);
            if (!this.option("text")) {
                this._maskValue = null
            }
            this._saveMaskValue()
        } else {
            this.callBase(e)
        }
    },
    _optionChanged: function(args) {
        switch (args.name) {
            case "useMaskBehavior":
                this._renderMask();
                break;
            case "displayFormat":
            case "mode":
                this.callBase(args);
                this._renderMask();
                break;
            case "value":
                this._loadMaskValue();
                this.callBase(args);
                this._renderDateParts();
                break;
            case "advanceCaret":
                break;
            default:
                this.callBase(args)
        }
    },
    _clearState: function() {
        this._clearSearchValue();
        delete this._dateParts;
        delete this._activePartIndex;
        delete this._maskValue
    },
    reset: function() {
        this.callBase();
        this._clearState();
        this._activePartIndex = 0
    },
    _clean: function() {
        this.callBase();
        this._detachMaskEvents();
        this._clearState()
    }
});
module.exports = DateBoxMask;
