/**
   * A childless stran is a "problem" in general because they break the evenness of the tree There
   * are three types of such strands, extra nodes to the left, extra to the right, or extra in
   * between parents. This method places those strands in spot.
   *
   * @param childlessStrand - the childless node to be laid out.
   * @param parentLeft - the nearest parent on the left (or <value>null</value> if none such exists)
   * @param parentRight - the nearest parent on the right (or <value>null</value> if none such
   *     exists)
   * @param yLoc - the vertical location to lay out the nodes on.
   */
  private void placeChildless(
      List<GXMoreThanNode> childlessStrand,
      GXMoreThanNode parentLeft,
      GXMoreThanNode parentRight,
      int yLoc) {
    int startMark = 0;
    int spacing =
        (int) (childlessStrand.get(0).getNode().getLayoutEntity().getWidthInLayout() + horSpacing);

    // There's only a parent on the right
    if (parentLeft == null && parentRight != null) {
      startMark = parentRight.getX() - (spacing * childlessStrand.size());
    } // there's a parent on the left
    else if (parentLeft != null) {
      startMark = parentLeft.getX() + spacing;

      // there's a parent on the right as well meaning the childless are between two parents
      // we need to make there's enough room to place them
      if (parentRight != null) {
        int endMark = startMark + (spacing * childlessStrand.size());

        // if there isn't enough room to place the childless between the parents
        if (endMark > parentRight.getX()) {
          // shift everything on the right to the right by the missing amount of space.
          shiftTreesRightOfMark(parentRight, endMark - parentRight.getX());
        }
      }
    }

    // now the room has been assured, place strand.
    placeStrand(childlessStrand, startMark, yLoc, spacing);
  }
  /**
   * follows the root by all its children to wrap the all up with all the extra info needed and adds
   * the tree to the matrix.
   *
   * @param currRoot - root to go over tree from
   * @param entitiesList - entities available
   * @param relationshipsList - relationship between the given entities
   * @param currRow - the current row in the matrix we are working on
   * @param rows - the matrix.
   */
  private void builtTreeFromRoot(
      GXMoreThanNode currRoot,
      List<InternalNode> entitiesList,
      List<InternalRelationship> relationshipsList,
      List<GXMoreThanNode> currRow,
      List<List<GXMoreThanNode>> rows) {

    // this is the first node that comes from the currRoot
    // we'll use the mark to know where to continue laying out from
    GXMoreThanNode mark = null;

    List<InternalRelationship> relationshipsListCopy =
        new ArrayList<InternalRelationship>(relationshipsList);
    // Orders the children of the currRoot in the given row (the row under it)
    for (InternalRelationship rel : relationshipsListCopy) {
      if (currRoot.getNode().equals(rel.getSource())) {
        InternalNode destNode = rel.getDestination();

        // if the destination node hasn't been laid out yet
        if (entitiesList.contains(destNode)) {

          // place it in the row (as in lay it out)
          GXMoreThanNode currNode = new GXMoreThanNode(destNode, currRoot.getNode());
          currRoot.addChild(currNode);
          currRow.add(currNode);
          currNode.addedToRow(currRow);
          entitiesList.remove(destNode);

          // if this is the first node, save it as a mark.
          if (mark == null) {
            mark = currNode;
          }

          // remove the relationship since both of its ends have been laid out.
          relationshipsList.remove(rel);
        }
      }
    }

    // if new children have been added
    if (mark != null) {

      // Create a next row if necessary
      if (rows.size() - 1 <= rows.indexOf(currRow)) {
        rows.add(new ArrayList<GXMoreThanNode>());
      }

      List<GXMoreThanNode> nextRow = rows.get(rows.indexOf(currRow) + 1);
      for (int i = currRow.indexOf(mark); i < currRow.size(); i++) {
        builtTreeFromRoot(currRow.get(i), entitiesList, relationshipsList, nextRow, rows);
      }
    }
  }
 /**
  * Shifts the trees right of mark node
  *
  * @param mark to shift from
  * @param shift - factor by which to move right by.
  */
 private void shiftTreesRightOfMark(GXMoreThanNode mark, int shift) {
   mark.setLocation(mark.getX() + shift, mark.getY());
   GXMoreThanNode leftMostChild = getRightMostChild(mark);
   List<GXMoreThanNode> treeRoots =
       leftMostChild
           .getRow()
           .subList(leftMostChild.getRow().indexOf(leftMostChild), leftMostChild.getRow().size());
   for (GXMoreThanNode root : treeRoots) {
     shiftTree(root, shift);
   }
 }
  /**
   * Returns the right most child of parent
   *
   * @param parent
   * @return the right most child of parent given.
   */
  private GXMoreThanNode getRightMostChild(GXMoreThanNode parent) {
    GXMoreThanNode rightMost = parent.getChildren().get(0);

    // run through children
    for (GXMoreThanNode child : parent.getChildren()) {
      if (child.getX() < rightMost.getX()) {
        rightMost = child;
      }
    }
    return rightMost;
  }
  /**
   * Lays out row with respect to it's children.
   *
   * @param yLocation - the vertical location to start placing the nodes.
   * @param row - the row who's nodes we'd like to lay out.
   */
  private void placeRow(List<GXMoreThanNode> row, int yLocation) {
    List<GXMoreThanNode> childlessStrand = new ArrayList<GXMoreThanNode>();
    GXMoreThanNode parentLeft = null;

    // for each parent in this parent row
    for (int j = 0; j < row.size(); j++) {
      GXMoreThanNode parentRight = row.get(j);
      // if the node has children
      if (!parentRight.getChildren().isEmpty()) {

        // place the node in the center above his children
        int parentX = 0;
        for (GXMoreThanNode child : parentRight.getChildren()) {
          parentX += child.getX();
        }
        parentX /= parentRight.getChildren().size();
        parentRight.setLocation(parentX, yLocation);

        // and layout the childless strand
        if (!childlessStrand.isEmpty()) {
          placeChildless(childlessStrand, parentLeft, parentRight, yLocation);
          childlessStrand.clear();
        }
        parentLeft = parentRight;

      } else { // accumulate the childless nodes
        childlessStrand.add(parentRight);
      }
    }

    // place childless who are extra on the right. as in did not get taken care of when
    // the parents were laid out.
    if (!childlessStrand.isEmpty()) {
      placeChildless(childlessStrand, parentLeft, null, yLocation);
    }
  }
 /**
  * Places the list of nodes horizontally at the given point and spaced on horizontally by given
  * spacing.
  *
  * @param strand - list of nodes to be laid out.
  * @param x - location to begin the placing
  * @param y - vertical location to lay out the entire list.
  * @param spacing the horizontal spacing between nodes.
  */
 private void placeStrand(List<GXMoreThanNode> strand, int x, int y, int spacing) {
   for (GXMoreThanNode item : strand) {
     item.setLocation(x, y);
     x += spacing;
   }
 }
 /**
  * Shifts the given tree by the shift factor given to the right.
  *
  * @param root - root of tree to shift
  * @param shift - factor to shirt by
  */
 private void shiftTree(GXMoreThanNode root, int shift) {
   root.setLocation(root.getX() + shift, root.getY());
   for (GXMoreThanNode child : root.getChildren()) {
     shiftTree(child, shift);
   }
 }