1/*
2 * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24package com.sun.hotspot.igv.hierarchicallayout;
25
26import java.awt.Point;
27import java.awt.Rectangle;
28import java.util.HashMap;
29import java.util.List;
30import java.util.Set;
31import java.util.ArrayList;
32import java.util.HashSet;
33import java.util.TreeSet;
34import com.sun.hotspot.igv.layout.Cluster;
35import com.sun.hotspot.igv.layout.LayoutGraph;
36import com.sun.hotspot.igv.layout.LayoutManager;
37import com.sun.hotspot.igv.layout.Link;
38import com.sun.hotspot.igv.layout.Port;
39import com.sun.hotspot.igv.layout.Vertex;
40
41/**
42 *
43 * @author Thomas Wuerthinger
44 */
45public class HierarchicalClusterLayoutManager implements LayoutManager {
46
47    private HierarchicalLayoutManager.Combine combine;
48    private LayoutManager subManager = new HierarchicalLayoutManager(combine);
49    private LayoutManager manager = new HierarchicalLayoutManager(combine);
50    private static final boolean TRACE = false;
51
52    public HierarchicalClusterLayoutManager(HierarchicalLayoutManager.Combine combine) {
53        this.combine = combine;
54    }
55
56    public void doLayout(LayoutGraph graph) {
57        doLayout(graph, new HashSet<Vertex>(), new HashSet<Vertex>(), new HashSet<Link>());
58    }
59
60    public void doLayout(LayoutGraph graph, Set<? extends Link> importantLinks) {
61        doLayout(graph);
62    }
63
64    public void setSubManager(LayoutManager manager) {
65        this.subManager = manager;
66    }
67
68    public void setManager(LayoutManager manager) {
69        this.manager = manager;
70    }
71
72    public void doLayout(LayoutGraph graph, Set<? extends Vertex> firstLayerHint, Set<? extends Vertex> lastLayerHint, Set<? extends Link> importantLinks) {
73
74        assert graph.verify();
75
76        HashMap<Cluster, List<Vertex>> lists = new HashMap<Cluster, List<Vertex>>();
77        HashMap<Cluster, List<Link>> listsConnection = new HashMap<Cluster, List<Link>>();
78        HashMap<Cluster, HashMap<Port, ClusterInputSlotNode>> clusterInputSlotHash = new HashMap<Cluster, HashMap<Port, ClusterInputSlotNode>>();
79        HashMap<Cluster, HashMap<Port, ClusterOutputSlotNode>> clusterOutputSlotHash = new HashMap<Cluster, HashMap<Port, ClusterOutputSlotNode>>();
80
81        HashMap<Cluster, ClusterNode> clusterNodes = new HashMap<Cluster, ClusterNode>();
82        HashMap<Cluster, Set<ClusterInputSlotNode>> clusterInputSlotSet = new HashMap<Cluster, Set<ClusterInputSlotNode>>();
83        HashMap<Cluster, Set<ClusterOutputSlotNode>> clusterOutputSlotSet = new HashMap<Cluster, Set<ClusterOutputSlotNode>>();
84        Set<Link> clusterEdges = new HashSet<Link>();
85        Set<Link> interClusterEdges = new HashSet<Link>();
86        HashMap<Link, ClusterOutgoingConnection> linkClusterOutgoingConnection = new HashMap<Link, ClusterOutgoingConnection>();
87        HashMap<Link, InterClusterConnection> linkInterClusterConnection = new HashMap<Link, InterClusterConnection>();
88        HashMap<Link, ClusterIngoingConnection> linkClusterIngoingConnection = new HashMap<Link, ClusterIngoingConnection>();
89        Set<ClusterNode> clusterNodeSet = new HashSet<ClusterNode>();
90
91        Set<Cluster> cluster = graph.getClusters();
92        int z = 0;
93        for (Cluster c : cluster) {
94            lists.put(c, new ArrayList<Vertex>());
95            listsConnection.put(c, new ArrayList<Link>());
96            clusterInputSlotHash.put(c, new HashMap<Port, ClusterInputSlotNode>());
97            clusterOutputSlotHash.put(c, new HashMap<Port, ClusterOutputSlotNode>());
98            clusterOutputSlotSet.put(c, new TreeSet<ClusterOutputSlotNode>());
99            clusterInputSlotSet.put(c, new TreeSet<ClusterInputSlotNode>());
100            ClusterNode cn = new ClusterNode(c, "" + z);
101            clusterNodes.put(c, cn);
102            clusterNodeSet.add(cn);
103            z++;
104        }
105
106        // Add cluster edges
107        for (Cluster c : cluster) {
108
109            ClusterNode start = clusterNodes.get(c);
110
111            for (Cluster succ : c.getSuccessors()) {
112                ClusterNode end = clusterNodes.get(succ);
113                if (end != null && start != end) {
114                    ClusterEdge e = new ClusterEdge(start, end);
115                    clusterEdges.add(e);
116                    interClusterEdges.add(e);
117                }
118            }
119        }
120
121        for (Vertex v : graph.getVertices()) {
122            Cluster c = v.getCluster();
123            assert c != null : "Cluster of vertex " + v + " is null!";
124            clusterNodes.get(c).addSubNode(v);
125        }
126
127        for (Link l : graph.getLinks()) {
128
129            Port fromPort = l.getFrom();
130            Port toPort = l.getTo();
131            Vertex fromVertex = fromPort.getVertex();
132            Vertex toVertex = toPort.getVertex();
133            Cluster fromCluster = fromVertex.getCluster();
134            Cluster toCluster = toVertex.getCluster();
135
136            Port samePort = null;
137            if (combine == HierarchicalLayoutManager.Combine.SAME_INPUTS) {
138                samePort = toPort;
139            } else if (combine == HierarchicalLayoutManager.Combine.SAME_OUTPUTS) {
140                samePort = fromPort;
141            }
142
143            assert listsConnection.containsKey(fromCluster);
144            assert listsConnection.containsKey(toCluster);
145
146            if (fromCluster == toCluster) {
147                listsConnection.get(fromCluster).add(l);
148                clusterNodes.get(fromCluster).addSubEdge(l);
149            } else {
150                ClusterInputSlotNode inputSlotNode = null;
151                ClusterOutputSlotNode outputSlotNode = null;
152
153                if (samePort != null) {
154                    outputSlotNode = clusterOutputSlotHash.get(fromCluster).get(samePort);
155                    inputSlotNode = clusterInputSlotHash.get(toCluster).get(samePort);
156                }
157
158                if (outputSlotNode == null) {
159                    outputSlotNode = new ClusterOutputSlotNode(clusterNodes.get(fromCluster), "Out " + fromCluster.toString() + " " + samePort.toString());
160                    clusterOutputSlotSet.get(fromCluster).add(outputSlotNode);
161                    ClusterOutgoingConnection conn = new ClusterOutgoingConnection(outputSlotNode, l);
162                    outputSlotNode.setOutgoingConnection(conn);
163                    clusterNodes.get(fromCluster).addSubEdge(conn);
164                    if (samePort != null) {
165                        clusterOutputSlotHash.get(fromCluster).put(samePort, outputSlotNode);
166                    }
167
168                    linkClusterOutgoingConnection.put(l, conn);
169                } else {
170                    linkClusterOutgoingConnection.put(l, outputSlotNode.getOutgoingConnection());
171                }
172
173                if (inputSlotNode == null) {
174                    inputSlotNode = new ClusterInputSlotNode(clusterNodes.get(toCluster), "In " + toCluster.toString() + " " + samePort.toString());
175                    clusterInputSlotSet.get(toCluster).add(inputSlotNode);
176                }
177
178                ClusterIngoingConnection conn = new ClusterIngoingConnection(inputSlotNode, l);
179                inputSlotNode.setIngoingConnection(conn);
180                clusterNodes.get(toCluster).addSubEdge(conn);
181                if (samePort != null) {
182                    clusterInputSlotHash.get(toCluster).put(samePort, inputSlotNode);
183                }
184
185                linkClusterIngoingConnection.put(l, conn);
186
187
188                InterClusterConnection interConn = new InterClusterConnection(outputSlotNode, inputSlotNode);
189                linkInterClusterConnection.put(l, interConn);
190                clusterEdges.add(interConn);
191            }
192        }
193
194        Timing t = null;
195
196        if (TRACE) {
197            new Timing("Child timing");
198            t.start();
199        }
200
201        for (Cluster c : cluster) {
202            ClusterNode n = clusterNodes.get(c);
203            subManager.doLayout(new LayoutGraph(n.getSubEdges(), n.getSubNodes()), new HashSet<Link>());
204            n.updateSize();
205        }
206
207        Set<Vertex> roots = new LayoutGraph(interClusterEdges).findRootVertices();
208        for (Vertex v : roots) {
209            assert v instanceof ClusterNode;
210            ((ClusterNode) v).setRoot(true);
211        }
212
213        manager.doLayout(new LayoutGraph(clusterEdges, clusterNodeSet), interClusterEdges);
214
215        for (Cluster c : cluster) {
216            ClusterNode n = clusterNodes.get(c);
217            c.setBounds(new Rectangle(n.getPosition(), n.getSize()));
218        }
219
220        // TODO: handle case where blocks are not fully connected
221
222        if (TRACE) {
223            t.stop();
224            t.print();
225        }
226
227        for (Link l : graph.getLinks()) {
228
229            if (linkInterClusterConnection.containsKey(l)) {
230                ClusterOutgoingConnection conn1 = linkClusterOutgoingConnection.get(l);
231                InterClusterConnection conn2 = linkInterClusterConnection.get(l);
232                ClusterIngoingConnection conn3 = linkClusterIngoingConnection.get(l);
233
234                assert conn1 != null;
235                assert conn2 != null;
236                assert conn3 != null;
237
238                List<Point> points = new ArrayList<Point>();
239
240                points.addAll(conn1.getControlPoints());
241                points.addAll(conn2.getControlPoints());
242                points.addAll(conn3.getControlPoints());
243
244                l.setControlPoints(points);
245            }
246        }
247    }
248
249    public void doRouting(LayoutGraph graph) {
250    }
251}
252