public class SpeciesTree {
    // OVERVIEW: An immutable tree of Species.  A tree has a root of type Species, and zero, one or two children, 
    //    each of which is a Tree.  Typical SpeciesTrees are < root >, < root, child >, and < root, child, child >.

    private /*@non_null@*/ Species root;
    private SpeciesTree lchild;
    private SpeciesTree rchild;

    // Rep Invariant (c):
    //     c != null
    //     c.root != null
    //     there are no cycles in the tree
    //        i.e., no tree reachable from c.(lchild | rchild)* is the same object as c.
    //     there is only one path from the root to a particular tree
    //        i.e., no tree reachable from c.(lchild | rchild)* is reachable from c.(lchild | rchild)*
    //                  except using the exact same path.

    public SpeciesTree (/*@non_null@*/ Species r)
	// EFFECTS: Returns a new SpeciesTree with root r and no children.
    {
	root = r;
	lchild = null;
	rchild = null;
    }

    public SpeciesTree (/*@non_null@*/ Species r, SpeciesTree lc, SpeciesTree rc)
	// EFFECTS: Returns a new SpeciesTree with root r and two children, lc and rc.
    {
	root = r;
	lchild = lc;
	rchild = rc;
    }

    public /*@non_null@*/ Species getRoot ()
	// EFFECTS: Returns the Species at the root of this tree.
    {
	return root;
    }

    public SpeciesTree getLeft () 
	// EFFECTS: Returns the left child of this tree.
	
    {
	return lchild;
    }

    public SpeciesTree getRight () 
	// EFFECTS: Returns the right child of this tree.
    {
	return rchild;
    }

    public int parsimonyValue ()
	// EFFECTS: Returns the parsimony value of this tree.
	//    (Note: a better design might put this in a separate class.)
    {
	int pvalue = 0;

	if (lchild != null) {
	    pvalue += lchild.parsimonyValue ();
	    pvalue += root.mutationDistance (lchild.getRoot ());
	}

	if (rchild != null) {
	    pvalue += rchild.parsimonyValue ();
	    pvalue += root.mutationDistance (rchild.getRoot ());
	}

	return pvalue;
    }

    public String toString ()
    {
	return toStringIndent (0);
    }

    private /*@non_null@*/ String toStringIndent (int indent)
	// EFFECTS: Returns a string representation of this tree indented indent spaces.
    {
	String res = "";
	
	for (int i = 0; i < indent; i++) {
	    res += " ";
	}

	res += root.toString () + "\n";

	if (lchild != null) {
	    res += lchild.toStringIndent (indent + 3);
	}

	if (rchild != null) {
	    res += rchild.toStringIndent (indent + 3);
	}

	return res;
    }
}