--- /dev/null
+package org.simantics.graph.matching;\r
+\r
+import gnu.trove.map.hash.TIntIntHashMap;\r
+import gnu.trove.map.hash.TIntObjectHashMap;\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.graph.representation.External;\r
+import org.simantics.graph.representation.Identity;\r
+import org.simantics.graph.representation.Internal;\r
+import org.simantics.graph.representation.Optional;\r
+import org.simantics.graph.representation.Root;\r
+\r
+/**\r
+ * A strategy matching resources with equal URIs.\r
+ * \r
+ * @author Hannu Niemistö\r
+ */\r
+public enum IdentityMatchingStrategy implements GraphMatchingStrategy {\r
+\r
+ INSTANCE;\r
+ \r
+ static class NamedResource {\r
+ String name;\r
+ int resource;\r
+ \r
+ public NamedResource(String name, int resource) {\r
+ this.name = name;\r
+ this.resource = resource;\r
+ }\r
+ }\r
+ \r
+ static class IdentityTree {\r
+ TIntObjectHashMap<ArrayList<NamedResource>> childMap = new TIntObjectHashMap<ArrayList<NamedResource>>();\r
+ ArrayList<NamedResource> roots = new ArrayList<NamedResource>(); \r
+ \r
+ public IdentityTree(Identity[] indentities) {\r
+ for(Identity id : indentities) {\r
+ if(id.definition instanceof External) {\r
+ External def = (External)id.definition;\r
+ addChild(id.resource, def.parent, def.name);\r
+ }\r
+ else if(id.definition instanceof Internal) {\r
+ Internal def = (Internal)id.definition;\r
+ addChild(id.resource, def.parent, def.name);\r
+ }\r
+ else if(id.definition instanceof Optional) {\r
+ Optional def = (Optional)id.definition;\r
+ addChild(id.resource, def.parent, def.name);\r
+ }\r
+ else if(id.definition instanceof Root) {\r
+ addRoot(id.resource, ((Root)id.definition).name);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void addRoot(int root, String name) {\r
+ roots.add(new NamedResource(name, root));\r
+ }\r
+ \r
+ private void addChild(int child, int parent, String name) {\r
+ ArrayList<NamedResource> children = childMap.get(parent);\r
+ if(children == null) {\r
+ children = new ArrayList<NamedResource>();\r
+ childMap.put(parent, children);\r
+ }\r
+ children.add(new NamedResource(name, child));\r
+ }\r
+ }\r
+ \r
+ static class MatchingProcess {\r
+ int[] aToB; \r
+ int[] bToA; \r
+ TIntIntHashMap aInv;\r
+ TIntIntHashMap bInv;\r
+ IdentityTree aTree; \r
+ IdentityTree bTree;\r
+ \r
+ public MatchingProcess(int[] aToB, int[] bToA,\r
+ TIntIntHashMap aInv, TIntIntHashMap bInv,\r
+ IdentityTree aTree, IdentityTree bTree) {\r
+ this.aToB = aToB;\r
+ this.bToA = bToA;\r
+ this.aInv = aInv;\r
+ this.bInv = bInv;\r
+ this.aTree = aTree;\r
+ this.bTree = bTree;\r
+ }\r
+\r
+ public void execute() {\r
+ match(aTree.roots, bTree.roots);\r
+ }\r
+\r
+ private void match(ArrayList<NamedResource> as, ArrayList<NamedResource> bs) {\r
+ TObjectIntHashMap<String> map = new TObjectIntHashMap<String>();\r
+ for(NamedResource b : bs)\r
+ map.put(b.name, b.resource);\r
+ for(NamedResource a : as)\r
+ if(map.contains(a.name))\r
+ match(a.resource, map.get(a.name));\r
+ }\r
+\r
+ private void match(int a, int b) {\r
+ if(aToB[a] < 0 && bToA[b] < 0) {\r
+ aToB[a] = b;\r
+ bToA[b] = a;\r
+ \r
+ if(aInv.contains(a) && bInv.contains(b))\r
+ match(aInv.get(a), bInv.get(b));\r
+ \r
+ ArrayList<NamedResource> as = aTree.childMap.get(a);\r
+ if(as == null)\r
+ return;\r
+ ArrayList<NamedResource> bs = bTree.childMap.get(b);\r
+ if(bs == null)\r
+ return;\r
+ match(as, bs);\r
+ }\r
+ }\r
+ }\r
+ \r
+ public void mapUnmapped(int[] map, TIntIntHashMap inverses, Identity[] identities, int rangeCount) {\r
+ for(Identity id : identities) {\r
+ int r = id.resource;\r
+ if(map[r] < 0) {\r
+ map[r] = rangeCount++;\r
+ if(inverses.containsKey(r))\r
+ map[inverses.get(r)] = rangeCount++;\r
+ }\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void applyTo(GraphMatching matching) {\r
+ new MatchingProcess(\r
+ matching.aToB, matching.bToA, \r
+ matching.aGraph.inverses, matching.bGraph.inverses,\r
+ new IdentityTree(matching.aGraph.identities), new IdentityTree(matching.bGraph.identities)\r
+ ).execute(); \r
+ mapUnmapped(matching.aToB, matching.aGraph.inverses, \r
+ matching.aGraph.identities, matching.bGraph.resourceCount);\r
+ mapUnmapped(matching.bToA, matching.bGraph.inverses, \r
+ matching.bGraph.identities, matching.aGraph.resourceCount);\r
+ matching.recomputeSize();\r
+ }\r
+}\r