/**
     * Adds all ports of given {@link LoopSide} of this component-holder to the current position of
     * the {@link ListIterator}. The ports are placed, so that source and target ports of an edge
     * are placed next to each other. The target port of an edge will be places before the source
     * port of an edge.
     *
     * @param loopSide The components of this {@link LoopSide} will be added.
     * @param itr The {@link ListIterator} to add the ports into.
     */
    public void addInlineTargetsFirst(final LoopSide loopSide, final ListIterator<LPort> itr) {
      final List<LPort> firstPart = Lists.newArrayList();
      final List<LPort> secondPart = Lists.newArrayList();

      final Iterator<ConnectedSelfLoopComponent> compItr =
          LISTS_OF_COMPONENTS.get(loopSide).iterator();

      while (compItr.hasNext()) {
        ConnectedSelfLoopComponent component = compItr.next();
        firstPart.addAll(0, component.getSourceLoopPorts());
        firstPart.addAll(0, component.getTargetLoopPortsReversed());

        if (compItr.hasNext()) {
          component = compItr.next();
          secondPart.addAll(component.getTargetLoopPortsReversed());
          secondPart.addAll(component.getSourceLoopPorts());
        }
      }

      setSideOfPorts(firstPart, loopSide.getTargetSide());
      setSideOfPorts(secondPart, loopSide.getSourceSide());

      for (final LPort port : firstPart) {
        itr.add(port);
      }
      for (final LPort port : secondPart) {
        itr.add(port);
      }
    }
    /**
     * Adds all target ports and than all source ports of the components of given {@link LoopSide}
     * of this component-holder to the current position of the {@link ListIterator}. The source
     * ports will be added in reversed order.
     *
     * @param loopSide The components of this {@link LoopSide} will be added.
     * @param itr The {@link ListIterator} to add the ports into.
     */
    public void addAllPorts(
        final LoopSide loopSide, final ListIterator<LPort> itr, final boolean sourceFirst) {

      final List<LPort> secondPart = Lists.newArrayList();
      PortSide secondPartSide = null;

      if (sourceFirst) {
        for (final ConnectedSelfLoopComponent component : LISTS_OF_COMPONENTS.get(loopSide)) {
          for (final LPort port : component.getSourceLoopPorts()) {
            itr.add(port);
            setSideOfPort(port, loopSide.getSourceSide());
          }
          secondPart.addAll(component.getTargetLoopPorts());
          secondPartSide = loopSide.getTargetSide();
        }
      } else {
        for (final ConnectedSelfLoopComponent component : LISTS_OF_COMPONENTS.get(loopSide)) {
          for (final LPort port : component.getTargetLoopPorts()) {
            itr.add(port);
            setSideOfPort(port, loopSide.getTargetSide());
          }
          secondPart.addAll(component.getSourceLoopPorts());
          secondPartSide = loopSide.getSourceSide();
        }
      }

      Collections.reverse(secondPart);
      setSideOfPorts(secondPart, secondPartSide);
      for (final LPort port : secondPart) {
        itr.add(port);
      }
    }
  /**
   * Sets the loopSide of all self-loops of the component individually, depending on the side(s)
   * already defined for at least one port in the component. At least one portSide must be defined,
   * otherwise this method will run infinitely.
   *
   * @param component The connected component to process.
   * @return The LoopSide that is equal to the assigned portSides. Undefined, if there is not a
   *     common side for all loops.
   */
  private LoopSide setPortSideByConstraint(final ConnectedSelfLoopComponent component) {
    // Iterator over the edges of the component.
    // The iterator is cycling, as there is no guarantee, that (at least) one port of the current
    // edge has a portSide defined. If both portSides of the current edge are UNDEFINED, we will
    // return to it later.
    final Iterator<LEdge> iter = Iterators.cycle(Lists.newArrayList(component.getEdges()));
    // LoopSides in this component will be collected here
    final EnumSet<LoopSide> loopSidesInComponent = EnumSet.noneOf(LoopSide.class);

    while (iter.hasNext()) {
      final LEdge edge = iter.next();
      final PortSide sourceSide = edge.getSource().getSide();
      final PortSide targetSide = edge.getTarget().getSide();
      if (sourceSide == PortSide.UNDEFINED) {
        // source side is undefined
        if (targetSide != PortSide.UNDEFINED) {
          // only targetSide is defined. Edge becomes a sideLoop on the side of target.
          final LoopSide side = LoopSide.fromPortSides(targetSide);
          edge.setProperty(InternalProperties.SPLINE_LOOPSIDE, side);
          edge.getSource().setSide(targetSide);
          loopSidesInComponent.add(side);
          iter.remove();
        }
      } else {
        // source side is defined
        if (targetSide == PortSide.UNDEFINED) {
          // only sourceSide is defined. Edge becomes a sideLoop on the side of source.
          final LoopSide side = LoopSide.fromPortSides(sourceSide);
          edge.setProperty(InternalProperties.SPLINE_LOOPSIDE, side);
          edge.getTarget().setSide(sourceSide);
          loopSidesInComponent.add(side);
          iter.remove();
        } else {
          // both sides are defined, set edge side resulting from the combination
          final LoopSide side = LoopSide.fromPortSide(sourceSide, targetSide);
          edge.setProperty(InternalProperties.SPLINE_LOOPSIDE, side);
          loopSidesInComponent.add(side);
          iter.remove();
        }
      }
    }

    // Now all edges have a LoopSide assigned.
    // Check if we can find a LoopSide for the whole component.
    LoopSide side;
    if (loopSidesInComponent.size() == 1) {
      side = loopSidesInComponent.iterator().next();
    } else {
      side = LoopSide.UNDEFINED;
    }

    component.setLoopSide(side, false);
    return side;
  }
    /**
     * Finds the "center" of the setup of currently available sides.
     *
     * @return The side considered as "center" for current setup of available port-sides.
     */
    private LoopSide findCenter() {
      final EnumSet<LoopSide> retVal;
      Iterator<LoopSide> itr;
      switch (loopSides.availableStraightSides().size()) {
        case 4:
          // all sides available: south is the center.
          return LoopSide.S;
        case 3:
          // only one side not available: the side not available is the center.
          return loopSides.allRemovedStraightSides().iterator().next();
        case 2:
          // Two sides were removed, two sides remain available. The center side depends on
          // the pattern of the removed/available sides:
          retVal = loopSides.availableStraightSides();
          itr = retVal.iterator();
          LoopSide first = itr.next();
          LoopSide second = itr.next();

          if (first.opposite() == second) {
            // the removed sides are opposed to each other.
            if (retVal.contains(LoopSide.S)) {
              // n-s sides were removed. Center is east.
              return LoopSide.E;
            } else {
              // w-e sides were removed. center is south.
              return LoopSide.S;
            }
          } else {
            // the removed sides were neighbors. The center is between them.
            if (first.left().left() == second) {
              // first element is right of second element.
              return first.left();
            } else {
              // first element is left of second element
              return first.right();
            }
          }
        case 1:
          // only one straight side is remaining. The opposite of this side is the center.
          retVal = loopSides.availableStraightSides();
          return retVal.iterator().next().opposite();
        case 0:
          // all straight sides were removed. The center is the s-e corner.
          return LoopSide.SE;
        default:
          return null;
      }
    }
    /**
     * Constructs a new {@code PortReAdder} holding the given {@link ConnectedSelfLoopComponent}s
     * given.
     *
     * @param components The {@link ConnectedSelfLoopComponent}s to be part of this PortReAdder.
     */
    PortReadder(final List<ConnectedSelfLoopComponent> components) {
      // Initialize the mapping. As the mapping is static, this needs to be done on every new run.
      for (LoopSide side : LoopSide.values()) {
        LISTS_OF_COMPONENTS.put(side, new ArrayList<ConnectedSelfLoopComponent>());
      }

      // First: group the components according to their loopSide
      for (final ConnectedSelfLoopComponent component : components) {
        allHiddenPorts.addAll(component.getHidablePorts());

        if (component.getNonLoopPorts().isEmpty()) {
          LISTS_OF_COMPONENTS.get(component.getLoopSide()).add(component);
        } else {
          withNonSelfLoop.add(component);
        }
      }

      // Second: sort the collections of components
      // (in revered order, biggest first)
      for (List<ConnectedSelfLoopComponent> list : LISTS_OF_COMPONENTS.values()) {
        Collections.sort(list, loopSorter);
      }
      // ports on the NW-border need to be reversed, again.
      Collections.reverse(LISTS_OF_COMPONENTS.get(LoopSide.NW));
    }
      /** Updates the performance lists. */
      private void updateAvailableSides() {
        availableStraightSides.clear();
        availableSides.clear();
        availableNotAcrossSides.clear();

        for (final LoopSide side : sizeMap.keySet()) {
          if (!side.isAcross()) {
            availableNotAcrossSides.add(side);
            if (side.isStraight()) {
              availableStraightSides.add(side);
            }
          }
          availableSides.add(side);
        }
        sideRemovedOrChanged = false;
      }
 /**
  * Adds all target ports of the components of given {@link LoopSide} of this component-holder to
  * the current position of the {@link ListIterator}.
  *
  * @param loopSide The components of this {@link LoopSide} will be added.
  * @param itr The {@link ListIterator} to add the ports into.
  */
 public void addTargetPorts(final LoopSide loopSide, final ListIterator<LPort> itr) {
   final PortSide portSide = loopSide.getTargetSide();
   for (final ConnectedSelfLoopComponent component : LISTS_OF_COMPONENTS.get(loopSide)) {
     for (final LPort port : component.getTargetLoopPorts()) {
       itr.add(port);
       setSideOfPort(port, portSide);
     }
   }
 }
    /**
     * Adds all source ports of the components of given {@link LoopSide} of this component-holder to
     * the current position of the {@link ListIterator} in reversed order.
     *
     * @param loopSide The components of this {@link LoopSide} will be added.
     * @param itr The {@link ListIterator} to add the ports into.
     */
    public void addSourcePortsReversed(final LoopSide loopSide, final ListIterator<LPort> itr) {
      final List<LPort> sourcePorts = Lists.newArrayList();

      for (final ConnectedSelfLoopComponent component : LISTS_OF_COMPONENTS.get(loopSide)) {
        sourcePorts.addAll(component.getSourceLoopPorts());
      }

      Collections.reverse(sourcePorts);
      setSideOfPorts(sourcePorts, loopSide.getSourceSide());

      for (final LPort port : sourcePorts) {
        itr.add(port);
      }
    }
    /**
     * Distributes the self-loops equally around the node.
     *
     * @param components
     */
    public void calculate(final List<ConnectedSelfLoopComponent> components) {
      final List<ConnectedSelfLoopComponent> withLongText = Lists.newArrayList();
      final List<ConnectedSelfLoopComponent> withShortText = Lists.newArrayList();
      final List<ConnectedSelfLoopComponent> withoutText = Lists.newArrayList();

      // first we are going to check for the size of possible edge labels
      for (final ConnectedSelfLoopComponent component : components) {
        if (component.getTextWidth() > MAX_TEXT_LENGTH) {
          withLongText.add(component);
        } else if (component.getTextWidth() > 0.0) {
          withShortText.add(component);
        } else {
          withoutText.add(component);
        }
      }

      // if there is only one loop with text, handle this loop as a long text loop
      if (withShortText.size() == 1 && withLongText.isEmpty()) {
        withLongText.addAll(withShortText);
        withShortText.clear();
      }

      // try to put the components with long text to one of the horizontal across loop sides.
      // if there are no such sides available, handle long text loops as short text loops.
      if (!withLongText.isEmpty()
          && loopSides.availableSides().contains(LoopSide.N)
          && loopSides.availableSides().contains(LoopSide.S)) {
        assignAcrossSide(withLongText);
      } else {
        withShortText.addAll(withLongText);
      }

      // put the components with short text to one of the corner loop sides
      if (!withShortText.isEmpty()) {
        assignCornerSide(withShortText);
      }

      // Last but not least: loops without text get spread equally.
      if (!withoutText.isEmpty()) {
        // ////////////////////////////////////////////////////////////
        // First of all we try to put those ConnectedSelfLoops who have more than one edge,
        // to one of the available straight sides.
        // ////////////////////////////////////////////////////////////

        final Set<LoopSide> availableStraights = loopSides.availableStraightSides();
        if (!availableStraights.isEmpty()) {
          final Iterator<ConnectedSelfLoopComponent> itrComponent = withoutText.iterator();
          final Iterator<LoopSide> itrAvailable = Iterables.cycle(availableStraights).iterator();

          while (itrComponent.hasNext()) {

            // look for a component with more than one edge
            ConnectedSelfLoopComponent component = itrComponent.next();
            while (itrComponent.hasNext() && component.getEdges().size() < 2) {
              component = itrComponent.next();
            }

            // If we have found a component with more than one edge, assign the next
            // straight side to the component.
            if (component.getEdges().size() > 1) {
              final LoopSide side = itrAvailable.next();
              component.setLoopSide(side, true);
              itrComponent.remove();
              loopSides.removeSide(side);
            }
          }
        }

        // ////////////////////////////////////////////////////////////
        // Now we can distribute the remaining components around the node.
        // ////////////////////////////////////////////////////////////

        // number of required sides
        final int number = withoutText.size();

        // Center of the assigned pattern.
        final LoopSide center = findCenter();

        // The list of portSides we assign to the set of connected components.
        final List<LoopSide> portSides = Lists.newArrayList();

        // How many times must a "full set" of LoopSide-elements be constructed?
        final int fullSets = number / loopSides.availableNotAcrossSides().size();

        // Construct the full sets.
        for (int i = 0; i < fullSets; i++) {
          portSides.addAll(loopSides.availableNotAcrossSides());
        }

        // How many elements are remaining to be constructed after the full sets have been
        // constructed?
        int remainer = number % loopSides.availableNotAcrossSides().size();

        // If more than three elements are remaining, the pattern includes all four corners
        // and the sides that would be included in the pattern for (n-4) elements.
        if (remainer > 3) {
          portSides.addAll(LoopSide.getAllCornerSides());
          remainer -= 4;
        }

        // Create the pattern for 1-3 elements.
        switch (remainer) {
          case 3:
            // opposed side (from center) and the the same sides as for two elements
            portSides.add(center.opposite());
          case 2:
            // the first AVAILABLE neighbors of the neighbors of the opposed side of the
            // center
            LoopSide tmpSide = center.opposite().left();
            do {
              tmpSide = tmpSide.left();
            } while (!loopSides.availableSides().contains(tmpSide));
            portSides.add(tmpSide);

            tmpSide = center.opposite().right();
            do {
              tmpSide = tmpSide.right();
            } while (!loopSides.availableSides().contains(tmpSide));
            portSides.add(tmpSide);
            break;
          case 1:
            // opposed side (from center)
            portSides.add(center.opposite());
            break;
          default:
            break;
        }

        // Now assign the remaining sides to the set of portSides we just have constructed.
        final Iterator<LoopSide> itrSides = portSides.iterator();
        final Iterator<ConnectedSelfLoopComponent> itrComponent = withoutText.iterator();
        while (itrSides.hasNext() && itrComponent.hasNext()) {
          itrComponent.next().setLoopSide(itrSides.next(), true);
        }
      }
    }
 /**
  * Removes all sides from the list of available sides, that already have an port places on it.
  * Use to make sure no loops will be places on sides with ports containing non-loop edges.
  */
 public void removeOccupiedSides() {
   for (final LPort port : node.getPorts()) {
     loopSides.removeSide(LoopSide.fromPortSides(port.getSide()));
   }
 }
 static {
   for (LoopSide side : LoopSide.values()) {
     LISTS_OF_COMPONENTS.put(side, null);
   }
 }
 /** @return A {@link List} of all removed side loopSides. */
 private Set<LoopSide> allRemovedStraightSides() {
   final Set<LoopSide> retVal = LoopSide.getAllStraightSides();
   retVal.removeAll(availableStraightSides());
   return retVal;
 }
 public SortedLoopSides() {
   for (final LoopSide side : LoopSide.getAllDefinedSides()) {
     sizeMap.put(side, new SizeOfSide(0.0, 0.0));
   }
 }