/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.kie.workbench.common.stunner.core.graph.util;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.kie.workbench.common.stunner.core.api.DefinitionManager;
import org.kie.workbench.common.stunner.core.client.canvas.Point2D;
import org.kie.workbench.common.stunner.core.graph.Edge;
import org.kie.workbench.common.stunner.core.graph.Element;
import org.kie.workbench.common.stunner.core.graph.Graph;
import org.kie.workbench.common.stunner.core.graph.Node;
import org.kie.workbench.common.stunner.core.graph.content.Bounds;
import org.kie.workbench.common.stunner.core.graph.content.definition.Definition;
import org.kie.workbench.common.stunner.core.graph.content.definition.DefinitionSet;
import org.kie.workbench.common.stunner.core.graph.content.relationship.Child;
import org.kie.workbench.common.stunner.core.graph.content.view.View;
public class GraphUtils {
public static Object getProperty(final DefinitionManager definitionManager,
final Element<? extends Definition> element,
final String id) {
if (null != element) {
final Object def = element.getContent().getDefinition();
final Set<?> properties = definitionManager.adapters().forDefinition().getProperties(def);
return getProperty(definitionManager,
properties,
id);
}
return null;
}
public static Object getProperty(final DefinitionManager definitionManager,
final Set<?> properties,
final String id) {
if (null != id && null != properties) {
for (final Object property : properties) {
final String pId = definitionManager.adapters().forProperty().getId(property);
if (pId.equals(id)) {
return property;
}
}
}
return null;
}
public static int countDefinitionsById(final DefinitionManager definitionManager,
final Graph<?, ? extends Node> target,
final String id) {
final int[] count = {0};
target.nodes().forEach(node -> {
if (getElementDefinitionId(definitionManager,
node).equals(id)) {
count[0]++;
}
});
return count[0];
}
public static <T> int countDefinitions(final DefinitionManager definitionManager,
final Graph<?, ? extends Node> target,
final T definition) {
final String id = definitionManager.adapters().forDefinition().getId(definition);
return countDefinitionsById(definitionManager,
target,
id);
}
public static int countEdges(final DefinitionManager definitionManager,
final String edgeId,
final List<? extends Edge> edges) {
final int[] count = {0};
if (null != edgeId
&& null != edges
&& !edges.isEmpty()) {
edges.stream().forEach(edge -> {
final String eId = getElementDefinitionId(definitionManager,
edge);
if (null != eId && edgeId.equals(eId)) {
count[0]++;
}
});
}
return count[0];
}
/**
* Does not returns labels not being used on the graph,
* even if included in the <code>filter</code>.
*/
@SuppressWarnings("unchecked")
public static Map<String, Integer> getLabelsCount(final Graph<?, ? extends Node> target,
final Set<String> filter) {
final Map<String, Integer> labels = new LinkedHashMap<>();
target.nodes().forEach(node -> {
final Set<String> nodeRoles = node.getLabels();
if (null != nodeRoles) {
nodeRoles
.stream()
.filter(role -> null == filter || filter.contains(role))
.forEach(role -> {
final Integer i = labels.get(role);
labels.put(role,
null != i ? i + 1 : 1);
});
}
});
return labels;
}
@SuppressWarnings("unchecked")
public static List<String> getParentIds(final DefinitionManager definitionManager,
final Graph<? extends DefinitionSet, ? extends Node> graph,
final Element<?> element) {
final List<String> result = new ArrayList<>(5);
Element<?> p = element;
while (p instanceof Node && p.getContent() instanceof Definition) {
p = getParent((Node<? extends Definition<?>, ? extends Edge>) p);
if (null != p) {
final Object definition = ((Definition) p.getContent()).getDefinition();
final String id = definitionManager.adapters().forDefinition().getId(definition);
result.add(id);
}
}
final String graphId = graph.getContent().getDefinition();
result.add(graphId);
return result;
}
@SuppressWarnings("unchecked")
public static Element<?> getParent(final Node<?, ? extends Edge> element) {
final List<? extends Edge> inEdges = element.getInEdges();
if (null != inEdges) {
final Edge<Child, ?> childEdge =
inEdges.stream()
.filter(edge -> (edge.getContent() instanceof Child))
.findFirst()
.orElse(null);
if (null != childEdge) {
return childEdge.getSourceNode();
}
}
return null;
}
public static Point2D getPosition(final View element) {
final Bounds.Bound ul = element.getBounds().getUpperLeft();
final double x = ul.getX();
final double y = ul.getY();
return new Point2D(x,
y);
}
public static double[] getGraphSize(final DefinitionSet element) {
final Bounds.Bound ul = element.getBounds().getUpperLeft();
final Bounds.Bound lr = element.getBounds().getLowerRight();
final double w = lr.getX() - ul.getX();
final double h = lr.getY() - ul.getY();
return new double[]{Math.abs(w), Math.abs(h)};
}
public static double[] getNodeSize(final View element) {
final Bounds.Bound ul = element.getBounds().getUpperLeft();
final Bounds.Bound lr = element.getBounds().getLowerRight();
final double w = lr.getX() - ul.getX();
final double h = lr.getY() - ul.getY();
return new double[]{Math.abs(w), Math.abs(h)};
}
/**
* Checks that the given Bounds do not exceed graph limits.
* @return if bounds exceed graph limits it returns <code>false</code>. Otherwise returns <code>true</code>.
*/
@SuppressWarnings("unchecked")
public static boolean checkBoundsExceeded(final Graph<DefinitionSet, ? extends Node> graph,
final Bounds bounds) {
final Bounds graphBounds = graph.getContent().getBounds();
if ((bounds.getLowerRight().getX() > graphBounds.getLowerRight().getX())
|| (bounds.getLowerRight().getY() > graphBounds.getLowerRight().getY())) {
return false;
}
return true;
}
/**
* Finds the first node in the graph structure for the given type.
* @param graph The graph structure.
* @param type The Definition type..
*/
@SuppressWarnings("unchecked")
public static <C> Node<Definition<C>, ?> getFirstNode(final Graph<?, Node> graph,
final Class<?> type) {
if (null != graph) {
for (final Node node : graph.nodes()) {
final Object content = node.getContent();
try {
final Definition definitionContent = (Definition) content;
if (instanceOf(definitionContent.getDefinition(),
type)) {
return node;
}
} catch (final ClassCastException e) {
// Node content does not contains a definition.
}
}
}
return null;
}
private static String getElementDefinitionId(final DefinitionManager definitionManager,
final Element<?> element) {
String targetId = null;
if (element.getContent() instanceof Definition) {
final Object definition = ((Definition) element.getContent()).getDefinition();
targetId = definitionManager.adapters().forDefinition().getId(definition);
} else if (element.getContent() instanceof DefinitionSet) {
targetId = ((DefinitionSet) element.getContent()).getDefinition();
}
return targetId;
}
private static boolean instanceOf(final Object item,
final Class<?> clazz) {
return null != item && item.getClass().equals(clazz);
}
}