11cb0ef41Sopenharmony_ciimport { GNode, MINIMUM_EDGE_SEPARATION } from "./node";
21cb0ef41Sopenharmony_ciimport { Edge } from "./edge";
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciexport class Graph {
51cb0ef41Sopenharmony_ci  nodeMap: Array<GNode>;
61cb0ef41Sopenharmony_ci  minGraphX: number;
71cb0ef41Sopenharmony_ci  maxGraphX: number;
81cb0ef41Sopenharmony_ci  minGraphY: number;
91cb0ef41Sopenharmony_ci  maxGraphY: number;
101cb0ef41Sopenharmony_ci  maxGraphNodeX: number;
111cb0ef41Sopenharmony_ci  maxBackEdgeNumber: number;
121cb0ef41Sopenharmony_ci  width: number;
131cb0ef41Sopenharmony_ci  height: number;
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci  constructor(data: any) {
161cb0ef41Sopenharmony_ci    this.nodeMap = [];
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci    this.minGraphX = 0;
191cb0ef41Sopenharmony_ci    this.maxGraphX = 1;
201cb0ef41Sopenharmony_ci    this.minGraphY = 0;
211cb0ef41Sopenharmony_ci    this.maxGraphY = 1;
221cb0ef41Sopenharmony_ci    this.width = 1;
231cb0ef41Sopenharmony_ci    this.height = 1;
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci    data.nodes.forEach((jsonNode: any) => {
261cb0ef41Sopenharmony_ci      this.nodeMap[jsonNode.id] = new GNode(jsonNode.nodeLabel);
271cb0ef41Sopenharmony_ci    });
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci    data.edges.forEach((e: any) => {
301cb0ef41Sopenharmony_ci      const t = this.nodeMap[e.target];
311cb0ef41Sopenharmony_ci      const s = this.nodeMap[e.source];
321cb0ef41Sopenharmony_ci      const newEdge = new Edge(t, e.index, s, e.type);
331cb0ef41Sopenharmony_ci      t.inputs.push(newEdge);
341cb0ef41Sopenharmony_ci      s.outputs.push(newEdge);
351cb0ef41Sopenharmony_ci      if (e.type == 'control') {
361cb0ef41Sopenharmony_ci        // Every source of a control edge is a CFG node.
371cb0ef41Sopenharmony_ci        s.cfg = true;
381cb0ef41Sopenharmony_ci      }
391cb0ef41Sopenharmony_ci    });
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci  }
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  *nodes(p = (n: GNode) => true) {
441cb0ef41Sopenharmony_ci    for (const node of this.nodeMap) {
451cb0ef41Sopenharmony_ci      if (!node || !p(node)) continue;
461cb0ef41Sopenharmony_ci      yield node;
471cb0ef41Sopenharmony_ci    }
481cb0ef41Sopenharmony_ci  }
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  *filteredEdges(p: (e: Edge) => boolean) {
511cb0ef41Sopenharmony_ci    for (const node of this.nodes()) {
521cb0ef41Sopenharmony_ci      for (const edge of node.inputs) {
531cb0ef41Sopenharmony_ci        if (p(edge)) yield edge;
541cb0ef41Sopenharmony_ci      }
551cb0ef41Sopenharmony_ci    }
561cb0ef41Sopenharmony_ci  }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  forEachEdge(p: (e: Edge) => void) {
591cb0ef41Sopenharmony_ci    for (const node of this.nodeMap) {
601cb0ef41Sopenharmony_ci      if (!node) continue;
611cb0ef41Sopenharmony_ci      for (const edge of node.inputs) {
621cb0ef41Sopenharmony_ci        p(edge);
631cb0ef41Sopenharmony_ci      }
641cb0ef41Sopenharmony_ci    }
651cb0ef41Sopenharmony_ci  }
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  redetermineGraphBoundingBox(showTypes: boolean): [[number, number], [number, number]] {
681cb0ef41Sopenharmony_ci    this.minGraphX = 0;
691cb0ef41Sopenharmony_ci    this.maxGraphNodeX = 1;
701cb0ef41Sopenharmony_ci    this.maxGraphX = undefined;  // see below
711cb0ef41Sopenharmony_ci    this.minGraphY = 0;
721cb0ef41Sopenharmony_ci    this.maxGraphY = 1;
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci    for (const node of this.nodes()) {
751cb0ef41Sopenharmony_ci      if (!node.visible) {
761cb0ef41Sopenharmony_ci        continue;
771cb0ef41Sopenharmony_ci      }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci      if (node.x < this.minGraphX) {
801cb0ef41Sopenharmony_ci        this.minGraphX = node.x;
811cb0ef41Sopenharmony_ci      }
821cb0ef41Sopenharmony_ci      if ((node.x + node.getTotalNodeWidth()) > this.maxGraphNodeX) {
831cb0ef41Sopenharmony_ci        this.maxGraphNodeX = node.x + node.getTotalNodeWidth();
841cb0ef41Sopenharmony_ci      }
851cb0ef41Sopenharmony_ci      if ((node.y - 50) < this.minGraphY) {
861cb0ef41Sopenharmony_ci        this.minGraphY = node.y - 50;
871cb0ef41Sopenharmony_ci      }
881cb0ef41Sopenharmony_ci      if ((node.y + node.getNodeHeight(showTypes) + 50) > this.maxGraphY) {
891cb0ef41Sopenharmony_ci        this.maxGraphY = node.y + node.getNodeHeight(showTypes) + 50;
901cb0ef41Sopenharmony_ci      }
911cb0ef41Sopenharmony_ci    }
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci    this.maxGraphX = this.maxGraphNodeX +
941cb0ef41Sopenharmony_ci      this.maxBackEdgeNumber * MINIMUM_EDGE_SEPARATION;
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci    this.width = this.maxGraphX - this.minGraphX;
971cb0ef41Sopenharmony_ci    this.height = this.maxGraphY - this.minGraphY;
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci    const extent: [[number, number], [number, number]] = [
1001cb0ef41Sopenharmony_ci      [this.minGraphX - this.width / 2, this.minGraphY - this.height / 2],
1011cb0ef41Sopenharmony_ci      [this.maxGraphX + this.width / 2, this.maxGraphY + this.height / 2]
1021cb0ef41Sopenharmony_ci    ];
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    return extent;
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci}
108