]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop.mapping/src/org/simantics/interop/mapping/data/GraphNode.java
d9bbb5099c788927b11918e3920b9be716c6e96f
[simantics/interop.git] / org.simantics.interop.mapping / src / org / simantics / interop / mapping / data / GraphNode.java
1 package org.simantics.interop.mapping.data;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.Collection;\r
5 import java.util.HashSet;\r
6 import java.util.List;\r
7 import java.util.Set;\r
8 \r
9 import org.simantics.interop.mapping.Logger;\r
10 import org.simantics.utils.datastructures.hints.HintContext;\r
11 \r
12 \r
13 /**\r
14  * \r
15  * \r
16  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
17  *\r
18  * @param <T>\r
19  */\r
20 public class GraphNode<T> extends HintContext {\r
21         protected T data;\r
22         private List<Link<T>> nodes = new ArrayList<Link<T>>();\r
23 \r
24         private boolean disposed = false;\r
25         \r
26         public GraphNode(T data) {\r
27                 this.data = data;\r
28         }\r
29         \r
30         /**\r
31          * Returns data.\r
32          * @return\r
33          */\r
34         public T getData() {\r
35                 return data;\r
36         }\r
37 \r
38         \r
39         @Override\r
40     public void setHint(Key key, Object value) {\r
41                 _checkDisposed();\r
42                 if (value == null)\r
43                         return; \r
44                 super.setHint(key, value);\r
45         }\r
46         \r
47         \r
48         \r
49         \r
50         /**\r
51          * Adds link to the other node.\r
52          * @param relationName name of the link from this node to the other node.\r
53          * @param inverseRelationName nam,e of the link from the other node to this node.\r
54          * @param node the other node.\r
55          * @return the created link. Returns null if the link cannot be created.\r
56          */\r
57         public Link<T> addLink(String relationName, String inverseRelationName,GraphNode<T> node) {\r
58                 _checkDisposed();\r
59                 Logger.defaultLogInfo("Node link " + data + " " + node.data + " " + relationName + " " + inverseRelationName +"\n");\r
60                 if(containsLink(relationName, node) && node.containsLink(inverseRelationName, this)) {\r
61                         Logger.defaultLogWarning("Node " + getData() + " has already given child " +  node.getData() + " ,with name " + relationName + " / " + inverseRelationName);\r
62                         return null;\r
63                 }\r
64                 Link<T> rel = _addLink(relationName,node);\r
65                 Link<T> inv = node._addLink(inverseRelationName,this);\r
66                 rel.setInverseLink(inv);\r
67                 inv.setMainLink(rel);\r
68                 return rel;\r
69         }\r
70         \r
71         /**\r
72          * Adds link to the other node, with <pre>null</pre> link name from the other node to this node.\r
73          * @param relationName\r
74          * @param node name of the link from this node to the other node\r
75          * @return the created link. Returns null if the link cannot be created.\r
76          */\r
77         public Link<T> addLink(String relationName,GraphNode<T> node) {\r
78                 _checkDisposed();\r
79                 if(containsLink(relationName, node)) {\r
80                         Logger.defaultLogWarning("Node " + getData() + " has already given child " +  node.getData() + " ,with name " + relationName );\r
81                         return null;\r
82                 }\r
83                 Link<T> rel = _addLink(relationName,node);\r
84                 Link<T> inv = node._addLink(null,this);\r
85                 rel.setInverseLink(inv);\r
86                 inv.setMainLink(rel);\r
87                 return rel;\r
88         }\r
89         \r
90         /**\r
91          * Adds link to the other node, with copying link properties from given link.\r
92          * @param link\r
93          * @param node name of the link from this node to the other node\r
94          * @return the created link. Returns null if the link cannot be created.\r
95          */\r
96         public Link<T> addLink(Link<T> link ,GraphNode<T> node) {\r
97                 _checkDisposed();\r
98                 if(containsLink(link.getName(), node) && node.containsLink(link.getInverseName(), this)) {\r
99                         Logger.defaultLogWarning("Node " + getData() + " has already given child " +  node.getData() + " ,with name " + link.getName() + " / " + link.getInverseName());\r
100                         return null;\r
101                 }\r
102                 Link<T> rel = _addLink(link.getName(),node);\r
103                 Link<T> inv = node._addLink(link.getInverseName(),this);\r
104                 rel.setInverseLink(inv);\r
105                 inv.setMainLink(rel);\r
106                 rel.setHints(link.getHints());\r
107                 inv.setHints(link.getInverse().getHints());\r
108                 return rel;\r
109         }\r
110         \r
111         protected Link<T> _addLink(String relation,  GraphNode<T> node) {\r
112                 Link<T> link = new Link<T>(this, relation,node);\r
113                 nodes.add(link);\r
114                 return link;\r
115         }\r
116         \r
117         protected Link<T> _removeLink(String relation,String inverse, GraphNode<T> node) {\r
118                 for (int i = 0; i < nodes.size(); i++) {\r
119                         Link<T> link = nodes.get(i);\r
120                         if (node.equals(link.to()) && equals(relation,link.getName()) && equals(inverse,link.getInverseName())) {\r
121                                 return nodes.remove(i);\r
122                         }\r
123                 }\r
124                 return null;\r
125         }\r
126         \r
127         protected Link<T> _removeLink(String relation) {\r
128                 for (int i = 0; i < nodes.size(); i++) {\r
129                         Link<T> link = nodes.get(i);\r
130                         if (equals(relation,link.getName())) {\r
131                                 return nodes.remove(i);\r
132                         }\r
133                 }\r
134                 return null;\r
135         }\r
136         \r
137         protected Link<T> _removeLink(String relation, String inverse) {\r
138                 for (int i = 0; i < nodes.size(); i++) {\r
139                         Link<T> link = nodes.get(i);\r
140                         if (equals(relation,link.getName()) && equals(inverse,link.getInverseName())) {\r
141                                 return nodes.remove(i);\r
142                         }\r
143                 }\r
144                 return null;\r
145         }\r
146         \r
147         protected Link<T> _removeLink(String relation, GraphNode<T> node) {\r
148                 for (int i = 0; i < nodes.size(); i++) {\r
149                         Link<T> link = nodes.get(i);\r
150                         if (node.equals(link.to()) && equals(relation,link.getName())) {\r
151                                 return nodes.remove(i);\r
152                         }\r
153                 }\r
154                 return null;\r
155         }\r
156         \r
157         protected Link<T> _removeLink(GraphNode<T> node) {\r
158                 for (int i = 0; i < nodes.size(); i++ ) {\r
159                         Link<T> link = nodes.get(i);\r
160                         if (node.equals(link.to())) {\r
161                                 return nodes.remove(i);\r
162                         }\r
163                 }\r
164                 return null;\r
165         }\r
166         \r
167         protected boolean _removeLink(Link<T> link) {\r
168                 return nodes.remove(link);\r
169         }\r
170         \r
171         /**\r
172          * Removes the given link.\r
173          * @param link\r
174          * @return true if the link was removed.\r
175          */\r
176         public boolean removeLink(Link<T> link) {\r
177                 _checkDisposed();\r
178                 if (_removeLink(link)) {\r
179                         if (link.hasInverse()) {\r
180                                 link.to()._removeLink(link.getInverse());\r
181                         }\r
182                         return true;\r
183                 }\r
184                 return false;\r
185         }\r
186         \r
187         /**\r
188          * Removes a link (or multiple links).\r
189          * @param relation the name of the link from this node.\r
190          * @return true if a link was removed.\r
191          */\r
192         public boolean removeLink(String relation) {\r
193                 _checkDisposed();\r
194                 boolean deleted = false;\r
195                 while (true) {\r
196                         Link<T> removed = _removeLink(relation);\r
197                         if (removed == null)\r
198                                 break;\r
199                         if (removed.hasInverse()) {\r
200                                 removed.to()._removeLink(removed.getInverse());\r
201                                 deleted = true;\r
202                         }\r
203                 }\r
204                 return deleted;\r
205         }\r
206         \r
207         /**\r
208          * Removes a link (or multiple links).\r
209          * @param relation the name of the link from this node.\r
210          * @return true if the link was removed.\r
211          */\r
212         public boolean removeLink(String relation, String inverse) {\r
213                 _checkDisposed();\r
214                 boolean deleted = false;\r
215                 while (true) {\r
216                         Link<T> removed = _removeLink(relation, inverse);\r
217                         if (removed == null)\r
218                                 break;\r
219                         if (removed.hasInverse()) {\r
220                                 removed.to()._removeLink(removed.getInverse());\r
221                                 deleted = true;\r
222                         }\r
223                 }\r
224                 return deleted;\r
225         }\r
226 \r
227         /**\r
228          * Removes a link.\r
229          * @param relation the name of the link from this node to the other node.\r
230          * @param node the other node.\r
231          * @return true if the link was removed.\r
232          */\r
233         public boolean removeLink(String relation, GraphNode<T> node) {\r
234                 _checkDisposed();\r
235                 \r
236                 boolean deleted = false;\r
237                 while (true) {\r
238                         Link<T> removed = _removeLink(relation, node);\r
239                         if (removed == null)\r
240                                 break;\r
241                         if (removed.hasInverse()) {\r
242                                 removed.to()._removeLink(removed.getInverse());\r
243                                 deleted = true;\r
244                         }\r
245                 }\r
246                 return deleted;\r
247         }\r
248         \r
249         /**\r
250          * Removes all links from this node to the other node.\r
251          * @param node the other node.\r
252          * @return\r
253          */\r
254         public boolean removeLink(GraphNode<T> node) {\r
255                 _checkDisposed();\r
256                 boolean deleted = false;\r
257                 while (true) {\r
258                         Link<T> removed = _removeLink(node);\r
259                         if (removed == null)\r
260                                 break;\r
261                         if (removed.hasInverse()) {\r
262                                 removed.to()._removeLink(removed.getInverse());\r
263                                 deleted = true;\r
264                         }\r
265                 }\r
266                 return deleted;\r
267         }\r
268         \r
269         /**\r
270          * Removes a link.\r
271          * @param relation the name of the link from this node to the other node.\r
272          * @param inverse the name of the link from the other node to this node.\r
273          * @param node the other node.\r
274          * @return true if the link was removed.\r
275          */\r
276         public boolean removeLink(String relation, String inverse, GraphNode<T> node) {\r
277                 _checkDisposed();\r
278                 Link<T> removed = _removeLink(relation, inverse, node);\r
279                 if (removed != null && removed.hasInverse()) {\r
280                         removed.to()._removeLink(removed.getInverse());\r
281                         return true;\r
282                 }\r
283                 return false;\r
284         }\r
285         \r
286         public boolean containsLink(GraphNode<T> node) {\r
287                 _checkDisposed();\r
288                 for (Link<T> link : nodes) {\r
289                         if (node.equals(link.to()))\r
290                                 return true;\r
291                 }\r
292                 return false;\r
293         }\r
294         \r
295         public boolean containsLink(String relationName, GraphNode<T> node) {\r
296                 _checkDisposed();\r
297                 if (relationName == null)\r
298                         return false;\r
299                 for (Link<T> link : nodes) {\r
300                         if (node.equals(link.to()) && equals(relationName,link.getName()))\r
301                                 return true;\r
302                 }\r
303                 return false;\r
304         }\r
305         \r
306         public boolean containsLink(String relationName, String inverseName, GraphNode<T> node) {\r
307                 _checkDisposed();\r
308                 for (Link<T> link : nodes) {\r
309                         if (node.equals(link.to()) && equals(relationName,link.getName()) && equals(inverseName,link.getInverseName()))\r
310                                 return true;\r
311                 }\r
312                 return false;\r
313         }\r
314 \r
315         public Collection<Link<T>> getLinks() {\r
316                 _checkDisposed();\r
317                 Collection<Link<T>> coll = new ArrayList<Link<T>>(nodes);\r
318                 return coll;\r
319         }\r
320         \r
321         public Collection<GraphNode<T>> getNodes(String rel) {\r
322                 _checkDisposed();\r
323                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
324 \r
325                 for (Link<T> link : nodes) {\r
326                         if (equals(rel,link.getName()))\r
327                                 result.add(link.to());\r
328                 }\r
329                 \r
330                 return result;\r
331         }\r
332         \r
333         public Collection<Link<T>> getLinks(String rel) {\r
334                 _checkDisposed();\r
335                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
336 \r
337                 for (Link<T> link : nodes) {\r
338                         if (equals(rel,link.getName()))\r
339                                 result.add(link);\r
340                 }\r
341                 \r
342                 return result;\r
343         }\r
344         \r
345         public Collection<Link<T>> getLinks(String rel, GraphNode<T> node) {\r
346                 _checkDisposed();\r
347                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
348 \r
349                 for (Link<T> link : nodes) {\r
350                         if (equals(rel,link.getName()) && link.to().equals(node))\r
351                                 result.add(link);\r
352                 }\r
353                 \r
354                 return result;\r
355         }\r
356         \r
357         public Collection<Link<T>> getLinks(String rel, String inverse) {\r
358                 _checkDisposed();\r
359                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
360 \r
361                 for (Link<T> link : nodes) {\r
362                         if (equals(rel,link.getName()) && equals(inverse, link.getInverseName()))\r
363                                 result.add(link);\r
364                 }\r
365                 \r
366                 return result;\r
367         }\r
368         \r
369         public Collection<Link<T>> getLinks(String rel, String inverse, GraphNode<T> node) {\r
370                 _checkDisposed();\r
371                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
372 \r
373                 for (Link<T> link : nodes) {\r
374                         if (equals(rel,link.getName()) && equals(inverse, link.getInverseName()) && link.to().equals(node))\r
375                                 result.add(link);\r
376                 }\r
377                 \r
378                 return result;\r
379         }\r
380         \r
381         public Collection<GraphNode<T>> getNodesWithInv(String inv) {\r
382                 _checkDisposed();\r
383                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
384 \r
385                 for (Link<T> link : nodes) {\r
386                         if (equals(inv,link.getInverseName()))\r
387                                 result.add(link.to());\r
388                 }\r
389                 \r
390                 return result;\r
391         }\r
392         \r
393         public Collection<GraphNode<T>> getNodes(String rel, String inv) {\r
394                 _checkDisposed();\r
395                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
396 \r
397                 for (Link<T> link : nodes) {\r
398                         if (equals(rel,link.getName()) && equals(inv,link.getInverseName()))\r
399                                 result.add(link.to());\r
400                 }\r
401 \r
402                 return result;\r
403         }\r
404         \r
405         public static boolean equals(String s1, String s2) {\r
406                 if (s1 != null)\r
407                         return s1.equals(s2);\r
408                 if (s2 != null)\r
409                         return s2.equals(s1);\r
410                 return true; // both null\r
411         }\r
412         \r
413         \r
414         /**\r
415          * Returns links from this node to the given node.\r
416          * @param node\r
417          * @return\r
418          */\r
419         public Collection<Link<T>> getLinks(GraphNode<T> node) {\r
420                 _checkDisposed();\r
421                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
422                 for (Link<T> link : nodes) {\r
423                         if (link.to().equals(node))\r
424                                 result.add(link);\r
425                 }\r
426                 return result;\r
427         }\r
428         \r
429         /**\r
430          * Returns names of links from this node to the given node. Does not return null names.\r
431          * @param node\r
432          * @return\r
433          */\r
434         public Collection<String> getRelations(GraphNode<T> node) {\r
435                 _checkDisposed();\r
436                 Collection<String> result = new ArrayList<String>();\r
437                 for (Link<T> link : nodes) {\r
438                         if (link.to().equals(node) && link.getName() != null)\r
439                                 result.add(link.getName());\r
440                 }\r
441                 return result;\r
442         }\r
443         \r
444         /**\r
445          * Returns links from given node to this node.\r
446          * @param node\r
447          * @return\r
448          */\r
449         public Collection<Link<T>> getInverseLinks(GraphNode<T> node) {\r
450                 _checkDisposed();\r
451                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
452                 for (Link<T> link : nodes) {\r
453                         if (link.to().equals(node))\r
454                                 result.add(link.getInverse());\r
455                 }\r
456                 return result;\r
457         }\r
458         \r
459         /**\r
460          * Returns names of links from given node to this node. Does not return null names.\r
461          * @param node\r
462          * @return\r
463          */\r
464         public Collection<String> getInverses(GraphNode<T> node) {\r
465                 _checkDisposed();\r
466                 Collection<String> result = new ArrayList<String>();\r
467                 for (Link<T> link : nodes) {\r
468                         if (link.to().equals(node) && link.getInverseName() != null)\r
469                                 result.add(link.getInverseName());\r
470                 }\r
471                 return result;\r
472         }\r
473         \r
474         \r
475         \r
476         @Override\r
477         public int hashCode() {\r
478                 return data.hashCode();\r
479         }\r
480         \r
481         @Override\r
482         public boolean equals(Object arg0) {\r
483                 if (!arg0.getClass().equals(getClass()))\r
484                         return false;\r
485                 GraphNode<?> other = (GraphNode<?>)arg0;\r
486                 if (this == other)\r
487                         return true;\r
488                 if (this.data == null || other.data == null)\r
489                         return false;\r
490                 if (!data.equals(other.data))\r
491                         return false;\r
492 \r
493                 return true;\r
494         }\r
495         \r
496         /**\r
497          * Merges given nodes to new node. \r
498          * Does not copy hints!\r
499          * @param other\r
500          */\r
501         public GraphNode<T> merge(GraphNode<T> other, T mergedData) {\r
502                 _checkDisposed();\r
503                 GraphNode<T> mergedNode = new GraphNode<T>(mergedData);\r
504                 copyLinks(this, mergedNode);\r
505                 copyLinks(other, mergedNode);\r
506                 \r
507                 //mergedNode.setHints(other.getHints());\r
508                 //mergedNode.setHints(this.getHints());\r
509                 \r
510                 this.destroy();\r
511                 other.destroy();\r
512                 \r
513                 return mergedNode;\r
514         }\r
515         \r
516         \r
517         \r
518         \r
519         \r
520         /**\r
521          * Copies a link to other node.\r
522          * @param from the node containing original link\r
523          * @param to the node where link is copied to\r
524          * @param l the link that is copied.\r
525          * @return created link, if copy is successful. Otherwise returns null.\r
526          */\r
527         public static <T> Link<T> copyLink(GraphNode<T> from, GraphNode<T> to, Link<T> l) {\r
528                 if (l.from() != from)\r
529                         throw new IllegalArgumentException("Link is not starting from " + from + " node.");\r
530                 if (l.to() == to)\r
531                         return null;\r
532                 if (to.containsLink(l.getName(), l.getInverseName(),l.to()))\r
533                         return null;\r
534                 if (l.isMain()) {\r
535                         Link<T> newLink = to.addLink(l.getName(),l.getInverseName(),l.to());\r
536                         if (newLink != null) {\r
537                                 newLink.setHints(l.getHints());\r
538                                 newLink.getInverse().setHints(l.getInverse().getHints());\r
539                                 return newLink;\r
540                         } else {\r
541                                 return null;\r
542                         }\r
543                 } else {\r
544                         Link<T> newLink = l.to().addLink(l.getInverseName(), l.getName(),to);\r
545                         if (newLink != null) {\r
546                                 newLink.setHints(l.getInverse().getHints());\r
547                                 newLink.getInverse().setHints(l.getHints());\r
548                                 return newLink.getInverse();\r
549                         } else {\r
550                                 return null;\r
551                         }\r
552                 }       \r
553                 \r
554         }\r
555         \r
556         /**\r
557          * Copies a link to other node, but inverts its direction.\r
558          * @param from the node containing original link\r
559          * @param to the node where link is copied to\r
560          * @param l the link that is copied.\r
561          * @return created link, if copy is successful. Otherwise returns null.\r
562          */\r
563         public static <T> Link<T> copyLinkInverse(GraphNode<T> from, GraphNode<T> to, Link<T> l) {\r
564                 if (l.from() != from)\r
565                         throw new IllegalArgumentException("Link is not starting from " + from + " node.");\r
566                 if (l.to() == to)\r
567                         return null;\r
568                 if (to.containsLink(l.getInverseName(), l.getName(),l.to()))\r
569                         return null;\r
570                 if (l.isMain()) {\r
571                         Link<T> newLink = l.to().addLink(l.getName(),l.getInverseName(),to);\r
572                         if (newLink != null) {\r
573                                 newLink.setHints(l.getHints());\r
574                                 newLink.getInverse().setHints(l.getInverse().getHints());\r
575                                 return newLink;\r
576                         } else {\r
577                                 return null;\r
578                         }\r
579                 } else {\r
580                         Link<T> newLink = to.addLink(l.getInverseName(), l.getName(),l.to());\r
581                         if (newLink != null) {\r
582                                 newLink.setHints(l.getInverse().getHints());\r
583                                 newLink.getInverse().setHints(l.getHints());\r
584                                 return newLink.getInverse();\r
585                         } else {\r
586                                 return null;\r
587                         }\r
588                 }       \r
589                 \r
590         }\r
591 \r
592         public static <T> void copyLinks(GraphNode<T> from, GraphNode<T> to, Collection<Link<T>> links) {\r
593                 for (Link<T> l : links) {\r
594                         copyLink(from, to, l);\r
595                 }\r
596         }\r
597 \r
598         \r
599         public static <T> void copyLinks(GraphNode<T> from, GraphNode<T> to) {\r
600                 for (Link<T> l : from.getLinks()) {\r
601                         copyLink(from, to, l);\r
602                 }\r
603         }\r
604         \r
605         /**\r
606          * Copies a link to other node and removes the original link. If move is not successful, the original link is not removed.\r
607          * @param from the node containing original link\r
608          * @param to the node where link is copied to\r
609          * @param l the link that is moved.\r
610          * @return created link, if move is successful. Otherwise returns null. \r
611          */\r
612         public static <T> Link<T> moveLink(GraphNode<T> from, GraphNode<T> to, Link<T> l) {\r
613                 Link<T> newLink = copyLink(from, to, l);\r
614                 if (newLink != null) {\r
615                         from.removeLink(l);\r
616                         return newLink;\r
617                 }\r
618                 return null;\r
619         }\r
620         \r
621         public static <T> void moveLinks(GraphNode<T> from, GraphNode<T> to, Collection<Link<T>> links) {\r
622                 for (Link<T> l : links) {\r
623                         Link<T> newLink = copyLink(from, to, l);\r
624                         if (newLink != null) {\r
625                                 from.removeLink(l);\r
626                         }       \r
627                 }\r
628         }\r
629         \r
630         public static <T> void moveLinkInverses(GraphNode<T> from, GraphNode<T> to, Collection<Link<T>> links) {\r
631                 for (Link<T> l : links) {\r
632                         Link<T> newLink = copyLinkInverse(from, to, l);\r
633                         if (newLink != null) {\r
634                                 from.removeLink(l);\r
635                         }       \r
636                 }\r
637         }\r
638         \r
639         public static <T> void moveLinks(GraphNode<T> from, GraphNode<T> to) {\r
640                 for (Link<T> l : from.getLinks()) {\r
641                         Link<T> newLink = copyLink(from, to, l);\r
642                         if (newLink != null) {\r
643                                 from.removeLink(l);\r
644                         }       \r
645                 }\r
646         }\r
647         \r
648         /**\r
649          * Replaces a link with a link going first to given node, and the to the original destination.\r
650          * The link names and hints are copied to the created links.\r
651          * \r
652          * Example: link is 'a' -> 'b'. With insert attribute 'c', the result is 'a' -> 'c' -> 'b'.\r
653          *   \r
654          * @param link\r
655          * @param insert\r
656          * @return Array containing created links (2).\r
657          */\r
658         @SuppressWarnings("unchecked")\r
659         public static <T> Link<T>[] insert(Link<T> link, GraphNode<T> insert) {\r
660                 GraphNode<T> a = link.from();\r
661                 Link<T> c_b = moveLink(a, insert, link);\r
662                 Link<T> a_c = a.addLink(c_b, insert);\r
663                 return new Link[]{a_c,c_b};\r
664         }\r
665 \r
666         \r
667         \r
668         /**\r
669          * Finds all nodes that have the same relations to the same nodes as this node. \r
670          * @return\r
671          */\r
672         public Collection<GraphNode<T>> getFullSimilars() {\r
673                 _checkDisposed();\r
674                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
675                 Set<GraphNode<T>> potential = new HashSet<GraphNode<T>>();\r
676                 for (Link<T> link : nodes) {\r
677                         for (Link<T> link2 : link.to().nodes) {\r
678                                 if (!link2.to().equals(this))\r
679                                         potential.add(link2.to());\r
680                         }\r
681                 }\r
682                 for (GraphNode<T> node : potential) {\r
683                         if (node.nodes.containsAll(nodes))\r
684                                 result.add(node);\r
685                 }\r
686                 \r
687                 return result;\r
688         }\r
689         \r
690         /**\r
691          * Finds all nodes that have at least one similar relation to the same nodes as this node. \r
692          * @return\r
693          */\r
694         public Collection<GraphNode<T>> getSemiSimilars() {\r
695                 _checkDisposed();\r
696                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
697                 Set<GraphNode<T>> potential = new HashSet<GraphNode<T>>();\r
698                 for (Link<T> link : nodes) {\r
699                         for (Link<T> link2 : link.to().nodes) {\r
700                                 if (!link2.to().equals(this))\r
701                                         potential.add(link2.to());\r
702                         }\r
703                 }\r
704                 for (GraphNode<T> node : potential) {\r
705                         for (Link<T> link : nodes) {\r
706                                 if (node.nodes.contains(link))\r
707                                         result.add(node);\r
708                         }\r
709                 }\r
710                 \r
711                 return result;\r
712         }\r
713         \r
714 \r
715         /**\r
716          * Disposes this node. Removes all the links that connect to this node.\r
717          */\r
718         public void destroy() {\r
719                 if (disposed)\r
720                         return;\r
721                 Logger.defaultLogInfo("Node destroy " + data + " " + this);\r
722                 Collection<Link<T>> coll = new ArrayList<Link<T>>();\r
723                 coll.addAll(nodes);\r
724                 nodes.clear();\r
725                 for (Link<T> link : coll) {\r
726                         link.to()._removeLink(this);\r
727                 }\r
728                 nodes = null;\r
729                 disposed = true;\r
730         }\r
731         \r
732         /**\r
733          * Removes this node from the graph, and reconnects parents and children of this node.\r
734          */\r
735         public void remove() {\r
736                 if (disposed)\r
737                         return;\r
738                 // FIXME: link.to may be *this.\r
739                 Logger.defaultLogInfo("Node remove " + data + " " + this);\r
740                 if (nodes.size() == 1) {\r
741                         Link<T> link = nodes.get(0);\r
742                         link.to().removeLink(link.getInverseName(), link.getName(), this);\r
743                 } else {\r
744                         for (int i = 0; i < nodes.size() -1 ; i++) {\r
745                                 Link<T> link1 = nodes.get(i);\r
746                                 link1.to()._removeLink(link1.getInverseName(), link1.getName(), this);\r
747                                 for (int j = i+1; j < nodes.size(); j++) {\r
748                                         Link<T> link2 = nodes.get(j);\r
749                                         link2.to()._removeLink(link2.getInverseName(), link2.getName(), this);\r
750                                         if (link1.to().equals(link2.to()))\r
751                                                 continue;\r
752                                         link1.to().addLink(link1.getInverseName(),link2.getInverseName(),link2.to());\r
753                                 }\r
754                                 \r
755                         }\r
756                 }\r
757                 \r
758                 nodes.clear();\r
759                 nodes = null;\r
760                 disposed = true;\r
761 \r
762         }\r
763         \r
764         /**\r
765          * \r
766          * @return true if the node has been disposed and cannot be used anymore.\r
767          */\r
768         public boolean isDisposed() {\r
769                 return disposed;\r
770         }\r
771         \r
772         /**\r
773          * Dispose the node and all nodes that are in the same graph.\r
774          */\r
775         public void dispose() {\r
776                 if (disposed)\r
777                         return;\r
778                 Collection<Link<T>> links = new ArrayList<Link<T>>();\r
779                 links.addAll(nodes);\r
780                 nodes.clear();\r
781                 for (Link<T> l : links)\r
782                         l.to().dispose();\r
783                 links.clear();\r
784                 nodes = null;\r
785                 disposed = true;\r
786         }\r
787         \r
788 \r
789         protected void _checkDisposed() {\r
790                 if (disposed) {\r
791                         Logger.defaultLogError("Remove Node, disposed " + this);\r
792                         throw new RuntimeException("Node " + this + " is disposed.");\r
793                 }\r
794         }\r
795         \r
796         \r
797         public int distanceTo(GraphNode<T> node, String rel, String inv) {\r
798                 if (node.equals(this))\r
799                         return 0;\r
800                 int count = 0;\r
801                 Set<GraphNode<T>> processed = new HashSet<GraphNode<T>>();\r
802                 Set<GraphNode<T>> next = new HashSet<GraphNode<T>>();\r
803                 next.add(this);\r
804                 while (true) {\r
805                         if (next.size() == 0)\r
806                                 return -1;\r
807                         count++;\r
808                         processed.addAll(next);\r
809                         Set<GraphNode<T>> nextNext = new HashSet<GraphNode<T>>();\r
810                         for (GraphNode<T> n : next) {\r
811                                 for (GraphNode<T> nn : n.getNodes(rel, inv))\r
812                                         if (!processed.contains(nn))\r
813                                                 nextNext.add(nn);\r
814                         }\r
815                         next = nextNext;\r
816                         if (next.contains(node))\r
817                                 return count;\r
818                 }\r
819         }\r
820         \r
821         public String toString() {\r
822                 return "Node : " + data;\r
823         }\r
824 }\r