"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = generate;

var _vue = require("vue");

var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));

var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));

var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));

var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));

var _generate = _interopRequireDefault(require("../vc-select/generate"));

var _TreeNode = _interopRequireDefault(require("./TreeNode"));

var _valueUtil = require("./utils/valueUtil");

var _warningPropsUtil = _interopRequireDefault(require("./utils/warningPropsUtil"));

var _Context = require("./Context");

var _useTreeData = _interopRequireDefault(require("./hooks/useTreeData"));

var _useKeyValueMap3 = _interopRequireDefault(require("./hooks/useKeyValueMap"));

var _useKeyValueMapping3 = _interopRequireDefault(require("./hooks/useKeyValueMapping"));

var _strategyUtil = require("./utils/strategyUtil");

var _legacyUtil = require("./utils/legacyUtil");

var _useSelectValues = _interopRequireDefault(require("./hooks/useSelectValues"));

var _props = require("./props");

var _valueUtil2 = require("../vc-select/utils/valueUtil");

var _omit = _interopRequireDefault(require("../_util/omit"));

var _treeUtil = require("../vc-tree/utils/treeUtil");

var _conductUtil = require("../vc-tree/utils/conductUtil");

var _warning = require("../vc-util/warning");

var _generator = require("../vc-select/interface/generator");

var OMIT_PROPS = ['expandedKeys', 'treeData', 'treeCheckable', 'showCheckedStrategy', 'searchPlaceholder', 'treeLine', 'treeIcon', 'showTreeIcon', 'switcherIcon', 'treeNodeFilterProp', 'filterTreeNode', 'dropdownPopupAlign', 'treeDefaultExpandAll', 'treeCheckStrictly', 'treeExpandedKeys', 'treeLoadedKeys', 'treeMotion', 'onTreeExpand', 'onTreeLoad', 'labelRender', 'loadData', 'treeDataSimpleMode', 'treeNodeLabelProp', 'treeDefaultExpandedKeys', 'bordered'];

function generate(config) {
  var prefixCls = config.prefixCls,
      optionList = config.optionList;
  var RefSelect = (0, _generate.default)({
    prefixCls: prefixCls,
    components: {
      optionList: optionList
    },
    // Not use generate since we will handle ourself
    convertChildrenToData: function convertChildrenToData() {
      return null;
    },
    flattenOptions: _valueUtil.flattenOptions,
    // Handle `optionLabelProp` in TreeSelect component
    getLabeledValue: _valueUtil2.getLabeledValue,
    filterOptions: _valueUtil.filterOptions,
    isValueDisabled: _valueUtil.isValueDisabled,
    findValueOption: _valueUtil.findValueOption,
    omitDOMProps: function omitDOMProps(props) {
      return (0, _omit.default)(props, OMIT_PROPS);
    }
  });
  return (0, _vue.defineComponent)({
    name: 'TreeSelect',
    props: (0, _props.treeSelectProps)(),
    slots: ['title', 'placeholder', 'maxTagPlaceholder', 'treeIcon', 'switcherIcon', 'notFoundContent', 'treeCheckable'],
    TreeNode: _TreeNode.default,
    SHOW_ALL: _strategyUtil.SHOW_ALL,
    SHOW_PARENT: _strategyUtil.SHOW_PARENT,
    SHOW_CHILD: _strategyUtil.SHOW_CHILD,
    setup: function setup(props, _ref) {
      var expose = _ref.expose,
          slots = _ref.slots,
          attrs = _ref.attrs;
      var mergedCheckable = (0, _vue.computed)(function () {
        return props.treeCheckable || props.treeCheckStrictly;
      });
      var mergedMultiple = (0, _vue.computed)(function () {
        return props.multiple || mergedCheckable.value;
      });
      var treeConduction = (0, _vue.computed)(function () {
        return props.treeCheckable && !props.treeCheckStrictly;
      });
      var mergedLabelInValue = (0, _vue.computed)(function () {
        return props.treeCheckStrictly || props.labelInValue;
      }); // ======================= Tree Data =======================
      // FieldNames

      var mergedFieldNames = (0, _vue.computed)(function () {
        return (0, _valueUtil.fillFieldNames)(props.fieldNames, true);
      }); // Legacy both support `label` or `title` if not set.
      // We have to fallback to function to handle this

      var getTreeNodeTitle = function getTreeNodeTitle(node) {
        var _mergedFieldNames$val;

        if (!props.treeData) {
          return node.title;
        }

        if ((_mergedFieldNames$val = mergedFieldNames.value) !== null && _mergedFieldNames$val !== void 0 && _mergedFieldNames$val.label) {
          return node[mergedFieldNames.value.label];
        }

        return node.label || node.title;
      };

      var getTreeNodeLabelProp = function getTreeNodeLabelProp(entity) {
        var labelRender = props.labelRender,
            treeNodeLabelProp = props.treeNodeLabelProp;
        var node = entity.data.node;

        if (labelRender) {
          return labelRender(entity);
        }

        if (treeNodeLabelProp) {
          return node[treeNodeLabelProp];
        }

        return getTreeNodeTitle(node);
      };

      var mergedTreeData = (0, _useTreeData.default)((0, _vue.toRef)(props, 'treeData'), (0, _vue.toRef)(props, 'children'), {
        getLabelProp: getTreeNodeTitle,
        simpleMode: (0, _vue.toRef)(props, 'treeDataSimpleMode'),
        fieldNames: mergedFieldNames
      });
      var flattedOptions = (0, _vue.computed)(function () {
        return (0, _valueUtil.flattenOptions)(mergedTreeData.value);
      });

      var _useKeyValueMap = (0, _useKeyValueMap3.default)(flattedOptions),
          _useKeyValueMap2 = (0, _slicedToArray2.default)(_useKeyValueMap, 2),
          cacheKeyMap = _useKeyValueMap2[0],
          cacheValueMap = _useKeyValueMap2[1];

      var _useKeyValueMapping = (0, _useKeyValueMapping3.default)(cacheKeyMap, cacheValueMap),
          _useKeyValueMapping2 = (0, _slicedToArray2.default)(_useKeyValueMapping, 2),
          getEntityByKey = _useKeyValueMapping2[0],
          getEntityByValue = _useKeyValueMapping2[1]; // Only generate keyEntities for check conduction when is `treeCheckable`


      var conductKeyEntities = (0, _vue.computed)(function () {
        if (treeConduction.value) {
          return (0, _treeUtil.convertDataToEntities)(mergedTreeData.value).keyEntities;
        }

        return null;
      }); // ========================== Ref ==========================

      var selectRef = (0, _vue.ref)();
      expose({
        scrollTo: function scrollTo() {
          var _selectRef$value$scro, _selectRef$value;

          for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }

          return (_selectRef$value$scro = (_selectRef$value = selectRef.value).scrollTo) === null || _selectRef$value$scro === void 0 ? void 0 : _selectRef$value$scro.call.apply(_selectRef$value$scro, [_selectRef$value].concat(args));
        },
        focus: function focus() {
          var _selectRef$value$focu, _selectRef$value2;

          return (_selectRef$value$focu = (_selectRef$value2 = selectRef.value).focus) === null || _selectRef$value$focu === void 0 ? void 0 : _selectRef$value$focu.call(_selectRef$value2);
        },
        blur: function blur() {
          var _selectRef$value3;

          return (_selectRef$value3 = selectRef.value) === null || _selectRef$value3 === void 0 ? void 0 : _selectRef$value3.blur();
        },

        /** @private Internal usage. It's save to remove if `rc-cascader` not use it any longer */
        getEntityByValue: getEntityByValue
      });
      var valueRef = (0, _vue.ref)(props.defaultValue);
      (0, _vue.watch)(function () {
        return props.value;
      }, function () {
        if (props.value !== undefined) {
          valueRef.value = props.value;
        }
      }, {
        immediate: true
      });
      /** Get `missingRawValues` which not exist in the tree yet */

      var splitRawValues = function splitRawValues(newRawValues) {
        var missingRawValues = [];
        var existRawValues = []; // Keep missing value in the cache

        newRawValues.forEach(function (val) {
          if (getEntityByValue(val)) {
            existRawValues.push(val);
          } else {
            missingRawValues.push(val);
          }
        });
        return {
          missingRawValues: missingRawValues,
          existRawValues: existRawValues
        };
      };

      var rawValues = (0, _vue.shallowRef)([]);
      var rawHalfCheckedKeys = (0, _vue.shallowRef)([]);
      (0, _vue.watchEffect)(function () {
        var valueHalfCheckedKeys = [];
        var newRawValues = [];
        (0, _valueUtil.toArray)(valueRef.value).forEach(function (item) {
          if (item && (0, _typeof2.default)(item) === 'object' && 'value' in item) {
            if (item.halfChecked && props.treeCheckStrictly) {
              var entity = getEntityByValue(item.value);
              valueHalfCheckedKeys.push(entity ? entity.key : item.value);
            } else {
              newRawValues.push(item.value);
            }
          } else {
            newRawValues.push(item);
          }
        }); // We need do conduction of values

        if (treeConduction.value) {
          var _splitRawValues = splitRawValues(newRawValues),
              missingRawValues = _splitRawValues.missingRawValues,
              existRawValues = _splitRawValues.existRawValues;

          var keyList = existRawValues.map(function (val) {
            return getEntityByValue(val).key;
          });

          var _conductCheck = (0, _conductUtil.conductCheck)(keyList, true, conductKeyEntities.value),
              checkedKeys = _conductCheck.checkedKeys,
              halfCheckedKeys = _conductCheck.halfCheckedKeys;

          rawValues.value = [].concat((0, _toConsumableArray2.default)(missingRawValues), (0, _toConsumableArray2.default)(checkedKeys.map(function (key) {
            return getEntityByKey(key).data.value;
          })));
          rawHalfCheckedKeys.value = halfCheckedKeys;
        } else {
          var _ref2 = [newRawValues, valueHalfCheckedKeys];
          rawValues.value = _ref2[0];
          rawHalfCheckedKeys.value = _ref2[1];
        }
      });
      var selectValues = (0, _useSelectValues.default)(rawValues, {
        treeConduction: treeConduction,
        value: valueRef,
        showCheckedStrategy: (0, _vue.toRef)(props, 'showCheckedStrategy'),
        conductKeyEntities: conductKeyEntities,
        getEntityByValue: getEntityByValue,
        getEntityByKey: getEntityByKey,
        getLabelProp: getTreeNodeLabelProp
      });

      var triggerChange = function triggerChange(newRawValues, extra, source) {
        var onChange = props.onChange,
            showCheckedStrategy = props.showCheckedStrategy,
            treeCheckStrictly = props.treeCheckStrictly;
        var preValue = valueRef.value;
        valueRef.value = mergedMultiple.value ? newRawValues : newRawValues[0];

        if (onChange) {
          var eventValues = newRawValues;

          if (treeConduction.value && showCheckedStrategy !== 'SHOW_ALL') {
            var keyList = newRawValues.map(function (val) {
              var entity = getEntityByValue(val);
              return entity ? entity.key : val;
            });
            var formattedKeyList = (0, _strategyUtil.formatStrategyKeys)(keyList, showCheckedStrategy, conductKeyEntities.value);
            eventValues = formattedKeyList.map(function (key) {
              var entity = getEntityByKey(key);
              return entity ? entity.data.value : key;
            });
          }

          var _ref3 = extra || {
            triggerValue: undefined,
            selected: undefined
          },
              triggerValue = _ref3.triggerValue,
              selected = _ref3.selected;

          var returnValues = mergedLabelInValue.value ? (0, _valueUtil.getRawValueLabeled)(eventValues, preValue, getEntityByValue, getTreeNodeLabelProp) : eventValues; // We need fill half check back

          if (treeCheckStrictly) {
            var halfValues = rawHalfCheckedKeys.value.map(function (key) {
              var entity = getEntityByKey(key);
              return entity ? entity.data.value : key;
            }).filter(function (val) {
              return !eventValues.includes(val);
            });
            returnValues = [].concat((0, _toConsumableArray2.default)(returnValues), (0, _toConsumableArray2.default)((0, _valueUtil.getRawValueLabeled)(halfValues, preValue, getEntityByValue, getTreeNodeLabelProp)));
          }

          var additionalInfo = {
            // [Legacy] Always return as array contains label & value
            preValue: selectValues.value,
            triggerValue: triggerValue
          }; // [Legacy] Fill legacy data if user query.
          // This is expansive that we only fill when user query
          // https://github.com/react-component/tree-select/blob/fe33eb7c27830c9ac70cd1fdb1ebbe7bc679c16a/src/Select.jsx

          var showPosition = true;

          if (treeCheckStrictly || source === 'selection' && !selected) {
            showPosition = false;
          }

          (0, _legacyUtil.fillAdditionalInfo)(additionalInfo, triggerValue, newRawValues, mergedTreeData.value, showPosition);

          if (mergedCheckable.value) {
            additionalInfo.checked = selected;
          } else {
            additionalInfo.selected = selected;
          }

          onChange(mergedMultiple.value ? returnValues : returnValues[0], mergedLabelInValue.value ? null : eventValues.map(function (val) {
            var entity = getEntityByValue(val);
            return entity ? entity.data.title : null;
          }), additionalInfo);
        }
      };

      var onInternalSelect = function onInternalSelect(selectValue, option, source) {
        var _props$onSelect;

        var eventValue = mergedLabelInValue.value ? selectValue : selectValue;

        if (!mergedMultiple.value) {
          // Single mode always set value
          triggerChange([selectValue], {
            selected: true,
            triggerValue: selectValue
          }, source);
        } else {
          var newRawValues = (0, _valueUtil.addValue)(rawValues.value, selectValue); // Add keys if tree conduction

          if (treeConduction.value) {
            // Should keep missing values
            var _splitRawValues2 = splitRawValues(newRawValues),
                missingRawValues = _splitRawValues2.missingRawValues,
                existRawValues = _splitRawValues2.existRawValues;

            var keyList = existRawValues.map(function (val) {
              return getEntityByValue(val).key;
            });

            var _conductCheck2 = (0, _conductUtil.conductCheck)(keyList, true, conductKeyEntities.value),
                checkedKeys = _conductCheck2.checkedKeys;

            newRawValues = [].concat((0, _toConsumableArray2.default)(missingRawValues), (0, _toConsumableArray2.default)(checkedKeys.map(function (key) {
              return getEntityByKey(key).data.value;
            })));
          }

          triggerChange(newRawValues, {
            selected: true,
            triggerValue: selectValue
          }, source);
        }

        (_props$onSelect = props.onSelect) === null || _props$onSelect === void 0 ? void 0 : _props$onSelect.call(props, eventValue, option);
      };

      var onInternalDeselect = function onInternalDeselect(selectValue, option, source) {
        var _props$onDeselect;

        var eventValue = selectValue;
        var newRawValues = (0, _valueUtil.removeValue)(rawValues.value, selectValue); // Remove keys if tree conduction

        if (treeConduction.value) {
          var _splitRawValues3 = splitRawValues(newRawValues),
              missingRawValues = _splitRawValues3.missingRawValues,
              existRawValues = _splitRawValues3.existRawValues;

          var keyList = existRawValues.map(function (val) {
            return getEntityByValue(val).key;
          });

          var _conductCheck3 = (0, _conductUtil.conductCheck)(keyList, {
            checked: false,
            halfCheckedKeys: rawHalfCheckedKeys.value
          }, conductKeyEntities.value),
              checkedKeys = _conductCheck3.checkedKeys;

          newRawValues = [].concat((0, _toConsumableArray2.default)(missingRawValues), (0, _toConsumableArray2.default)(checkedKeys.map(function (key) {
            return getEntityByKey(key).data.value;
          })));
        }

        triggerChange(newRawValues, {
          selected: false,
          triggerValue: selectValue
        }, source);
        (_props$onDeselect = props.onDeselect) === null || _props$onDeselect === void 0 ? void 0 : _props$onDeselect.call(props, eventValue, option);
      };

      var onInternalClear = function onInternalClear() {
        triggerChange([], null, 'clear');
      }; // ========================= Open ==========================


      var onInternalDropdownVisibleChange = function onInternalDropdownVisibleChange(open) {
        if (props.onDropdownVisibleChange) {
          var legacyParam = {};
          Object.defineProperty(legacyParam, 'documentClickClose', {
            get: function get() {
              (0, _warning.warning)(false, 'Second param of `onDropdownVisibleChange` has been removed.');
              return false;
            }
          });
          props.onDropdownVisibleChange(open, legacyParam);
        }
      }; // ======================== Warning ========================


      if (process.env.NODE_ENV !== 'production') {
        (0, _warningPropsUtil.default)(props);
      }

      return function () {
        var treeNodeFilterProp = props.treeNodeFilterProp,
            dropdownPopupAlign = props.dropdownPopupAlign,
            filterTreeNode = props.filterTreeNode,
            treeDefaultExpandAll = props.treeDefaultExpandAll,
            treeExpandedKeys = props.treeExpandedKeys,
            treeDefaultExpandedKeys = props.treeDefaultExpandedKeys,
            onTreeExpand = props.onTreeExpand,
            treeIcon = props.treeIcon,
            treeMotion = props.treeMotion,
            showTreeIcon = props.showTreeIcon,
            switcherIcon = props.switcherIcon,
            treeLine = props.treeLine,
            loadData = props.loadData,
            treeLoadedKeys = props.treeLoadedKeys,
            onTreeLoad = props.onTreeLoad; // ======================== Render =========================
        // We pass some props into select props style

        var selectProps = {
          optionLabelProp: null,
          optionFilterProp: treeNodeFilterProp,
          dropdownAlign: dropdownPopupAlign,
          internalProps: {
            mark: _generator.INTERNAL_PROPS_MARK,
            onClear: onInternalClear,
            skipTriggerChange: true,
            skipTriggerSelect: true,
            onRawSelect: onInternalSelect,
            onRawDeselect: onInternalDeselect
          },
          filterOption: filterTreeNode
        };

        if (props.filterTreeNode === undefined) {
          delete selectProps.filterOption;
        }

        var selectContext = {
          checkable: mergedCheckable.value,
          loadData: loadData,
          treeLoadedKeys: treeLoadedKeys,
          onTreeLoad: onTreeLoad,
          checkedKeys: rawValues.value,
          halfCheckedKeys: rawHalfCheckedKeys.value,
          treeDefaultExpandAll: treeDefaultExpandAll,
          treeExpandedKeys: treeExpandedKeys,
          treeDefaultExpandedKeys: treeDefaultExpandedKeys,
          onTreeExpand: onTreeExpand,
          treeIcon: treeIcon,
          treeMotion: treeMotion,
          showTreeIcon: showTreeIcon,
          switcherIcon: switcherIcon,
          treeLine: treeLine,
          treeNodeFilterProp: treeNodeFilterProp,
          getEntityByKey: getEntityByKey,
          getEntityByValue: getEntityByValue,
          customCheckable: slots.treeCheckable,
          slots: slots
        };
        return (0, _vue.createVNode)(_Context.SelectContext, {
          "value": selectContext
        }, {
          default: function _default() {
            return [(0, _vue.createVNode)(RefSelect, (0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, attrs), {}, {
              "ref": selectRef,
              "mode": mergedMultiple.value ? 'multiple' : null
            }, props), selectProps), {}, {
              "value": selectValues.value,
              "labelInValue": true,
              "options": mergedTreeData.value,
              "onChange": null,
              "onSelect": null,
              "onDeselect": null,
              "onDropdownVisibleChange": onInternalDropdownVisibleChange
            }), slots)];
          }
        });
      };
    }
  });
}