class CaseManagementSetChildNodeGraphCommand extends AbstractGraphCommand {

    @SuppressWarnings("unchecked")
    void addNewRelationship(final GraphCommandExecutionContext context) {
        OptionalInt insertIndex = index;

        if (isStage(parent, child)) {
            // If moving a Stage
            List<Node> childNodes = parent.getOutEdges().stream()
                    .map(Edge::getTargetNode).collect(Collectors.toList());

            if (index.isPresent()) {
                // Find the last Stage node or the Start Event
                for (int i = index.getAsInt() - 1; i >= 0; i--) {
                    Node node = childNodes.get(i);
                    if (isStageNode(node)
                            || ((Node<View<?>, Edge>) node).getContent().getDefinition() instanceof StartNoneEvent) {
                        in = Optional.of(node);
                        break;
                    }
                }

                // Find the next Stage node or the End Event
                for (int i = index.getAsInt(), n = childNodes.size(); i < n; i++) {
                    Node node = childNodes.get(i);
                    if (isStageNode(node)
                            || ((Node<View<?>, Edge>) node).getContent().getDefinition() instanceof EndNoneEvent) {
                        out = Optional.of(node);
                        break;
                    }
                }
            } else {
                int n = childNodes.size();
                int i = n - 1;

                // If index is not specified, find the last Stage node and move the node next to it
                for (; i >= 0; i--) {
                    Node node = childNodes.get(i);
                    if (isStageNode(node)
                            || ((Node<View<?>, Edge>) node).getContent().getDefinition() instanceof StartNoneEvent) {
                        in = Optional.of(node);
                        insertIndex = OptionalInt.of(i + 1);
                        break;
                    }
                }

                if (i == 0) {
                    insertIndex = OptionalInt.of(0);
                }

                // Find the End Event after the last Stage node
                if (i >= 0) {
                    for (; i < n; i++) {
                        Node node = childNodes.get(i);
                        if (((Node<View<?>, Edge>) node).getContent().getDefinition() instanceof EndNoneEvent) {
                            out = Optional.of(node);
                            break;
                        }
                    }
                }
            }
        }

        // There is a direct edge between two nodes next to the moved node, remove the edge
        if (in.isPresent() && out.isPresent()) {
            edge = getEdgeForTarget(in,
                                    out.get(),
                                    sequencePredicate());
        }

        edge.ifPresent(e -> removeRelationship(e,
                                               in.get(),
                                               out.get(),
                                               context));

        // Add new relationship
        addRelationship(parent,
                        child,
                        insertIndex,
                        context,
                        Child::new);

        // Link the nodes to the moved node
        in.ifPresent(n -> addRelationship(n,
                                          child,
                                          OptionalInt.empty(),
                                          context,
                                          sequenceFlowSupplier()));
        out.ifPresent(n -> addRelationship(child,
                                           n,
                                           OptionalInt.empty(),
                                           context,
                                           sequenceFlowSupplier()));
    }

    public  CaseManagementSetChildNodeGraphCommand(final Node<View<?>, Edge> parent,
                                                  final Node<View<?>, Edge> child,
                                                  final OptionalInt index,
                                                  final Optional<Node<View<?>, Edge>> originalParent,
                                                  final OptionalInt originalIndex);

}