JAL-1953 2.11.2 with Archeopteryx!
[jalview.git] / src / jalview / ext / archaeopteryx / TreeNode.java
index 8e06d6c..0844171 100644 (file)
 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;
 
-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);
+
+  /**
+   * Please don't use me directly.
+   * 
+   * @param aptxNode
+   */
+  private TreeNode(PhylogenyNode aptxNode)
   {
     node = aptxNode;
+    if (aptxNode.getNodeData().getSequence() != null)
+    {
+    nodeSeq = DataConversions
+              .createJalviewSequence(aptxNode);
+    }
+    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<TreeNodeI> getDirectChildren()
+  {
+    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)
+  {
+    PhylogenyMethods.setBranchColorValue(node, branchColor);
+
   }
 
   @Override
-  public List<ExternalTreeNodeI> getChildren()
+  public boolean isInternal()
   {
-    // return node.getDescendants();
-    return null;
+    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();
+  }
+
+  @Override
+  public boolean isCollapsed()
+  {
+    return node.isCollapse();
+  }
 
 }