export class SimpleGraph {
  constructor({ directed = true } = {}) {
    this.directed = directed;
    this.out = new Map();
    this.in = new Map();
  }

  _getSet(map, node) {
    let set = map.get(node);
    if (!set) {
      set = new Set();
      map.set(node, set);
    }
    return set;
  }

  addEdge(src, dst) {
    this._getSet(this.out, src).add(dst);
    this._getSet(this.in, dst).add(src);
    if (!this.directed) {
      this._getSet(this.out, dst).add(src);
      this._getSet(this.in, src).add(dst);
    }
  }

  removeEdge(src, dst) {
    const outSet = this.out.get(src);
    if (outSet) {
      outSet.delete(dst);
      if (outSet.size === 0) this.out.delete(src);
    }
    const inSet = this.in.get(dst);
    if (inSet) {
      inSet.delete(src);
      if (inSet.size === 0) this.in.delete(dst);
    }
    if (!this.directed) {
      const outSetRev = this.out.get(dst);
      if (outSetRev) {
        outSetRev.delete(src);
        if (outSetRev.size === 0) this.out.delete(dst);
      }
      const inSetRev = this.in.get(src);
      if (inSetRev) {
        inSetRev.delete(dst);
        if (inSetRev.size === 0) this.in.delete(src);
      }
    }
  }

  neighbors(node, reverse = false) {
    const set = reverse ? this.in.get(node) : this.out.get(node);
    return set ? Array.from(set) : [];
  }

  degree(node, reverse = false) {
    const set = reverse ? this.in.get(node) : this.out.get(node);
    return set ? set.size : 0;
  }
}
