createLayoutInfo = function createLayoutInfo(cy, layout, options) {
  // Shortcut
  var edges = options.eles.edges();
  var nodes = options.eles.nodes();
  var layoutInfo = {
    isCompound: cy.hasCompoundNodes(),
    layoutNodes: [],
    idToIndex: {},
    nodeSize: nodes.size(),
    graphSet: [],
    indexToGraph: [],
    layoutEdges: [],
    edgeSize: edges.size(),
    temperature: options.initialTemp,
    clientWidth: cy.width(),
    clientHeight: cy.width(),
    boundingBox: makeBoundingBox(options.boundingBox ? options.boundingBox : {
      x1: 0,
      y1: 0,
      w: cy.width(),
      h: cy.height()
    })
  };
  var components = options.eles.components();
  var id2cmptId = {};

  for (var i = 0; i < components.length; i++) {
    var component = components[i];

    for (var j = 0; j < component.length; j++) {
      var node = component[j];
      id2cmptId[node.id()] = i;
    }
  } // Iterate over all nodes, creating layout nodes


  for (var i = 0; i < layoutInfo.nodeSize; i++) {
    var n = nodes[i];
    var nbb = n.layoutDimensions(options);
    var tempNode = {};
    tempNode.isLocked = n.locked();
    tempNode.id = n.data('id');
    tempNode.parentId = n.data('parent');
    tempNode.cmptId = id2cmptId[n.id()];
    tempNode.children = [];
    tempNode.positionX = n.position('x');
    tempNode.positionY = n.position('y');
    tempNode.offsetX = 0;
    tempNode.offsetY = 0;
    tempNode.height = nbb.w;
    tempNode.width = nbb.h;
    tempNode.maxX = tempNode.positionX + tempNode.width / 2;
    tempNode.minX = tempNode.positionX - tempNode.width / 2;
    tempNode.maxY = tempNode.positionY + tempNode.height / 2;
    tempNode.minY = tempNode.positionY - tempNode.height / 2;
    tempNode.padLeft = parseFloat(n.style('padding'));
    tempNode.padRight = parseFloat(n.style('padding'));
    tempNode.padTop = parseFloat(n.style('padding'));
    tempNode.padBottom = parseFloat(n.style('padding')); // forces

    tempNode.nodeRepulsion = fn(options.nodeRepulsion) ? options.nodeRepulsion(n) : options.nodeRepulsion; // Add new node

    layoutInfo.layoutNodes.push(tempNode); // Add entry to id-index map

    layoutInfo.idToIndex[tempNode.id] = i;
  } // Inline implementation of a queue, used for traversing the graph in BFS order


  var queue = [];
  var start = 0; // Points to the start the queue

  var end = -1; // Points to the end of the queue

  var tempGraph = []; // Second pass to add child information and
  // initialize queue for hierarchical traversal

  for (var i = 0; i < layoutInfo.nodeSize; i++) {
    var n = layoutInfo.layoutNodes[i];
    var p_id = n.parentId; // Check if node n has a parent node

    if (null != p_id) {
      // Add node Id to parent's list of children
      layoutInfo.layoutNodes[layoutInfo.idToIndex[p_id]].children.push(n.id);
    } else {
      // If a node doesn't have a parent, then it's in the root graph
      queue[++end] = n.id;
      tempGraph.push(n.id);
    }
  } // Add root graph to graphSet


  layoutInfo.graphSet.push(tempGraph); // Traverse the graph, level by level,

  while (start <= end) {
    // Get the node to visit and remove it from queue
    var node_id = queue[start++];
    var node_ix = layoutInfo.idToIndex[node_id];
    var node = layoutInfo.layoutNodes[node_ix];
    var children = node.children;

    if (children.length > 0) {
      // Add children nodes as a new graph to graph set
      layoutInfo.graphSet.push(children); // Add children to que queue to be visited

      for (var i = 0; i < children.length; i++) {
        queue[++end] = children[i];
      }
    }
  } // Create indexToGraph map


  for (var i = 0; i < layoutInfo.graphSet.length; i++) {
    var graph = layoutInfo.graphSet[i];

    for (var j = 0; j < graph.length; j++) {
      var index = layoutInfo.idToIndex[graph[j]];
      layoutInfo.indexToGraph[index] = i;
    }
  } // Iterate over all edges, creating Layout Edges


  for (var i = 0; i < layoutInfo.edgeSize; i++) {
    var e = edges[i];
    var tempEdge = {};
    tempEdge.id = e.data('id');
    tempEdge.sourceId = e.data('source');
    tempEdge.targetId = e.data('target'); // Compute ideal length

    var idealLength = fn(options.idealEdgeLength) ? options.idealEdgeLength(e) : options.idealEdgeLength;
    var elasticity = fn(options.edgeElasticity) ? options.edgeElasticity(e) : options.edgeElasticity; // Check if it's an inter graph edge

    var sourceIx = layoutInfo.idToIndex[tempEdge.sourceId];
    var targetIx = layoutInfo.idToIndex[tempEdge.targetId];
    var sourceGraph = layoutInfo.indexToGraph[sourceIx];
    var targetGraph = layoutInfo.indexToGraph[targetIx];

    if (sourceGraph != targetGraph) {
      // Find lowest common graph ancestor
      var lca = findLCA(tempEdge.sourceId, tempEdge.targetId, layoutInfo); // Compute sum of node depths, relative to lca graph

      var lcaGraph = layoutInfo.graphSet[lca];
      var depth = 0; // Source depth

      var tempNode = layoutInfo.layoutNodes[sourceIx];

      while (-1 === lcaGraph.indexOf(tempNode.id)) {
        tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]];
        depth++;
      } // Target depth


      tempNode = layoutInfo.layoutNodes[targetIx];

      while (-1 === lcaGraph.indexOf(tempNode.id)) {
        tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]];
        depth++;
      } // logDebug('LCA of nodes ' + tempEdge.sourceId + ' and ' + tempEdge.targetId +
      //  ". Index: " + lca + " Contents: " + lcaGraph.toString() +
      //  ". Depth: " + depth);
      // Update idealLength


      idealLength *= depth * options.nestingFactor;
    }

    tempEdge.idealLength = idealLength;
    tempEdge.elasticity = elasticity;
    layoutInfo.layoutEdges.push(tempEdge);
  } // Finally, return layoutInfo object


  return layoutInfo;
}
@brief     : Creates an object which is contains all the data
             used in the layout process
@arg cy    : cytoscape.js object
@return    : layoutInfo object initialized