import {ObjectsManagerNode} from "../../nodes/manager/ObjectsManager";
import {CoreString} from "../../../core/String";
export class NodesController {
  constructor(scene) {
    this.scene = scene;
    this._node_context_signatures = {};
    this._instanciated_nodes_by_context_and_type = {};
  }
  init() {
    this._root = new ObjectsManagerNode(this.scene);
    this._root.initialize_base_and_node();
    this._root.init_default_scene();
  }
  root() {
    return this._root;
  }
  _traverseNode(parent, callback) {
    const nodes = parent.children();
    if (!nodes || nodes.length == 0) {
      return;
    }
    for (let node of nodes) {
      callback(node);
      if (node.childrenController) {
        this._traverseNode(node, callback);
      }
    }
  }
  clear() {
    const children = this.root().children();
    for (let child of children) {
      this.root().childrenController?.removeNode(child);
    }
  }
  node(path) {
    if (path === "/") {
      return this.root();
    } else {
      return this.root().node(path);
    }
  }
  allNodes() {
    let nodes = [this.root()];
    let current_parents = [this.root()];
    let cmptr = 0;
    while (current_parents.length > 0 && cmptr < 10) {
      const children = current_parents.map((current_parent) => {
        if (current_parent.childrenAllowed()) {
          return current_parent.children();
        } else {
          return [];
        }
      }).flat();
      nodes = nodes.concat(children);
      current_parents = children;
      cmptr += 1;
    }
    return nodes.flat();
  }
  nodesFromMask(mask) {
    const nodes = this.allNodes();
    const matching_nodes = [];
    for (let node of nodes) {
      const path = node.fullPath();
      if (CoreString.matchMask(path, mask)) {
        matching_nodes.push(node);
      }
    }
    return matching_nodes;
  }
  reset_node_context_signatures() {
    this._node_context_signatures = {};
  }
  register_node_context_signature(node) {
    if (node.childrenAllowed() && node.childrenController) {
      this._node_context_signatures[node.childrenController.node_context_signature()] = true;
    }
  }
  node_context_signatures() {
    return Object.keys(this._node_context_signatures).sort().map((s) => s.toLowerCase());
  }
  addToInstanciatedNode(node) {
    const context = node.nodeContext();
    const node_type = node.type();
    this._instanciated_nodes_by_context_and_type[context] = this._instanciated_nodes_by_context_and_type[context] || {};
    this._instanciated_nodes_by_context_and_type[context][node_type] = this._instanciated_nodes_by_context_and_type[context][node_type] || {};
    this._instanciated_nodes_by_context_and_type[context][node_type][node.graphNodeId()] = node;
  }
  removeFromInstanciatedNode(node) {
    const context = node.nodeContext();
    const node_type = node.type();
    delete this._instanciated_nodes_by_context_and_type[context][node_type][node.graphNodeId()];
  }
  nodesByType(type) {
    const list = [];
    this._traverseNode(this.scene.root(), (node) => {
      if (node.type() == type) {
        list.push(node);
      }
    });
    return list;
  }
  nodesByContextAndType(context, node_type) {
    const nodes = [];
    const nodes_for_context = this._instanciated_nodes_by_context_and_type[context];
    if (nodes_for_context) {
      const nodes_by_ids = nodes_for_context[node_type];
      if (nodes_by_ids) {
        for (let id of Object.keys(nodes_by_ids)) {
          nodes.push(nodes_by_ids[id]);
        }
      }
    }
    return nodes;
  }
}
