e37f89d43828b26fef2ddc145094240fc894e7e0
[jalview.git] / src / jalview / ext / archaeopteryx / TreeNode.java
1 package jalview.ext.archaeopteryx;
2
3 import jalview.datamodel.SequenceI;
4 import jalview.ext.treeviewer.ExternalTreeNodeI;
5
6 import java.awt.Color;
7 import java.util.ArrayList;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11
12 import org.forester.phylogeny.PhylogenyMethods;
13 import org.forester.phylogeny.PhylogenyNode;
14 import org.forester.phylogeny.data.BranchColor;
15
16 public class TreeNode implements ExternalTreeNodeI
17 {
18   private final PhylogenyNode node;
19
20   private SequenceI nodeSeq;
21
22   private static Map<PhylogenyNode, ExternalTreeNodeI> originalNodes = new HashMap<>(
23           500); // prolly make this size dynamic
24
25   private static Map<ExternalTreeNodeI, PhylogenyNode> wrappedNodes = new HashMap<>(
26           500);
27
28   private TreeNode(PhylogenyNode aptxNode)
29   {
30     node = aptxNode;
31     originalNodes.put(aptxNode, this);
32     wrappedNodes.put(this, aptxNode);
33
34   }
35
36
37   @Override
38   public String getNodeName()
39   {
40     return node.getName();
41   }
42
43
44   @Override
45   public List<ExternalTreeNodeI> getAllDescendants()
46   {
47
48     List<PhylogenyNode> descNodes = PhylogenyMethods
49             .getAllDescendants(node);
50     return getUniqueWrappers(descNodes);
51     
52
53   }
54
55   @Override
56   public List<ExternalTreeNodeI> getExternalDescendants()
57   {
58     List<PhylogenyNode> extDescNodes = node.getAllExternalDescendants();
59     return getUniqueWrappers(extDescNodes);
60   }
61
62
63   @Override
64   public List<ExternalTreeNodeI> getDirectChildren()
65   {
66     List<PhylogenyNode> childNodes = node.getDescendants();
67     return getUniqueWrappers(childNodes);
68     
69
70   }
71
72
73
74   @Override
75   public void setSequence(SequenceI seq)
76   {
77     nodeSeq = seq;
78     org.forester.phylogeny.data.Sequence foresterFormatSeq = DataConversions
79             .createForesterSequence(seq, true);
80     node.getNodeData().setSequence(foresterFormatSeq);
81
82   }
83
84   @Override
85   public SequenceI getSequence()
86   {
87     return nodeSeq;
88     // ideally this would return a converted node.getNodeData().getSequence()
89   }
90
91   @Override
92   public void addAsChild(ExternalTreeNodeI childNode)
93   {
94     PhylogenyNode aptxNode = unwrapNode(childNode);
95
96     node.addAsChild(aptxNode);
97
98   }
99
100   @Override
101   public long getId()
102   {
103     return node.getId();
104   }
105
106   @Override
107   public float getXcoord()
108   {
109     return node.getXcoord();
110   }
111
112   @Override
113   public void setBranchColor(Color branchColor)
114   {
115     node.getBranchData().setBranchColor(new BranchColor(branchColor));
116
117   }
118
119   @Override
120   public boolean isInternal()
121   {
122     return node.isInternal();
123   }
124
125   public static List<ExternalTreeNodeI> getUniqueWrappers(
126           List<PhylogenyNode> aptxNodes)
127   {
128     List<ExternalTreeNodeI> wrappedNodes = new ArrayList<>(
129             aptxNodes.size());
130
131     for (PhylogenyNode aptxNode : aptxNodes)
132     {
133       wrappedNodes.add(getUniqueWrapper(aptxNode));
134     }
135     return wrappedNodes;
136   }
137
138   /**
139    * This method should be used to create new wrappers as there is a possibility
140    * the Archaeopteryx node was already introduced to Jalview previously so this
141    * avoids giving one node duplicate wrappers
142    * 
143    * @param aptxNode
144    * @return
145    */
146   public static ExternalTreeNodeI getUniqueWrapper(
147           PhylogenyNode aptxNode)
148   {
149     if (aptxNode == null)
150     {
151       return null;
152     }
153     ExternalTreeNodeI wrappedNode = originalNodes.get(aptxNode);
154     if (wrappedNode == null)
155     {
156       wrappedNode = new TreeNode(aptxNode);
157     }
158     return wrappedNode;
159   }
160
161   /**
162    * Attempts to unwrap the given node, if the unwrapped node already exists it
163    * is simply returned as is. If it is not however, the wrapper will be used to
164    * create a new Archaeopteryx node. This way it becomes possible to construct
165    * new Archaeopteryx nodes from different tree viewers, as long as they
166    * implement the interface.
167    * 
168    * @param wrappedNode
169    * @return
170    */
171   protected static PhylogenyNode unwrapNode(ExternalTreeNodeI wrappedNode)
172   {
173     if (wrappedNode == null)
174     {
175       return null;
176     }
177     PhylogenyNode aptxNode = wrappedNodes.get(wrappedNode);
178     if (aptxNode == null)
179     {
180       // expand this
181       aptxNode = new PhylogenyNode(wrappedNode.getNodeName());
182
183     }
184     return aptxNode;
185
186   }
187
188
189   @Override
190   public int hashCode()
191   {
192     final int prime = 31;
193     int result = 1;
194     result = (int) (prime * result
195             + ((node == null) ? 0 : (node.hashCode() * getId())));
196     return result;
197   }
198
199   @Override
200   public boolean equals(Object obj)
201   {
202     if (this == obj)
203     {
204       return true;
205     }
206     if (obj == null)
207     {
208       return false;
209     }
210     if (getClass() != obj.getClass())
211     {
212       return false;
213     }
214     TreeNode other = (TreeNode) obj;
215     if (node == null)
216     {
217       if (other.node != null)
218       {
219         return false;
220       }
221     }
222     if (getId() != other.getId())
223     {
224       return false;
225     }
226
227     if (!node.equals(other.node))
228     {
229       return false;
230     }
231     return true;
232   }
233
234
235   @Override
236   public float getYcoord()
237   {
238     return node.getYcoord();
239   }
240
241 }