text: /* eslint-disable no-unused-vars */
  import VVNode from "../../Model/Node"
  import VVEdge from "../../Model/Edge"
  /**
   * Takes a graph as input and returns nodes sorted by level from first source to last target.
   * Also returns a second array containing "fake" nodes that connect the different layers.
   * @param {VVNode[]} nodes
   * @param {VVEdge[]} edges
   * @returns {{hierarchy: VVNode[][], fakeNodesHierarchy: {id: string}[][] fakeEdges: {sourceNode: string, targetNode: string}[]}} - Level array of nodes
   */
  export const determineLevels = (nodes, edges) => {
  	const incomingEdges = new Map(nodes.map(node => [node.id, edges.filter(edge => edge.targetNode === node.id)]))
  	const outgoingEdges = new Map(nodes.map(node => [node.id, edges.filter(edge => edge.sourceNode === node.id)]))
  
  	//Compute y coordinate for a node. This is the same as "level", but makes the variables more readable.
  	//Islands are reserved on level 0, and sources start at level 1. Generally this results in a more readable layout.
  	const sources = nodes.filter(node => !incomingEdges.get(node.id).length && outgoingEdges.get(node.id).length)
  	const islands = nodes.filter(node => !incomingEdges.get(node.id).length && !outgoingEdges.get(node.id).length)
  	const yCoordinates = new Map([...islands.map(node => [node.id, 0]), ...sources.map(node => [node.id, 1])])
  	const getYCoordinate = nodeID => {
  		if (!yCoordinates.has(nodeID)) {
  			const maxLevelSource = Math.max(...incomingEdges.get(nodeID).map(edge => getYCoordinate(edge.sourceNode)))
  			yCoordinates.set(nodeID, maxLevelSource + 1)
  		}
  		return yCoordinates.get(nodeID)
  	}
  
  	//Assign all nodes to levels
  	const levels = new Map()
  	for (let i = 0; i < nodes.length; i++) {
  		const level = getYCoordinate(nodes[i].id)
  		if (!levels.has(level)) {
  			levels.set(level, [])
  		}
  		levels.get(level).push(nodes[i])
  	}
  	const nodesByLevel = Array.from(levels.keys())
  		.sort((a, b) => a - b)
  		.map(key => levels.get(key))
  
  	//Compute fake nodes
  	const fakeNodesByLevel = nodesByLevel.map(() => [])
  	const fakeEdgeArray = []
  	const createdNodes = new Set()
  	for (let i = 0; i < nodes.length; i++) {
  		const nodeID = nodes[i].id
  		const nodeYLevel = getYCoordinate(nodeID)
  		const sourceNodes = incomingEdges.get(nodeID).map(edge => edge.sourceNode)
  		for (let j = 0; j < sourceNodes.length; j++) {
  			const sourceNodeID = sourceNodes[j]
  			const sourceYLevel = getYCoordinate(sourceNodeID)
  			const diff = nodeYLevel - sourceYLevel
  			if (diff > 1) {
  				let nextSourceNodeID = sourceNodeID
  				for (let z = sourceYLevel + 1; z < nodeYLevel; z++) {
  					const fakeNodeID = "__FAKE_NODE__" + z + nodeID + nextSourceNodeID
  					if (!createdNodes.has(fakeNodeID)) {
  						//There can be nodes with multiple connections between each other. These should result in a single fake vertex.
  						createdNodes.add(fakeNodeID)
  						const fakeNode = { id: fakeNodeID }
  						fakeNodesByLevel[z - 1].push(fakeNode) //We need -1 because islands are reserved for level 0
  					}
  					fakeEdgeArray.push({ sourceNode: nextSourceNodeID, targetNode: fakeNodeID })
  					nextSourceNodeID = fakeNodeID
  				}
  				fakeEdgeArray.push({ sourceNode: nextSourceNodeID, targetNode: nodeID })
  			}
  		}
  	}
  
  	return {
  		hierarchy: nodesByLevel,
  		fakeNodesHierarchy: fakeNodesByLevel,
  		fakeEdges: fakeEdgeArray
  	}
  }
  