import { isObject, isPropAbsent } from "../../../../utils/types.mjs";
import { hasOwn } from "../../../../utils/objects.mjs";
import { NOOP } from "../../../../utils/functions.mjs";
import { getNodeKey } from "./util.mjs";
import Node from "./node.mjs";
import { isNil } from "lodash-unified";
import { nextTick } from "vue";

//#region ../../packages/components/tree/src/model/tree-store.ts
var TreeStore = class {
	constructor(options) {
		this.lazy = false;
		this.checkStrictly = false;
		this.autoExpandParent = false;
		this.defaultExpandAll = false;
		this.checkDescendants = false;
		this.currentNode = null;
		this.currentNodeKey = null;
		for (const option in options) if (hasOwn(options, option)) this[option] = options[option];
		this.nodesMap = {};
	}
	initialize() {
		this.root = new Node({
			data: this.data,
			store: this
		});
		this.root.initialize();
		if (this.lazy && this.load) {
			const loadFn = this.load;
			loadFn(this.root, (data) => {
				this.root.doCreateChildren(data);
				this._initDefaultCheckedNodes();
			}, NOOP);
		} else this._initDefaultCheckedNodes();
	}
	filter(value) {
		const filterNodeMethod = this.filterNodeMethod;
		const lazy = this.lazy;
		const traverse = async function(node) {
			const childNodes = node.root ? node.root.childNodes : node.childNodes;
			for (const [index, child] of childNodes.entries()) {
				child.visible = !!filterNodeMethod?.call(child, value, child.data, child);
				if (index % 80 === 0 && index > 0) await nextTick();
				await traverse(child);
			}
			if (!node.visible && childNodes.length) {
				let allHidden = true;
				allHidden = !childNodes.some((child) => child.visible);
				if (node.root) node.root.visible = allHidden === false;
				else node.visible = allHidden === false;
			}
			if (!value) return;
			if (node.visible && !node.isLeaf) {
				if (!lazy || node.loaded) node.expand();
			}
		};
		traverse(this);
	}
	setData(newVal) {
		if (newVal !== this.root.data) {
			this.nodesMap = {};
			this.root.setData(newVal);
			this._initDefaultCheckedNodes();
			this.setCurrentNodeKey(this.currentNodeKey);
		} else this.root.updateChildren();
	}
	getNode(data) {
		if (data instanceof Node) return data;
		const key = isObject(data) ? getNodeKey(this.key, data) : data;
		return this.nodesMap[key] || null;
	}
	insertBefore(data, refData) {
		const refNode = this.getNode(refData);
		refNode.parent?.insertBefore({ data }, refNode);
	}
	insertAfter(data, refData) {
		const refNode = this.getNode(refData);
		refNode.parent?.insertAfter({ data }, refNode);
	}
	remove(data) {
		const node = this.getNode(data);
		if (node && node.parent) {
			if (node === this.currentNode) this.currentNode = null;
			node.parent.removeChild(node);
		}
	}
	append(data, parentData) {
		const parentNode = !isPropAbsent(parentData) ? this.getNode(parentData) : this.root;
		if (parentNode) parentNode.insertChild({ data });
	}
	_initDefaultCheckedNodes() {
		const defaultCheckedKeys = this.defaultCheckedKeys || [];
		const nodesMap = this.nodesMap;
		defaultCheckedKeys.forEach((checkedKey) => {
			const node = nodesMap[checkedKey];
			if (node) node.setChecked(true, !this.checkStrictly);
		});
	}
	_initDefaultCheckedNode(node) {
		const defaultCheckedKeys = this.defaultCheckedKeys || [];
		if (!isNil(node.key) && defaultCheckedKeys.includes(node.key)) node.setChecked(true, !this.checkStrictly);
	}
	setDefaultCheckedKey(newVal) {
		if (newVal !== this.defaultCheckedKeys) {
			this.defaultCheckedKeys = newVal;
			this._initDefaultCheckedNodes();
		}
	}
	registerNode(node) {
		const key = this.key;
		if (!node || !node.data) return;
		if (!key) this.nodesMap[node.id] = node;
		else {
			const nodeKey = node.key;
			if (!isNil(nodeKey)) this.nodesMap[nodeKey] = node;
		}
	}
	deregisterNode(node) {
		if (!this.key || !node || !node.data) return;
		node.childNodes.forEach((child) => {
			this.deregisterNode(child);
		});
		delete this.nodesMap[node.key];
	}
	getCheckedNodes(leafOnly = false, includeHalfChecked = false) {
		const checkedNodes = [];
		const traverse = function(node) {
			(node.root ? node.root.childNodes : node.childNodes).forEach((child) => {
				if ((child.checked || includeHalfChecked && child.indeterminate) && (!leafOnly || leafOnly && child.isLeaf)) checkedNodes.push(child.data);
				traverse(child);
			});
		};
		traverse(this);
		return checkedNodes;
	}
	getCheckedKeys(leafOnly = false) {
		return this.getCheckedNodes(leafOnly).map((data) => (data || {})[this.key]);
	}
	getHalfCheckedNodes() {
		const nodes = [];
		const traverse = function(node) {
			(node.root ? node.root.childNodes : node.childNodes).forEach((child) => {
				if (child.indeterminate) nodes.push(child.data);
				traverse(child);
			});
		};
		traverse(this);
		return nodes;
	}
	getHalfCheckedKeys() {
		return this.getHalfCheckedNodes().map((data) => (data || {})[this.key]);
	}
	_getAllNodes() {
		const allNodes = [];
		const nodesMap = this.nodesMap;
		for (const nodeKey in nodesMap) if (hasOwn(nodesMap, nodeKey)) allNodes.push(nodesMap[nodeKey]);
		return allNodes;
	}
	updateChildren(key, data) {
		const node = this.nodesMap[key];
		if (!node) return;
		const childNodes = node.childNodes;
		for (let i = childNodes.length - 1; i >= 0; i--) {
			const child = childNodes[i];
			this.remove(child.data);
		}
		for (let i = 0, j = data.length; i < j; i++) {
			const child = data[i];
			this.append(child, node.data);
		}
	}
	_setCheckedKeys(key, leafOnly = false, checkedKeys) {
		const allNodes = this._getAllNodes().sort((a, b) => a.level - b.level);
		const cache = Object.create(null);
		const keys = Object.keys(checkedKeys);
		allNodes.forEach((node) => node.setChecked(false, false));
		const cacheCheckedChild = (node) => {
			node.childNodes.forEach((child) => {
				cache[child.data[key]] = true;
				if (child.childNodes?.length) cacheCheckedChild(child);
			});
		};
		for (let i = 0, j = allNodes.length; i < j; i++) {
			const node = allNodes[i];
			const nodeKey = node.data[key].toString();
			if (!keys.includes(nodeKey)) {
				if (node.checked && !cache[nodeKey]) node.setChecked(false, false);
				continue;
			}
			if (node.childNodes.length) cacheCheckedChild(node);
			if (node.isLeaf || this.checkStrictly) {
				node.setChecked(true, false);
				continue;
			}
			node.setChecked(true, true);
			if (leafOnly) {
				node.setChecked(false, false, true);
				const traverse = function(node) {
					node.childNodes.forEach((child) => {
						if (!child.isLeaf) child.setChecked(false, false, true);
						traverse(child);
					});
					node.reInitChecked();
				};
				traverse(node);
			}
		}
	}
	setCheckedNodes(array, leafOnly = false) {
		const key = this.key;
		const checkedKeys = {};
		array.forEach((item) => {
			checkedKeys[(item || {})[key]] = true;
		});
		this._setCheckedKeys(key, leafOnly, checkedKeys);
	}
	setCheckedKeys(keys, leafOnly = false) {
		this.defaultCheckedKeys = keys;
		const key = this.key;
		const checkedKeys = {};
		keys.forEach((key) => {
			checkedKeys[key] = true;
		});
		this._setCheckedKeys(key, leafOnly, checkedKeys);
	}
	setDefaultExpandedKeys(keys) {
		keys = keys || [];
		this.defaultExpandedKeys = keys;
		keys.forEach((key) => {
			const node = this.getNode(key);
			if (node) node.expand(null, this.autoExpandParent);
		});
	}
	setChecked(data, checked, deep) {
		const node = this.getNode(data);
		if (node) node.setChecked(!!checked, deep);
	}
	getCurrentNode() {
		return this.currentNode;
	}
	setCurrentNode(currentNode) {
		const prevCurrentNode = this.currentNode;
		if (prevCurrentNode) prevCurrentNode.isCurrent = false;
		this.currentNode = currentNode;
		this.currentNode.isCurrent = true;
	}
	setUserCurrentNode(node, shouldAutoExpandParent = true) {
		const key = node[this.key];
		const currNode = this.nodesMap[key];
		this.setCurrentNode(currNode);
		if (shouldAutoExpandParent && this.currentNode && this.currentNode.level > 1) this.currentNode.parent?.expand(null, true);
	}
	setCurrentNodeKey(key, shouldAutoExpandParent = true) {
		this.currentNodeKey = key;
		if (isPropAbsent(key)) {
			this.currentNode && (this.currentNode.isCurrent = false);
			this.currentNode = null;
			return;
		}
		const node = this.getNode(key);
		if (node) {
			this.setCurrentNode(node);
			if (shouldAutoExpandParent && this.currentNode && this.currentNode.level > 1) this.currentNode.parent?.expand(null, true);
		}
	}
};

//#endregion
export { TreeStore as default };
//# sourceMappingURL=tree-store.mjs.map