--- /dev/null
+package jalview.ext.archaeopteryx;
+
+import jalview.analysis.TreeBuilder;
+import jalview.datamodel.SequenceI;
+import jalview.ext.forester.DataConversions;
+import jalview.ext.forester.ForesterMatrix;
+import jalview.ext.treeviewer.ExternalTreeBuilderI;
+import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.forester.evoinference.matrix.distance.DistanceMatrix;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.NodeData;
+import org.forester.phylogeny.data.Sequence;
+
+/**
+ * Class for converting trees made in Jalview (through TreeBuilder) to trees
+ * compatible with Forester (Phylogeny objects).
+ *
+ * Note that this currently demands a 1:1 relationship between tree nodes and
+ * the sequences used for generating them.
+ *
+ * @author kjvanderheide
+ *
+ */
+public class AptxTreeBuilder
+ implements ExternalTreeBuilderI<Phylogeny, PhylogenyNode>
+{
+ protected final SequenceI[] sequences;
+
+ protected final DistanceMatrix distances;
+
+ protected final TreeBuilder jalviewTree;
+
+ public String treeTitle;
+
+ private final Phylogeny aptxTree;
+
+ private PhylogenyNode rootNode;
+
+ private final Map<SequenceI, PhylogenyNode> alignmentWithNodes;
+
+ private final Map<PhylogenyNode, SequenceI> nodesWithAlignment;
+
+ public AptxTreeBuilder(final TreeBuilder calculatedTree)
+ {
+ jalviewTree = calculatedTree;
+ sequences = jalviewTree.getSequences();
+ distances = ForesterMatrix.convertJalviewToForester(
+ jalviewTree.getDistances(), sequences);
+
+ aptxTree = new Phylogeny();
+ rootNode = new PhylogenyNode();
+
+ int amountOfSequences = distances.getSize();
+ alignmentWithNodes = new HashMap<>(amountOfSequences);
+ nodesWithAlignment = new HashMap<>(amountOfSequences);
+
+
+ }
+
+ @Override
+ public Phylogeny buildTree(final PhylogenyNode treeRoot)
+ {
+
+ if (treeRoot != null)
+ {
+ rootNode = treeRoot;
+ }
+
+ buildTree();
+
+ return aptxTree;
+
+ }
+
+
+ @Override
+ public Phylogeny buildTree()
+ {
+
+ for (SequenceI sequence : sequences)
+ {
+ Sequence seq = DataConversions
+ .createForesterSequence(sequence, true);
+ PhylogenyNode sequenceNode = new PhylogenyNode(sequence.getName());
+
+ NodeData nodeData = sequenceNode.getNodeData();
+ nodeData.setSequence(seq);
+
+ MappingUtils.putWithDuplicationCheck(nodesWithAlignment,
+ sequenceNode, sequence);
+ MappingUtils.putWithDuplicationCheck(alignmentWithNodes,
+ sequence, sequenceNode);
+ rootNode.addAsChild(sequenceNode);
+ }
+
+
+ aptxTree.setRoot(rootNode);
+
+ treeTitle = generateTreeName();
+ aptxTree.setName(treeTitle);
+
+ return aptxTree;
+
+ }
+
+ @Override
+ public Map<SequenceI, PhylogenyNode> getAlignmentBoundNodes()
+ {
+ return alignmentWithNodes;
+ }
+
+ @Override
+ public Map<PhylogenyNode, SequenceI> getNodesBoundAlignment()
+ {
+ return nodesWithAlignment;
+ }
+
+ private Phylogeny clusterNodes()
+ {
+ return aptxTree;
+
+ }
+ /**
+ * Formats a localised title for the tree panel, like
+ * <p>
+ * Neighbour Joining Using BLOSUM62
+ * <p>
+ * For a tree loaded from file, just uses the file name
+ *
+ * @return
+ */
+ @Override
+ public String generateTreeName() // Move this and add selection region to the
+ // title when applicable
+ {
+ if (treeTitle != null) // will currently never happen, loaded tree file will
+ // take a different path
+ {
+ return treeTitle;
+ }
+ else
+ {
+ /*
+ * i18n description of Neighbour Joining or Average Distance method
+ */
+ String treecalcnm = MessageManager
+ .getString("label.tree_calc_" + jalviewTree.getClass()
+ .getSimpleName().substring(0, 2).toLowerCase());
+ /*
+ * short score model name (long description can be too long)
+ */
+ String smn = jalviewTree.getScoreModel().getName();
+
+ /*
+ * put them together as <method> Using <model>
+ */
+ final String ttl = MessageManager
+ .formatMessage("label.treecalc_title", treecalcnm, smn);
+ return ttl;
+ }
+ }
+
+
+}