"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const indexTreeModel = require("./indexTreeModel.js");
const tree = require("./tree.js");
const iterator = require("../../../common/iterator.js");
class ObjectTreeModel {
  constructor(user, list, options = {}) {
    this.user = user;
    this.rootRef = null;
    this.nodes = /* @__PURE__ */ new Map();
    this.nodesByIdentity = /* @__PURE__ */ new Map();
    this.model = new indexTreeModel.IndexTreeModel(user, list, null, options);
    this.onDidSplice = this.model.onDidSplice;
    this.onDidChangeCollapseState = this.model.onDidChangeCollapseState;
    this.onDidChangeRenderNodeCount = this.model.onDidChangeRenderNodeCount;
    if (options.sorter) {
      this.sorter = {
        compare(a, b) {
          return options.sorter.compare(a.element, b.element);
        }
      };
    }
    this.identityProvider = options.identityProvider;
  }
  setChildren(element, children = iterator.Iterable.empty(), options = {}) {
    const location = this.getElementLocation(element);
    this._setChildren(location, this.preserveCollapseState(children), options);
  }
  _setChildren(location, children = iterator.Iterable.empty(), options) {
    const insertedElements = /* @__PURE__ */ new Set();
    const insertedElementIds = /* @__PURE__ */ new Set();
    const onDidCreateNode = (node) => {
      var _a;
      if (node.element === null) {
        return;
      }
      const tnode = node;
      insertedElements.add(tnode.element);
      this.nodes.set(tnode.element, tnode);
      if (this.identityProvider) {
        const id = this.identityProvider.getId(tnode.element).toString();
        insertedElementIds.add(id);
        this.nodesByIdentity.set(id, tnode);
      }
      (_a = options.onDidCreateNode) === null || _a === void 0 ? void 0 : _a.call(options, tnode);
    };
    const onDidDeleteNode = (node) => {
      var _a;
      if (node.element === null) {
        return;
      }
      const tnode = node;
      if (!insertedElements.has(tnode.element)) {
        this.nodes.delete(tnode.element);
      }
      if (this.identityProvider) {
        const id = this.identityProvider.getId(tnode.element).toString();
        if (!insertedElementIds.has(id)) {
          this.nodesByIdentity.delete(id);
        }
      }
      (_a = options.onDidDeleteNode) === null || _a === void 0 ? void 0 : _a.call(options, tnode);
    };
    this.model.splice([...location, 0], Number.MAX_VALUE, children, Object.assign(Object.assign({}, options), { onDidCreateNode, onDidDeleteNode }));
  }
  preserveCollapseState(elements = iterator.Iterable.empty()) {
    if (this.sorter) {
      elements = [...elements].sort(this.sorter.compare.bind(this.sorter));
    }
    return iterator.Iterable.map(elements, (treeElement) => {
      let node = this.nodes.get(treeElement.element);
      if (!node && this.identityProvider) {
        const id = this.identityProvider.getId(treeElement.element).toString();
        node = this.nodesByIdentity.get(id);
      }
      if (!node) {
        return Object.assign(Object.assign({}, treeElement), { children: this.preserveCollapseState(treeElement.children) });
      }
      const collapsible = typeof treeElement.collapsible === "boolean" ? treeElement.collapsible : node.collapsible;
      const collapsed = typeof treeElement.collapsed !== "undefined" ? treeElement.collapsed : node.collapsed;
      return Object.assign(Object.assign({}, treeElement), {
        collapsible,
        collapsed,
        children: this.preserveCollapseState(treeElement.children)
      });
    });
  }
  rerender(element) {
    const location = this.getElementLocation(element);
    this.model.rerender(location);
  }
  getFirstElementChild(ref = null) {
    const location = this.getElementLocation(ref);
    return this.model.getFirstElementChild(location);
  }
  has(element) {
    return this.nodes.has(element);
  }
  getListIndex(element) {
    const location = this.getElementLocation(element);
    return this.model.getListIndex(location);
  }
  getListRenderCount(element) {
    const location = this.getElementLocation(element);
    return this.model.getListRenderCount(location);
  }
  isCollapsible(element) {
    const location = this.getElementLocation(element);
    return this.model.isCollapsible(location);
  }
  setCollapsible(element, collapsible) {
    const location = this.getElementLocation(element);
    return this.model.setCollapsible(location, collapsible);
  }
  isCollapsed(element) {
    const location = this.getElementLocation(element);
    return this.model.isCollapsed(location);
  }
  setCollapsed(element, collapsed, recursive) {
    const location = this.getElementLocation(element);
    return this.model.setCollapsed(location, collapsed, recursive);
  }
  expandTo(element) {
    const location = this.getElementLocation(element);
    this.model.expandTo(location);
  }
  refilter() {
    this.model.refilter();
  }
  getNode(element = null) {
    if (element === null) {
      return this.model.getNode(this.model.rootRef);
    }
    const node = this.nodes.get(element);
    if (!node) {
      throw new tree.TreeError(this.user, `Tree element not found: ${element}`);
    }
    return node;
  }
  getNodeLocation(node) {
    return node.element;
  }
  getParentNodeLocation(element) {
    if (element === null) {
      throw new tree.TreeError(this.user, `Invalid getParentNodeLocation call`);
    }
    const node = this.nodes.get(element);
    if (!node) {
      throw new tree.TreeError(this.user, `Tree element not found: ${element}`);
    }
    const location = this.model.getNodeLocation(node);
    const parentLocation = this.model.getParentNodeLocation(location);
    const parent = this.model.getNode(parentLocation);
    return parent.element;
  }
  getElementLocation(element) {
    if (element === null) {
      return [];
    }
    const node = this.nodes.get(element);
    if (!node) {
      throw new tree.TreeError(this.user, `Tree element not found: ${element}`);
    }
    return this.model.getNodeLocation(node);
  }
}
exports.ObjectTreeModel = ObjectTreeModel;
