"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get keyExists () {
        return keyExists;
    },
    get treePathReducer () {
        return treePathReducer;
    }
});
var _utils = require("../../../../utils");
function _type_of(obj) {
    "@swc/helpers - typeof";
    return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
}
var keyExists = function keyExists(obj, path) {
    if ((typeof obj === "undefined" ? "undefined" : _type_of(obj)) !== 'object' || obj === null || !Array.isArray(path)) {
        return false;
    }
    var current = obj;
    for(var i = 0; i < path.length; i++){
        var key = path[i];
        if (current === null || (typeof current === "undefined" ? "undefined" : _type_of(current)) !== 'object' || !(key in current)) {
            return false;
        }
        current = current[key];
    }
    return true;
};
function createObjectAtPath(obj, path) {
    if ((typeof obj === "undefined" ? "undefined" : _type_of(obj)) !== 'object' || obj === null) {
        return;
    }
    var current = obj;
    for(var i = 0; i < path.length; i++){
        var key = path[i];
        if (i === path.length - 1) {
            current[key] = {};
            break;
        }
        if (current[key] === undefined || current[key] === null) {
            current[key] = {};
        }
        current = current[key];
    }
    return obj;
}
function removeObjectAtPath(obj, path) {
    if (path.length === 0) {
        return obj;
    }
    var current = obj;
    for(var i = 0; i < path.length; i++){
        var key = path[i];
        if (current === null || (typeof current === "undefined" ? "undefined" : _type_of(current)) !== 'object' || !(key in current)) {
            return obj;
        }
        if (i === path.length - 1) {
            delete current[key];
            break;
        }
        current = current[key];
    }
    return obj;
}
/**
 * Утилита, которая получает на вход список отфильтрованных элементов и
 * callback, с помощью которого эти элементы были отфильтрованы.
 * Возвращает TreePathState, т.е. список раскрытых групп.
 * По умолчанию группа не раскрывается, если в ней не было найдено ни одного элемента.
 * Но т.к. поиск может осуществляться как по элементам, так и по группам,
 * то может возникнуть ситуация, когда будет найдена как группа с определенным названием,
 * так и элемент с таким же названием внутри нее, и в таком случае мы должны частично раскрыть группу,
 * вплоть то найденного элемента.
 * Если найдена только группа, без элементов внутри нее, то саму эту группу
 * раскрывать не нужно. Нужно раскрыть только родителя этой группы.
 */ function generateNestedTreePathFromFilteredItems(filteredItems, filterCb, textValue) {
    var result = {};
    function traverse(items, currentPath) {
        var hasFoundItems = false;
        var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
        try {
            for(var _iterator = items[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
                var item = _step.value;
                var isFound = filterCb(item, textValue);
                if (item.items && item.items.length > 0) {
                    // Обрабатываем детей
                    var childPath = {};
                    var foundInChildren = traverse(item.items, childPath);
                    if (foundInChildren) {
                        // Если в детях найдены элементы - добавляем путь
                        currentPath[item.value] = childPath;
                        hasFoundItems = true;
                    }
                    // Если сама группа найдена, но в детях ничего нет - НЕ добавляем путь
                    // Просто отмечаем что что-то найдено на этом уровне
                    if (isFound && !foundInChildren) {
                        hasFoundItems = true;
                    }
                } else if (isFound) {
                    // Для конечного элемента не добавляем путь в currentPath,
                    // но отмечаем что на этом уровне есть найденные элементы
                    hasFoundItems = true;
                }
            }
        } catch (err) {
            _didIteratorError = true;
            _iteratorError = err;
        } finally{
            try {
                if (!_iteratorNormalCompletion && _iterator.return != null) {
                    _iterator.return();
                }
            } finally{
                if (_didIteratorError) {
                    throw _iteratorError;
                }
            }
        }
        return hasFoundItems;
    }
    traverse(filteredItems, result);
    return result;
}
function treePathReducer(state, action) {
    switch(action.type){
        case 'reset':
            {
                return {};
            }
        case 'toggled_level':
            {
                var stateCopy = (0, _utils.deepCopy)(state);
                var isTargetLevelOpened = keyExists(stateCopy, action.value);
                if (isTargetLevelOpened) {
                    // нужно закрыть текущий уровень
                    removeObjectAtPath(stateCopy, action.value);
                } else {
                    // нужно открыть требуемый уровень
                    createObjectAtPath(stateCopy, action.value);
                }
                return stateCopy;
            }
        case 'expand_by_key':
            {
                var _action_value = action.value, filteredItems = _action_value.filteredItems, filterCb = _action_value.filterCb, textValue = _action_value.textValue;
                return generateNestedTreePathFromFilteredItems(filteredItems, filterCb, textValue);
            }
        case 'open_level':
            {
                var stateCopy1 = (0, _utils.deepCopy)(state);
                createObjectAtPath(stateCopy1, action.value);
                return stateCopy1;
            }
        case 'close_level':
            {
                var stateCopy2 = (0, _utils.deepCopy)(state);
                removeObjectAtPath(stateCopy2, action.value);
                return stateCopy2;
            }
        default:
            {
                return state;
            }
    }
}
