/*
* Copyright (C) 2014 by Array Systems Computing Inc. http://www.array.ca
*
* This program is 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.
* This program is 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 program; if not, see http://www.gnu.org/licenses/
*/
package org.esa.snap.graphbuilder.rcp.dialogs.support;
import com.bc.ceres.binding.dom.DomElement;
import org.esa.snap.core.gpf.graph.Graph;
import org.esa.snap.core.gpf.graph.GraphException;
import org.esa.snap.core.gpf.graph.GraphIO;
import org.esa.snap.core.gpf.graph.Node;
import org.esa.snap.core.gpf.graph.NodeSource;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Replaces SubGraphOp with operators from the sub-graph
*/
public class SubGraphHandler {
private final Graph graph;
private final GraphNodeList graphNodeList;
private final GraphNode[] savedSubGraphList;
private GraphNode[] nodesToRemove;
public SubGraphHandler(final Graph graph, final GraphNodeList graphNodeList) throws GraphException {
this.graph = graph;
this.graphNodeList = graphNodeList;
this.savedSubGraphList = replaceAllSubGraphs();
}
private GraphNode[] replaceAllSubGraphs() throws GraphException {
final SubGraphData[] dataList = findSubGraphs("SubGraph");
final List<GraphNode> savedList = new ArrayList<>();
for (SubGraphData data : dataList) {
final GraphNode sourceNode = graphNodeList.findGraphNode(data.nodeID);
if (data.subGraph != null) {
replaceSubGraph(sourceNode, data.subGraph);
removeNode(sourceNode);
savedList.add(sourceNode);
}
}
return savedList.toArray(new GraphNode[savedList.size()]);
}
private SubGraphData[] findSubGraphs(final String opName) throws GraphException {
try {
final List<SubGraphData> dataList = new ArrayList<>();
for (Node n : graph.getNodes()) {
if (n.getOperatorName().equalsIgnoreCase(opName)) {
final SubGraphData data = new SubGraphData();
data.nodeID = n.getId();
final DomElement config = n.getConfiguration();
final DomElement[] params = config.getChildren();
for (DomElement p : params) {
if (p.getName().equals("graphFile") && p.getValue() != null) {
data.subGraph = GraphIO.read(new FileReader(p.getValue()));
break;
}
}
dataList.add(data);
}
}
return dataList.toArray(new SubGraphData[dataList.size()]);
} catch (Exception e) {
throw new GraphException(e.getMessage(), e);
}
}
public void restore() {
for (GraphNode savedNode : savedSubGraphList) {
for (GraphNode n : nodesToRemove) {
graphNodeList.switchConnections(n, savedNode.getID());
removeNode(n);
}
graphNodeList.add(savedNode);
graph.addNode(savedNode.getNode());
}
}
private void replaceSubGraph(final GraphNode subGraphOpNode, final Graph subGraph) {
final List<GraphNode> toRemove = new ArrayList<>();
final Node[] nodes = subGraph.getNodes();
final Node firstNode = nodes[0];
final Node lastNode = nodes[nodes.length - 1];
final GraphNode[] connectedNodes = graphNodeList.findConnectedNodes(subGraphOpNode);
final NodeSource[] sources = subGraphOpNode.getNode().getSources();
for (NodeSource source : sources) {
final Map<String, Node> subGraphNodeMap = new HashMap<>();
for (Node subNode : nodes) {
final Node newNode = new Node(source.getSourceNodeId() + subNode.getId(), subNode.getOperatorName());
subGraphNodeMap.put(subNode.getId(), newNode);
newNode.setConfiguration(subNode.getConfiguration());
graph.addNode(newNode);
GraphNode newGraphNode = new GraphNode(newNode);
graphNodeList.add(newGraphNode);
toRemove.add(newGraphNode);
for (NodeSource ns : subNode.getSources()) {
Node src = subGraphNodeMap.get(ns.getSourceNodeId());
if (src != null) {
newGraphNode.connectOperatorSource(src.getId());
}
}
if (subNode == firstNode) {
newNode.addSource(source);
} else if (subNode == lastNode) {
// switch connections
for (GraphNode node : connectedNodes) {
node.connectOperatorSource(newNode.getId());
}
}
}
}
nodesToRemove = toRemove.toArray(new GraphNode[toRemove.size()]);
}
private void removeNode(final GraphNode node) {
graphNodeList.remove(node);
graph.removeNode(node.getID());
}
private static class SubGraphData {
String nodeID = null;
Graph subGraph = null;
}
}