package jalview.ext.archaeopteryx;
-import jalview.ext.treeviewer.ExternalTreeNodeI;
+import jalview.datamodel.SequenceI;
+import jalview.ext.forester.DataConversions;
+import jalview.ext.treeviewer.TreeNodeI;
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import org.forester.phylogeny.PhylogenyMethods;
import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.BranchColor;
-public class TreeNode implements ExternalTreeNodeI
+public class TreeNode implements TreeNodeI
{
private final PhylogenyNode node;
- public TreeNode(PhylogenyNode aptxNode)
+ private SequenceI nodeSeq;
+
+ private static Map<PhylogenyNode, TreeNodeI> originalNodes = new HashMap<>(
+ 500); // prolly make this size dynamic
+
+ private static Map<TreeNodeI, PhylogenyNode> wrappedNodes = new HashMap<>(
+ 500);
+
+ private TreeNode(PhylogenyNode aptxNode)
{
node = aptxNode;
+ if (aptxNode.getNodeData().getSequence() != null)
+ {
+ nodeSeq = DataConversions
+ .createJalviewSequence(aptxNode.getNodeData().getSequence());
+ }
+ originalNodes.put(aptxNode, this);
+ wrappedNodes.put(this, aptxNode);
+
}
+
@Override
- public PhylogenyNode getOriginalNode()
+ public String getNodeName()
{
- return node;
+ return node.getName();
}
+
@Override
- public String getNodeName()
+ public List<TreeNodeI> getAllDescendants()
{
- return node.getName();
+
+ List<PhylogenyNode> descNodes = PhylogenyMethods
+ .getAllDescendants(node);
+ return getUniqueWrappers(descNodes);
+
+
+ }
+
+ @Override
+ public List<TreeNodeI> getExternalDescendants()
+ {
+ List<PhylogenyNode> extDescNodes = node.getAllExternalDescendants();
+ return getUniqueWrappers(extDescNodes);
}
+
@Override
- public List<ExternalTreeNodeI> getChildren()
+ public List<TreeNodeI> getDirectChildren()
{
- // return node.getDescendants();
- return null;
+ List<PhylogenyNode> childNodes = node.getDescendants();
+ return getUniqueWrappers(childNodes);
+
}
+
+ @Override
+ public void setSequence(SequenceI seq)
+ {
+ nodeSeq = seq;
+ org.forester.phylogeny.data.Sequence foresterFormatSeq = DataConversions
+ .createForesterSequence(seq, true);
+ node.getNodeData().setSequence(foresterFormatSeq);
+
+ }
+
+ @Override
+ public SequenceI getSequence()
+ {
+ return nodeSeq;
+ }
+
+ @Override
+ public void addAsChild(TreeNodeI childNode)
+ {
+ PhylogenyNode aptxNode = unwrapNode(childNode);
+
+ node.addAsChild(aptxNode);
+
+ }
+
+ @Override
+ public long getId()
+ {
+ return node.getId();
+ }
+
+ @Override
+ public float getXcoord()
+ {
+ return node.getXcoord();
+ }
+
+ @Override
+ public void setBranchColor(Color branchColor)
+ {
+ node.getBranchData().setBranchColor(new BranchColor(branchColor));
+
+ }
+
+ @Override
+ public boolean isInternal()
+ {
+ return node.isInternal();
+ }
+
+ public static List<TreeNodeI> getUniqueWrappers(
+ List<PhylogenyNode> aptxNodes)
+ {
+ List<TreeNodeI> wrappedNodes = new ArrayList<>(
+ aptxNodes.size());
+
+ for (PhylogenyNode aptxNode : aptxNodes)
+ {
+ wrappedNodes.add(getUniqueWrapper(aptxNode));
+ }
+ return wrappedNodes;
+ }
+
+ /**
+ * This method should be used to create new wrappers as there is a possibility
+ * the Archaeopteryx node was already introduced to Jalview previously so this
+ * avoids giving one node duplicate wrappers
+ *
+ * @param aptxNode
+ * @return
+ */
+ public static TreeNodeI getUniqueWrapper(
+ PhylogenyNode aptxNode)
+ {
+ if (aptxNode == null)
+ {
+ return null;
+ }
+ TreeNodeI wrappedNode = originalNodes.get(aptxNode);
+ if (wrappedNode == null)
+ {
+ wrappedNode = new TreeNode(aptxNode);
+ }
+ return wrappedNode;
+ }
+
+ /**
+ * Attempts to unwrap the given node, if the unwrapped node already exists it
+ * is simply returned as is. If it is not however, the wrapper will be used to
+ * create a new Archaeopteryx node. This way it becomes possible to construct
+ * new Archaeopteryx nodes from different tree viewers, as long as they
+ * implement the interface.
+ *
+ * @param wrappedNode
+ * @return
+ */
+ protected static PhylogenyNode unwrapNode(TreeNodeI wrappedNode)
+ {
+ if (wrappedNode == null)
+ {
+ return null;
+ }
+ PhylogenyNode aptxNode = wrappedNodes.get(wrappedNode);
+ if (aptxNode == null)
+ {
+ // expand this
+ aptxNode = new PhylogenyNode(wrappedNode.getNodeName());
+
+ }
+ return aptxNode;
+
+ }
+
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = (int) (prime * result
+ + ((node == null) ? 0 : (node.hashCode() * getId())));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ TreeNode other = (TreeNode) obj;
+ if (node == null)
+ {
+ if (other.node != null)
+ {
+ return false;
+ }
+ }
+ if (getId() != other.getId())
+ {
+ return false;
+ }
+
+ if (!node.equals(other.node))
+ {
+ return false;
+ }
+ return true;
+ }
+
+
+ @Override
+ public float getYcoord()
+ {
+ return node.getYcoord();
+ }
+
}