searhc of domains only when domains are shown!
[jalview.git] / forester / java / src / org / forester / phylogeny / Phylogeny.java
index a3277ba..a4102d2 100644 (file)
@@ -7,7 +7,7 @@
 // Copyright (C) 2000-2001 Washington University School of Medicine
 // and Howard Hughes Medical Institute
 // All rights reserved
-// 
+//
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
@@ -17,7 +17,7 @@
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 // Lesser General Public License for more details.
-// 
+//
 // You should have received a copy of the GNU Lesser General Public
 // License along with this library; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -39,9 +39,11 @@ import java.util.NoSuchElementException;
 import java.util.Vector;
 
 import org.forester.io.writers.PhylogenyWriter;
+import org.forester.phylogeny.PhylogenyNodeI.NH_CONVERSION_SUPPORT_VALUE_STYLE;
 import org.forester.phylogeny.data.BranchData;
 import org.forester.phylogeny.data.Confidence;
 import org.forester.phylogeny.data.Identifier;
+import org.forester.phylogeny.data.PhylogenyDataUtil;
 import org.forester.phylogeny.data.Sequence;
 import org.forester.phylogeny.data.SequenceRelation;
 import org.forester.phylogeny.data.SequenceRelation.SEQUENCE_RELATION_TYPE;
@@ -66,7 +68,7 @@ public class Phylogeny {
     private Confidence                                          _confidence;
     private Identifier                                          _identifier;
     private boolean                                             _rerootable;
-    private HashMap<Integer, PhylogenyNode>                     _idhash;
+    private HashMap<Integer, PhylogenyNode>                     _id_to_node_map;
     private List<PhylogenyNode>                                 _external_nodes_set;
     private Collection<Sequence>                                _sequenceRelationQueries;
     private Collection<SequenceRelation.SEQUENCE_RELATION_TYPE> _relevant_sequence_relation_types;
@@ -111,7 +113,7 @@ public class Phylogeny {
         new_node.setParent( sibling_parent );
         sibling.setParent( new_node );
         sibling_parent.setChildNode( sibling_index, new_node );
-        final double new_dist = sibling.getDistanceToParent() == PhylogenyNode.DISTANCE_DEFAULT ? PhylogenyNode.DISTANCE_DEFAULT
+        final double new_dist = sibling.getDistanceToParent() == PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ? PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT
                 : sibling.getDistanceToParent() / 2;
         new_node.setDistanceToParent( new_dist );
         sibling.setDistanceToParent( new_dist );
@@ -211,7 +213,7 @@ public class Phylogeny {
     }
 
     /**
-     * Need the delete and/or rehash _idhash (not done automatically
+     * Need to call clearHashIdToNodeMap() afterwards (not done automatically
      * to allow client multiple deletions in linear time).
      * Need to call 'recalculateNumberOfExternalDescendants(boolean)' after this 
      * if tree is to be displayed.
@@ -219,14 +221,13 @@ public class Phylogeny {
      * @param remove_us the parent node of the subtree to be deleted
      */
     public void deleteSubtree( final PhylogenyNode remove_us, final boolean collapse_resulting_node_with_one_desc ) {
-        if ( isEmpty() ) {
+        if ( isEmpty() || ( remove_us.isRoot() && ( getNumberOfExternalNodes() != 1 ) ) ) {
             return;
         }
-        if ( remove_us.isRoot() ) {
+        if ( remove_us.isRoot() && ( getNumberOfExternalNodes() == 1 ) ) {
             init();
-            return;
         }
-        if ( !collapse_resulting_node_with_one_desc ) {
+        else if ( !collapse_resulting_node_with_one_desc ) {
             remove_us.getParent().removeChildNode( remove_us );
         }
         else {
@@ -267,8 +268,7 @@ public class Phylogeny {
                 }
             }
         }
-        remove_us.setParent( null );
-        setIdHash( null );
+        remove_us.removeConnections();
         externalNodesHaveChanged();
     }
 
@@ -375,11 +375,8 @@ public class Phylogeny {
         return _identifier;
     }
 
-    // ---------------------------------------------------------
-    // Modification of Phylogeny topology and Phylogeny appearance
-    // ---------------------------------------------------------
-    private HashMap<Integer, PhylogenyNode> getIdHash() {
-        return _idhash;
+    private HashMap<Integer, PhylogenyNode> getIdToNodeMap() {
+        return _id_to_node_map;
     }
 
     /**
@@ -391,29 +388,16 @@ public class Phylogeny {
 
     /**
      * Finds the PhylogenyNode of this Phylogeny which has a matching ID number.
-     * Takes O(n) time. After method hashIDs() has been called it runs in
-     * constant time.
-     * 
-     * @param id
-     *            ID number (int) of the PhylogenyNode to find
      * @return PhylogenyNode with matching ID, null if not found
      */
     public PhylogenyNode getNode( final int id ) throws NoSuchElementException {
         if ( isEmpty() ) {
             throw new NoSuchElementException( "attempt to get node in an empty phylogeny" );
         }
-        if ( _idhash != null ) {
-            return _idhash.get( id );
+        if ( ( getIdToNodeMap() == null ) || getIdToNodeMap().isEmpty() ) {
+            reHashIdToNodeMap();
         }
-        else {
-            for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) {
-                final PhylogenyNode node = iter.next();
-                if ( node.getId() == id ) {
-                    return node;
-                }
-            }
-        }
-        return null;
+        return getIdToNodeMap().get( id );
     }
 
     /**
@@ -563,6 +547,21 @@ public class Phylogeny {
         return nodes.get( 0 );
     }
 
+    /**
+     * This is time-inefficient since it runs a iterator each time it is called.
+     * 
+     */
+    public int getNodeCount() {
+        if ( isEmpty() ) {
+            return 0;
+        }
+        int c = 0;
+        for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); it.next() ) {
+            ++c;
+        }
+        return c;
+    }
+
     public int getNumberOfBranches() {
         if ( isEmpty() ) {
             return 0;
@@ -708,17 +707,21 @@ public class Phylogeny {
      * constant time. Important: The user is responsible for calling this method
      * (again) after this Phylogeny has been changed/created/renumbered.
      */
-    public void hashIDs() {
+    private void reHashIdToNodeMap() {
         if ( isEmpty() ) {
             return;
         }
-        setIdHash( new HashMap<Integer, PhylogenyNode>() );
+        setIdToNodeMap( new HashMap<Integer, PhylogenyNode>() );
         for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) {
             final PhylogenyNode node = iter.next();
-            getIdHash().put( node.getId(), node );
+            getIdToNodeMap().put( node.getId(), node );
         }
     }
 
+    public void clearHashIdToNodeMap() {
+        setIdToNodeMap( null );
+    }
+
     /**
      * Deletes this Phylogeny.
      */
@@ -729,7 +732,7 @@ public class Phylogeny {
         _description = "";
         _type = "";
         _distance_unit = "";
-        _idhash = null;
+        _id_to_node_map = null;
         _confidence = null;
         _identifier = null;
         _rerootable = true;
@@ -833,7 +836,7 @@ public class Phylogeny {
         if ( isEmpty() ) {
             return;
         }
-        _idhash = null;
+        _id_to_node_map = null;
         int max = 0;
         for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); ) {
             final PhylogenyNode node = it.next();
@@ -850,51 +853,11 @@ public class Phylogeny {
         PhylogenyNode.setNodeCount( max + 1 );
     }
 
-    /**
-     * Arranges the order of childern for each node of this Phylogeny in such a
-     * way that either the branch with more children is on top (right) or on
-     * bottom (left), dependent on the value of boolean order.
-     * 
-     * @param order
-     *            decides in which direction to order
-     */
-    public void orderAppearance( final boolean order ) throws RuntimeException {
-        if ( !isTree() ) {
-            throw new FailedConditionCheckException( "Attempt to order appearance on phylogeny which is not tree-like." );
-        }
-        if ( isEmpty() ) {
-            return;
-        }
-        orderAppearanceHelper( getRoot(), order );
-    }
-
-    // Helper method for "orderAppearance(boolean)".
-    // Traverses this Phylogeny recusively.
-    private void orderAppearanceHelper( final PhylogenyNode n, final boolean order ) {
-        if ( n.isExternal() ) {
-            return;
-        }
-        else {
-            PhylogenyNode temp = null;
-            // FIXME
-            if ( ( n.getNumberOfDescendants() == 2 )
-                    && ( n.getChildNode1().getNumberOfExternalNodes() != n.getChildNode2().getNumberOfExternalNodes() )
-                    && ( ( n.getChildNode1().getNumberOfExternalNodes() < n.getChildNode2().getNumberOfExternalNodes() ) == order ) ) {
-                temp = n.getChildNode1();
-                n.setChild1( n.getChildNode2() );
-                n.setChild2( temp );
-            }
-            for( int i = 0; i < n.getNumberOfDescendants(); ++i ) {
-                orderAppearanceHelper( n.getChildNode( i ), order );
-            }
-        }
-    }
-
     public void preOrderReId() {
         if ( isEmpty() ) {
             return;
         }
-        setIdHash( null );
+        setIdToNodeMap( null );
         int i = PhylogenyNode.getNodeCount();
         for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); ) {
             it.next().setId( i++ );
@@ -1093,8 +1056,8 @@ public class Phylogeny {
                 b.setBranchData( ( BranchData ) a.getBranchDataDirectly().copy() );
             }
             // New root is always placed in the middle of the branch:
-            if ( a.getDistanceToParent() == PhylogenyNode.DISTANCE_DEFAULT ) {
-                b.setDistanceToParent( PhylogenyNode.DISTANCE_DEFAULT );
+            if ( a.getDistanceToParent() == PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) {
+                b.setDistanceToParent( PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT );
             }
             else {
                 if ( distance_n_to_parent >= 0.0 ) {
@@ -1127,9 +1090,9 @@ public class Phylogeny {
             if ( c.getNumberOfDescendants() == 2 ) {
                 final PhylogenyNode node = c.getChildNode( 1 - b.getChildNodeIndex( c ) );
                 node.setParent( b );
-                if ( ( c.getDistanceToParent() == PhylogenyNode.DISTANCE_DEFAULT )
-                        && ( node.getDistanceToParent() == PhylogenyNode.DISTANCE_DEFAULT ) ) {
-                    node.setDistanceToParent( PhylogenyNode.DISTANCE_DEFAULT );
+                if ( ( c.getDistanceToParent() == PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT )
+                        && ( node.getDistanceToParent() == PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) ) {
+                    node.setDistanceToParent( PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT );
                 }
                 else {
                     node.setDistanceToParent( ( c.getDistanceToParent() >= 0.0 ? c.getDistanceToParent() : 0.0 )
@@ -1189,8 +1152,8 @@ public class Phylogeny {
         _identifier = identifier;
     }
 
-    void setIdHash( final HashMap<Integer, PhylogenyNode> idhash ) {
-        _idhash = idhash;
+    private void setIdToNodeMap( final HashMap<Integer, PhylogenyNode> idhash ) {
+        _id_to_node_map = idhash;
     }
 
     /**
@@ -1239,35 +1202,15 @@ public class Phylogeny {
         _type = type;
     }
 
-    /**
-     * Swaps the the two childern of a PhylogenyNode node of this Phylogeny.
-     * <p>
-     * (Last modified: 06/13/01)
-     * 
-     * @param node
-     *            a PhylogenyNode of this Phylogeny
-     */
-    public void swapChildren( final PhylogenyNode node ) throws RuntimeException {
-        if ( !isTree() ) {
-            throw new FailedConditionCheckException( "Attempt to swap children on phylogeny which is not tree-like." );
-        }
-        if ( isEmpty() || node.isExternal() || ( node.getNumberOfDescendants() < 2 ) ) {
-            return;
-        }
-        final PhylogenyNode first = node.getFirstChildNode();
-        for( int i = 1; i < node.getNumberOfDescendants(); ++i ) {
-            node.setChildNode( i - 1, node.getChildNode( i ) );
-        }
-        node.setChildNode( node.getNumberOfDescendants() - 1, first );
-    } // swapChildren( PhylogenyNode )
-
     public String toNewHampshire() {
-        return toNewHampshire( false );
+        return toNewHampshire( false, NH_CONVERSION_SUPPORT_VALUE_STYLE.NONE );
     }
 
-    public String toNewHampshire( final boolean simple_nh ) {
+    public String toNewHampshire( final boolean simple_nh,
+                                  final NH_CONVERSION_SUPPORT_VALUE_STYLE nh_conversion_support_style ) {
         try {
-            return new PhylogenyWriter().toNewHampshire( this, simple_nh, true ).toString();
+            return new PhylogenyWriter().toNewHampshire( this, simple_nh, true, nh_conversion_support_style )
+                    .toString();
         }
         catch ( final IOException e ) {
             throw new Error( "this should not have happend: " + e.getMessage() );
@@ -1283,15 +1226,19 @@ public class Phylogeny {
         }
     }
 
-    public String toNexus() {
+    public String toNexus( final NH_CONVERSION_SUPPORT_VALUE_STYLE svs ) {
         try {
-            return new PhylogenyWriter().toNexus( this ).toString();
+            return new PhylogenyWriter().toNexus( this, svs ).toString();
         }
         catch ( final IOException e ) {
             throw new Error( "this should not have happend: " + e.getMessage() );
         }
     }
 
+    public String toNexus() {
+        return toNexus( NH_CONVERSION_SUPPORT_VALUE_STYLE.NONE );
+    }
+
     public String toPhyloXML( final int phyloxml_level ) {
         try {
             return new PhylogenyWriter().toPhyloXML( this, phyloxml_level ).toString();