"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var react_1 = tslib_1.__importDefault(require("react"));
var xorBy_1 = tslib_1.__importDefault(require("lodash/xorBy"));
var unionBy_1 = tslib_1.__importDefault(require("lodash/unionBy"));
var Overlay_1 = tslib_1.__importDefault(require("../../components/Overlay"));
var Checkbox_1 = tslib_1.__importDefault(require("../../components/Checkbox"));
var PopOver_1 = tslib_1.__importDefault(require("../../components/PopOver"));
var react_overlays_1 = require("react-overlays");
var icons_1 = require("../../components/icons");
var helper_1 = require("../../utils/helper");
var tpl_builtin_1 = require("../../utils/tpl-builtin");
var Options_1 = require("../Form/Options");
var Input_1 = tslib_1.__importDefault(require("../../components/Input"));
var react_dom_1 = require("react-dom");
var NestedSelectControl = /** @class */ (function (_super) {
    tslib_1.__extends(NestedSelectControl, _super);
    function NestedSelectControl() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.state = {
            isOpened: false,
            isFocused: false,
            inputValue: '',
            stack: []
        };
        return _this;
    }
    NestedSelectControl.prototype.domRef = function (ref) {
        this.target = ref;
    };
    NestedSelectControl.prototype.open = function () {
        var _a = this.props, options = _a.options, disabled = _a.disabled;
        if (!disabled) {
            this.setState({
                isOpened: true,
                stack: [options]
            });
        }
    };
    NestedSelectControl.prototype.close = function () {
        this.setState({
            isOpened: false,
            stack: []
        });
    };
    NestedSelectControl.prototype.removeItem = function (index, e) {
        var _a = this.props, onChange = _a.onChange, selectedOptions = _a.selectedOptions, disabled = _a.disabled, joinValues = _a.joinValues, valueField = _a.valueField, extractValue = _a.extractValue, delimiter = _a.delimiter, value = _a.value;
        if (disabled) {
            return;
        }
        e && e.stopPropagation();
        selectedOptions.splice(index, 1);
        if (joinValues) {
            value = selectedOptions
                .map(function (item) { return item[valueField || 'value']; })
                .join(delimiter || ',');
        }
        else if (extractValue) {
            value = selectedOptions.map(function (item) { return item[valueField || 'value']; });
        }
        onChange(value);
    };
    NestedSelectControl.prototype.renderValue = function () {
        var _this = this;
        var _a = this.props, multiple = _a.multiple, cx = _a.classnames, selectedOptions = _a.selectedOptions, labelField = _a.labelField, placeholder = _a.placeholder, disabled = _a.disabled;
        if (!(selectedOptions && selectedOptions.length > 0)) {
            return (react_1.default.createElement("div", { className: cx('NestedSelect-placeholder') }, placeholder));
        }
        return selectedOptions.map(function (item, index) {
            return multiple ? (react_1.default.createElement("div", { className: cx('Select-value'), key: index },
                react_1.default.createElement("span", { className: cx('Select-valueIcon', {
                        'is-disabled': disabled || item.disabled
                    }), onClick: _this.removeItem.bind(_this, index) }, "\u00D7"),
                react_1.default.createElement("span", { className: cx('Select-valueLabel') }, item[labelField || 'label']))) : (react_1.default.createElement("div", { className: cx('Select-value'), key: index }, item[labelField || 'label']));
        });
    };
    NestedSelectControl.prototype.renderClear = function () {
        var _a = this.props, clearable = _a.clearable, value = _a.value, disabled = _a.disabled, cx = _a.classnames;
        return clearable &&
            !disabled &&
            (Array.isArray(value) ? value.length : value) ? (react_1.default.createElement("a", { onClick: this.clearValue, className: cx('NestedSelect-clear') },
            react_1.default.createElement(icons_1.Icon, { icon: "close", className: "icon" }))) : null;
    };
    NestedSelectControl.prototype.clearValue = function () {
        var _a = this.props, onChange = _a.onChange, resetValue = _a.resetValue;
        onChange(typeof resetValue === 'undefined' ? '' : resetValue);
    };
    NestedSelectControl.prototype.handleOptionClick = function (option, e) {
        var _a = this.props, multiple = _a.multiple, onChange = _a.onChange, joinValues = _a.joinValues, extractValue = _a.extractValue, valueField = _a.valueField, autoFill = _a.autoFill, onBulkChange = _a.onBulkChange;
        if (multiple) {
            return;
        }
        e.stopPropagation();
        var sendTo = !multiple &&
            autoFill &&
            !helper_1.isEmpty(autoFill) &&
            tpl_builtin_1.dataMapping(autoFill, option);
        sendTo && onBulkChange(sendTo);
        onChange(joinValues
            ? option[valueField || 'value']
            : extractValue
                ? option[valueField || 'value']
                : option);
        !multiple && this.close();
    };
    NestedSelectControl.prototype.handleCheck = function (option, index) {
        var _a = this.props, onChange = _a.onChange, selectedOptions = _a.selectedOptions, joinValues = _a.joinValues, valueField = _a.valueField, delimiter = _a.delimiter, extractValue = _a.extractValue, withChildren = _a.withChildren, cascade = _a.cascade, multiple = _a.multiple;
        var stack = this.state.stack;
        if (!Array.isArray(option) &&
            option.children &&
            option.children.length &&
            typeof index === 'number') {
            var checked = selectedOptions.some(function (o) { return o.value == option.value; });
            var uncheckable_1 = cascade
                ? false
                : option.uncheckable || (multiple && !checked);
            var children = option.children.map(function (c) { return (tslib_1.__assign(tslib_1.__assign({}, c), { uncheckable: uncheckable_1 })); });
            if (stack[index]) {
                stack.splice(index + 1, 1, children);
            }
            else {
                stack.push(children);
            }
        }
        var items = selectedOptions.concat();
        var newValue;
        // 三种情况：
        // 1.全选，option为数组
        // 2.单个选中，且有children
        // 3.单个选中，没有children
        if (Array.isArray(option)) {
            option = withChildren ? helper_1.flattenTree(option) : option;
            newValue = items.length === option.length ? [] : option;
        }
        else if (Array.isArray(option.children)) {
            if (cascade) {
                newValue = xorBy_1.default(items, [option], valueField || 'value');
            }
            else if (withChildren) {
                option = helper_1.flattenTree([option]);
                var fn = option.every(function (opt) { return !!~items.findIndex(function (item) { return item.value === opt.value; }); })
                    ? xorBy_1.default
                    : unionBy_1.default;
                newValue = fn(items, option, valueField || 'value');
            }
            else {
                newValue = items.filter(function (item) {
                    return !~helper_1.flattenTree([option], function (i) { return i.value; }).indexOf(item.value);
                });
                !~items.map(function (item) { return item.value; }).indexOf(option.value) &&
                    newValue.push(option);
            }
        }
        else {
            newValue = xorBy_1.default(items, [option], valueField || 'value');
        }
        if (joinValues) {
            newValue = newValue
                .map(function (item) { return item[valueField || 'value']; })
                .join(delimiter || ',');
        }
        else if (extractValue) {
            newValue = newValue.map(function (item) { return item[valueField || 'value']; });
        }
        onChange(newValue);
    };
    NestedSelectControl.prototype.allChecked = function (options) {
        var _this = this;
        var _a = this.props, selectedOptions = _a.selectedOptions, withChildren = _a.withChildren;
        return options.every(function (option) {
            if (withChildren && option.children) {
                return _this.allChecked(option.children);
            }
            return selectedOptions.some(function (selectedOption) { return selectedOption.value == option.value; });
        });
    };
    NestedSelectControl.prototype.partialChecked = function (options) {
        var _this = this;
        var _a = this.props, selectedOptions = _a.selectedOptions, withChildren = _a.withChildren;
        return options.some(function (option) {
            if (withChildren && option.children) {
                return _this.partialChecked(option.children);
            }
            return selectedOptions.some(function (selectedOption) { return selectedOption.value == option.value; });
        });
    };
    NestedSelectControl.prototype.reload = function () {
        var reload = this.props.reloadOptions;
        reload && reload();
    };
    NestedSelectControl.prototype.onFocus = function (e) {
        this.props.disabled ||
            this.state.isOpened ||
            this.setState({
                isFocused: true
            }, this.focus);
        this.props.onFocus && this.props.onFocus(e);
    };
    NestedSelectControl.prototype.onBlur = function (e) {
        this.setState({
            isFocused: false
        });
        this.props.onBlur && this.props.onBlur(e);
    };
    NestedSelectControl.prototype.focus = function () {
        this.input
            ? this.input.focus()
            : this.getTarget() && this.getTarget().focus();
    };
    NestedSelectControl.prototype.blur = function () {
        this.input
            ? this.input.blur()
            : this.getTarget() && this.getTarget().blur();
    };
    NestedSelectControl.prototype.getTarget = function () {
        if (!this.target) {
            this.target = react_dom_1.findDOMNode(this);
        }
        return this.target;
    };
    NestedSelectControl.prototype.inputRef = function (ref) {
        this.input = ref;
    };
    NestedSelectControl.prototype.handleInputChange = function (evt) {
        var inputValue = evt.currentTarget.value;
        var _a = this.props, options = _a.options, labelField = _a.labelField, valueField = _a.valueField;
        var regexp = helper_1.string2regExp(inputValue);
        var filtedOptions = inputValue && this.state.isOpened
            ? helper_1.filterTree(options, function (option) {
                return regexp.test(option[labelField || 'label']) ||
                    regexp.test(option[valueField || 'value']) ||
                    !!(option.children && option.children.length);
            }, 1, true)
            : options.concat();
        this.setState({
            inputValue: inputValue,
            stack: [filtedOptions]
        });
    };
    NestedSelectControl.prototype.renderOptions = function () {
        var _this = this;
        var _a = this.props, multiple = _a.multiple, selectedOptions = _a.selectedOptions, cx = _a.classnames, value = _a.value, options = _a.options, disabled = _a.disabled, searchable = _a.searchable, searchPromptText = _a.searchPromptText;
        var stack = this.state.stack;
        var searchInput = searchable ? (react_1.default.createElement("div", { className: cx("Select-input", {
                'is-focused': this.state.isFocused
            }) },
            react_1.default.createElement(icons_1.Icon, { icon: "search", className: "icon" }),
            react_1.default.createElement(Input_1.default, { value: this.state.inputValue, onFocus: this.onFocus, onBlur: this.onBlur, disabled: disabled, placeholder: searchPromptText, onChange: this.handleInputChange, ref: this.inputRef }))) : null;
        var partialChecked = this.partialChecked(options);
        var allChecked = this.allChecked(options);
        return (react_1.default.createElement(react_1.default.Fragment, null, stack.map(function (options, index) { return (react_1.default.createElement("div", { key: index, className: cx('NestedSelect-menu') },
            index === 0 ? searchInput : null,
            multiple && index === 0 ? (react_1.default.createElement("div", { className: cx('NestedSelect-option', 'checkall'), onMouseEnter: _this.onMouseEnterAll },
                react_1.default.createElement(Checkbox_1.default, { onChange: _this.handleCheck.bind(_this, options), checked: partialChecked, partial: partialChecked && !allChecked }, "\u5168\u9009"))) : null,
            options.map(function (option, idx) {
                var checked = selectedOptions.some(function (o) { return o.value == option.value; });
                var selfChecked = !!option.uncheckable || checked;
                var nodeDisabled = !!option.uncheckable || !!disabled;
                return (react_1.default.createElement("div", { key: idx, className: cx('NestedSelect-option', {
                        'is-active': value && value === option.value
                    }), onClick: _this.handleOptionClick.bind(_this, option), onMouseEnter: _this.onMouseEnter.bind(_this, option, index) },
                    multiple ? (react_1.default.createElement(Checkbox_1.default, { className: cx('NestedSelect-optionLabel'), onChange: _this.handleCheck.bind(_this, option, index), trueValue: option.value, checked: selfChecked, disabled: nodeDisabled }, option.label)) : (react_1.default.createElement("div", { className: cx('NestedSelect-optionLabel') },
                        react_1.default.createElement("span", null, option.label))),
                    option.children && option.children.length ? (react_1.default.createElement("div", { className: cx('NestedSelect-optionArrowRight') },
                        react_1.default.createElement(icons_1.Icon, { icon: "right-arrow", className: "icon" }))) : null));
            }))); })));
    };
    NestedSelectControl.prototype.onMouseEnterAll = function () {
        this.setState({
            stack: [this.props.options]
        });
    };
    NestedSelectControl.prototype.onMouseEnter = function (option, index, e) {
        var stack = this.state.stack;
        var _a = this.props, cascade = _a.cascade, multiple = _a.multiple, selectedOptions = _a.selectedOptions;
        index = index + 1;
        if (option.children && option.children.length) {
            var checked = selectedOptions.some(function (o) { return o.value == option.value; });
            var uncheckable_2 = cascade
                ? false
                : option.uncheckable || (multiple && checked);
            var children = option.children.map(function (c) { return (tslib_1.__assign(tslib_1.__assign({}, c), { uncheckable: uncheckable_2 })); });
            if (stack[index]) {
                stack.splice(index, 1, children);
            }
            else {
                stack.push(children);
            }
        }
        else {
            stack[index] && stack.splice(index, 1);
        }
        this.setState({ stack: stack.slice(0, index + 1) });
    };
    NestedSelectControl.prototype.renderOuter = function () {
        var _a = this.props, popOverContainer = _a.popOverContainer, cx = _a.classnames;
        var body = (react_1.default.createElement(react_overlays_1.RootCloseWrapper, { disabled: !this.state.isOpened, onRootClose: this.close },
            react_1.default.createElement("div", { className: cx('NestedSelect-menuOuter') }, this.renderOptions())));
        return (react_1.default.createElement(Overlay_1.default, { container: popOverContainer || this.getTarget, target: this.getTarget, show: true },
            react_1.default.createElement(PopOver_1.default, { className: cx('NestedSelect-popover') }, body)));
    };
    NestedSelectControl.prototype.render = function () {
        var _a;
        var _b = this.props, className = _b.className, disabled = _b.disabled, cx = _b.classnames, multiple = _b.multiple;
        return (react_1.default.createElement("div", { className: cx('NestedSelectControl', className) },
            react_1.default.createElement("div", { className: cx('NestedSelect', (_a = {},
                    _a["NestedSelect--multi"] = multiple,
                    _a['is-opened'] = this.state.isOpened,
                    _a['is-disabled'] = disabled,
                    _a)), onClick: this.open, ref: this.domRef },
                react_1.default.createElement("div", { className: cx('NestedSelect-valueWrap'), onClick: this.open }, this.renderValue()),
                this.renderClear(),
                react_1.default.createElement("span", { className: cx('Select-arrow') })),
            this.state.isOpened ? this.renderOuter() : null));
    };
    var _a, _b;
    NestedSelectControl.defaultProps = {
        cascade: false,
        withChildren: false,
        searchPromptText: '输入内容进行检索'
    };
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", [Object]),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "domRef", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", []),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "open", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", []),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "close", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", []),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "clearValue", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", [Object]),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "onFocus", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", [Object]),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "onBlur", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", []),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "focus", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", []),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "blur", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", []),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "getTarget", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", [typeof (_a = typeof HTMLInputElement !== "undefined" && HTMLInputElement) === "function" ? _a : Object]),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "inputRef", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", [typeof (_b = typeof react_1.default !== "undefined" && react_1.default.ChangeEvent) === "function" ? _b : Object]),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "handleInputChange", null);
    tslib_1.__decorate([
        helper_1.autobind,
        tslib_1.__metadata("design:type", Function),
        tslib_1.__metadata("design:paramtypes", []),
        tslib_1.__metadata("design:returntype", void 0)
    ], NestedSelectControl.prototype, "onMouseEnterAll", null);
    return NestedSelectControl;
}(react_1.default.Component));
exports.default = NestedSelectControl;
var NestedSelectControlRenderer = /** @class */ (function (_super) {
    tslib_1.__extends(NestedSelectControlRenderer, _super);
    function NestedSelectControlRenderer() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    NestedSelectControlRenderer = tslib_1.__decorate([
        Options_1.OptionsControl({
            type: 'nested-select'
        })
    ], NestedSelectControlRenderer);
    return NestedSelectControlRenderer;
}(NestedSelectControl));
exports.NestedSelectControlRenderer = NestedSelectControlRenderer;
//# sourceMappingURL=./renderers/Form/NestedSelect.js.map
