/*
* This file is part of the Trickl Open Source Libraries.
*
* Trickl Open Source Libraries - http://open.trickl.com/
*
* Copyright (C) 2011 Tim Gee.
*
* Trickl Open Source Libraries are free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Trickl Open Source Libraries are distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this project. If not, see <http://www.gnu.org/licenses/>.
*/
package com.trickl.graph;
import java.util.HashMap;
import java.util.Map;
import org.jgrapht.Graph;
public class CopyGraphVisitor<V1, E1, V2, E2> extends AbstractSpanningSearchVisitor<V1, E1> {
protected Graph<V1, E1> inputGraph;
protected Graph<V2, E2> outputGraph;
protected CopyVertexFactory<V2, V1> vertexFactory;
protected CopyEdgeFactory<V2, E2, E1> edgeFactory;
private Map<V1, V2> vertexMap;
private Map<V1, Integer> aggregationGroups;
private Map<Integer, V2> aggregationVertices;
public CopyGraphVisitor(Graph<V1, E1> inputGraph,
Graph<V2, E2> dualGraph) {
this(inputGraph, dualGraph, null);
}
public CopyGraphVisitor(Graph<V1, E1> inputGraph,
Graph<V2, E2> dualGraph,
CopyVertexFactory<V2, V1> vertexFactory) {
this(inputGraph, dualGraph, vertexFactory, null);
}
public CopyGraphVisitor(Graph<V1, E1> inputGraph,
Graph<V2, E2> outputGraph,
CopyVertexFactory<V2, V1> vertexFactory,
CopyEdgeFactory<V2, E2, E1> edgeFactory) {
this.inputGraph = inputGraph;
this.outputGraph = outputGraph;
this.vertexFactory = vertexFactory;
this.edgeFactory = edgeFactory;
this.vertexMap = new HashMap<V1, V2>();
this.aggregationVertices = new HashMap<Integer, V2>();
}
@Override
public void examineEdge(V1 inputSource, V1 inputTarget) {
V2 outputSource = getMappedVertex(inputSource);
V2 outputTarget = getMappedVertex(inputTarget);
// Don't create output self-loops, unless the self-loop existed
// in the input graph. This allows us to create aggregate graphs without
// self-loops for aggregated nodes.
if (!outputSource.equals(outputTarget) || inputSource.equals(inputTarget)) {
E2 edge = null;
E1 inputEdge = inputGraph.getEdge(inputSource, inputTarget);
if (edgeFactory != null) {
edge = edgeFactory.createEdge(outputSource, outputTarget, inputEdge);
} else {
edge = (E2) inputEdge;
}
outputGraph.addEdge(outputSource, outputTarget, edge);
}
}
private V2 getMappedVertex(V1 inputVertex) {
if (!vertexMap.containsKey(inputVertex)) {
V2 outputVertex = null;
Integer group = aggregationGroups == null
? null : aggregationGroups.get(inputVertex);
if (group != null) {
outputVertex = aggregationVertices.get(group);
}
if (outputVertex == null) {
// A new vertex in the output graph
if (vertexFactory != null) {
// Use the vertex factory to create new vertices
outputVertex = vertexFactory.createVertex(inputVertex);
} else {
// Can copy vertex straight over, but required V1 == V2
outputVertex = (V2) inputVertex;
}
outputGraph.addVertex(outputVertex);
if (group != null) {
// This vertex will now represent the group
aggregationVertices.put(group, outputVertex);
}
}
vertexMap.put(inputVertex, outputVertex);
}
return vertexMap.get(inputVertex);
}
public Map<V1, V2> getVertexMap() {
return vertexMap;
}
/**
* Optional aggregation of input graph vertices. Putting multiple input
* graph vertices in the same group will mean they are represented by
* a single vertex in the output graph
* @return
*/
public Map<V1, Integer> getAggregationGroups() {
return aggregationGroups;
}
public void setAggregationGroups(Map<V1, Integer> aggregationGroups) {
this.aggregationGroups = aggregationGroups;
}
}