"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
class Node {
  constructor(data) {
    this.incoming = /* @__PURE__ */ new Map();
    this.outgoing = /* @__PURE__ */ new Map();
    this.data = data;
  }
}
class Graph {
  constructor(_hashFn) {
    this._hashFn = _hashFn;
    this._nodes = /* @__PURE__ */ new Map();
  }
  roots() {
    const ret = [];
    for (let node of this._nodes.values()) {
      if (node.outgoing.size === 0) {
        ret.push(node);
      }
    }
    return ret;
  }
  insertEdge(from, to) {
    const fromNode = this.lookupOrInsertNode(from);
    const toNode = this.lookupOrInsertNode(to);
    fromNode.outgoing.set(this._hashFn(to), toNode);
    toNode.incoming.set(this._hashFn(from), fromNode);
  }
  removeNode(data) {
    const key = this._hashFn(data);
    this._nodes.delete(key);
    for (let node of this._nodes.values()) {
      node.outgoing.delete(key);
      node.incoming.delete(key);
    }
  }
  lookupOrInsertNode(data) {
    const key = this._hashFn(data);
    let node = this._nodes.get(key);
    if (!node) {
      node = new Node(data);
      this._nodes.set(key, node);
    }
    return node;
  }
  isEmpty() {
    return this._nodes.size === 0;
  }
  toString() {
    let data = [];
    for (let [key, value] of this._nodes) {
      data.push(`${key}, (incoming)[${[...value.incoming.keys()].join(", ")}], (outgoing)[${[...value.outgoing.keys()].join(",")}]`);
    }
    return data.join("\n");
  }
  /**
   * This is brute force and slow and **only** be used
   * to trouble shoot.
   */
  findCycleSlow() {
    for (let [id, node] of this._nodes) {
      const seen = /* @__PURE__ */ new Set([id]);
      const res = this._findCycle(node, seen);
      if (res) {
        return res;
      }
    }
    return void 0;
  }
  _findCycle(node, seen) {
    for (let [id, outgoing] of node.outgoing) {
      if (seen.has(id)) {
        return [...seen, id].join(" -> ");
      }
      seen.add(id);
      const value = this._findCycle(outgoing, seen);
      if (value) {
        return value;
      }
      seen.delete(id);
    }
    return void 0;
  }
}
exports.Graph = Graph;
exports.Node = Node;
