// $Id: branch.h,v 1.71 2018/01/03 21:33:03 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


/*******************************************************************

 Class Branch represents a branch in the tree, and is polymorphic on the type of event at its top
 (a coalescence, migration, etc.).  It contains auxiliary objects (a Range * and a DLCell) to manage
 likelihood and site information.

 A Branch's parents and children are represented by vectors of Branch_ptr.
 There may be 0, 1 or 2 parents and 0, 1 or 2 children; other values are illegal.

 As Branches are polymorphic, they are only put in containers as boost::shared_ptrs.
 To copy a Branch use the Clone() function, which will create a new Branch of appropriate subtype.

 Branches are either Cuttable (can be cut during rearrangement) or not, and signal this by returning
 their "count of cuttable branches" which is currently either 0 or 1.  Partition and stick branches
 are currently non-cuttable.

 Written by Jim Sloan, heavily revised by Jon Yamato
 -- dlcell turned into a container Mary 2002/05/28
 -- derivation hierarchy reworked, TreeBranch class inserted
    Branch class narrowed Jon 2003/02/24
 -- Adding semi-unique ID numbers for each branch (the "same" branch
    in two different trees will share the same ID number).  First
    implementation via reference counted pointer objects.  Jon 2007/01/09

********************************************************************/

#ifndef BRANCH_H
#define BRANCH_H

#include <cassert>
#include <cmath>
#include <deque>
#include <functional>
#include <string>
#include <vector>

#include "vectorx.h"
#include "constants.h"
#include "defaults.h"
#include "range.h"                      // For Link-related typedefs and constants.
#include "dlcell.h"
#include "locuscell.h"
#include "shared_ptr.hpp"               // for Branch_ptr (boost::shared_ptr)
#include "enable_shared_from_this.hpp"  // for shared_ptr support
#include "branchtag.h"
#include "rangex.h"                     // for class Range (and subclass) factory duties
#include "fc_status.h"                  // for RevalidateRange debug function

//------------------------------------------------------------------------------------

class TreeSummary;
class TipData;
class BranchBuffer;
class Force;
class Branch;
class TBranch;
class TiXmlElement;

enum branch_type {btypeBase, btypeTip, btypeCoal, btypeMig, btypeDivMig, btypeDisease, btypeRec, btypeEpoch};
enum branch_group {bgroupTip, bgroupBody};

std::string ToString(branch_type btype);

typedef boost::shared_ptr<TBranch> TBranch_ptr;

//------------------------------------------------------------------------------------

class Branch : public boost::enable_shared_from_this<Branch>
{
  private:
    Range * m_rangePtr;                 // Accessed via GetRangePtr(), which tests for NULLness (in DEBUG mode).

    Branch();                               // Default ctor is undefined.
    Branch & operator=(const Branch & src); // Assignment operator is undefined.
    vector<weakBranch_ptr> m_parents;
    vector<weakBranch_ptr> m_children;

  protected:
    bool m_updateDL;
    BranchTag m_ID;
    weakBranch_ptr m_equivBranch;

    // We own what these point to.
    vector<LocusCell> m_DLcells;
    vector<LocusCell> m_movingDLcells;

    virtual void CopyAllMembers(const Branch & src);
    LongVec1d GetLocalPartitions() const; // Used by ScoreEvent.

    // Each derived branch must implement some form of Range factory function that will be called
    // in that branch's ctor to create the new Range for that branch.  We did not implement a pure
    // virtual base function because of the different signature needs of each of the derived
    // branch's Range.  The current factory is named CreateRange(), which returns a Range *,
    // a pointer to a newly-heap-allocated Range.
    //
    // NB: the C++ standard does not currently (2010/03/31) allow you to call polymorphically
    // from within a ctor of base.  You will get the base instantiation of the function; if one
    // does not exist, the compiler will/should fail.

  public:
    LongVec1d m_partitions;
    double m_eventTime;
    bool m_marked;

    //************Panel Correction control parameters
    // this exists so we don't have to reach all the way back into the xml
    // 0 if a Panel member
    // 1 if a Sample member
    // 2 if a coalescence has only sample tips above it
    int m_isSample;
    bool m_wasCoalCalced; // coalescence DLCell has been calculated once
    // used to prevent recalculation of type 2 coalesences
    //************Panel Correction control parameters

    static Branch_ptr NONBRANCH;

    Branch(Range * newrangeptr);
    Branch(const Branch & src);

    // Destructor.  Defined to deallocated the Range object in every Branch object.
    // The destructors for all the derived classes are default dtors which do nothing.
    // Since this base class dtor gets called after the dtor for each derived class,
    // this dtor will be the only one which deletes the Range object once and only once.
    virtual ~Branch();

    // Accessor for Range pointer also tests (in DEBUG mode) for NULLness.
    // BBranch objects have a NULL value for "m_rangePtr", but it should never be dereferenced.
    Range * GetRangePtr() const { assert(m_rangePtr) ; return m_rangePtr; };

    // RTTI
    virtual branch_type Event()                 const = 0;
    virtual branch_group BranchGroup()          const = 0;

    virtual Branch_ptr Clone() const { return Branch::NONBRANCH; };

    // Convenience getters and setters.
    long int GetID() const;
    weakBranch_ptr GetEquivBranch() const;
    void     SetEquivBranch(Branch_ptr twin);

    long int GetPartition(force_type) const;
    void     SetPartition(force_type force, long int val);
    virtual void    CopyPartitionsFrom(Branch_ptr src);

    Branch_ptr    Child(long int which) { return m_children[which].lock(); };
    Branch_ptr    Parent(long int which) { return m_parents[which].lock(); };
    const Branch_ptr Child(long int which) const { return m_children[which].lock(); };
    const Branch_ptr Parent(long int which) const { return m_parents[which].lock(); };
    void     SetChild(long int which, Branch_ptr val) { m_children[which] = val; };
    void     SetParent(long int which, Branch_ptr val) { m_parents[which] = val; };
    long int NParents() const { return m_parents.size(); };
    long int NChildren() const { return m_children.size(); };

    // Arrangement helpers.
    bool    IsAMember(const Force & force, const LongVec1d & membership) const;
    virtual long int Cuttable()                const { return 0; };
    virtual bool     CanRemove(Branch_ptr)           { return true; };
    virtual long int CountDown()               const { return 0; };
    virtual void     UpdateBranchRange(const rangeset &, bool ) {};
    virtual void     UpdateRootBranchRange(const rangeset &, bool) {};
    virtual bool     IsEquivalentTo(const Branch_ptr)   const; // Virtual, but there is only 1 definition.
    virtual bool     HasSamePartitionsAs(const Branch_ptr) const;
    virtual bool     PartitionsConsistentWith(const Branch_ptr) const;
    long int         Nsites() const { return GetRangePtr()->GetNumRegionSites(); };

    rangeset         GetLiveSites() const { return GetRangePtr()->GetLiveSites(); };

    virtual bool     IsRemovableRecombinationLeg(const rangeset &) const { return false; };

    virtual Branch_ptr GetRecPartner() const { return Branch::NONBRANCH; };
    void ResetBuffersForNextRearrangement();
    void ResetOldTargetSites(const rangeset & fcsites) { GetRangePtr()->ResetOldTargetSites(fcsites); };

    // The following routine is a no-op except in a branch where updateDL is
    // allowed to be true, in which case it will be overridden.
    virtual void    SetUpdateDL()                   {};
    void    ClearUpdateDL()                 { m_updateDL = false; };
    bool    GetUpdateDL()             const { return m_updateDL; };
    void    MarkParentsForDLCalc();
    virtual void    ReplaceChild(Branch_ptr oldchild, Branch_ptr newchild);
    virtual bool    HasSameActive(const Branch & br);
    const Cell_ptr GetDLCell(long int loc, long int ind, bool moving) const;
    Cell_ptr GetDLCell(long int loc, long int ind, bool moving);

    void     SetDLCells(const std::vector<LocusCell> & src) { m_DLcells = src; };
    long int GetNcells(long int locus)  const { return m_DLcells[locus].size(); };
    void     SetMovingDLCells(const std::vector<LocusCell> & src) { m_movingDLcells = src; };

    // long int GetNcells(long int locus)  const { return m_DLcells[locus].size(); };

    double GetTime() { return m_eventTime; };

    // Subtree maker helper.
    // Value returned is a Littlelink (well, code for a non-existent one here).
    virtual long int GetRecpoint() const { return FLAGLONG; };

    // Likelihood calculation helpers.
    virtual double HowFarTo(const Branch & br) const;
    virtual bool   CanCalcDL(long int)         const { return false; };
    virtual bool   CanCalcPanelDL(long int)    const { return false; };
    virtual bool   ShouldCalcDL(long int)      const { return false; };
    Branch_ptr GetValidChild(Branch_ptr br, long int whichpos);
    Branch_ptr GetValidPanelChild(Branch_ptr br, long int whichpos);
    Branch_ptr GetValidParent(long int whichpos);

    // Haplotyping helpers.
    virtual bool    DiffersInDLFrom(Branch_ptr branch, long int locus, long int marker) const;

    // Tree summarization helpers.
    // Some subclass functions return results via the reference second and third arguments.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const = 0;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const = 0;

    // Invariant checking.
    virtual bool    operator==(const Branch & src) const;
    bool    operator!=(const Branch & src) const { return !(*this == src); };

    // Debugging functions.
    virtual bool    CheckInvariant()              const;
    virtual string  DLCheck(const Branch & other)  const;
    void            InvertUpdateDL() { m_updateDL = !m_updateDL; };
    virtual void    PrintInfo() const;
    vector<Branch_ptr> GetBranchChildren(); // Used by TimeList::PrintTimeList()
    virtual bool    IsSameExceptForTimes(const Branch_ptr other) const;

    // Used by TimeList::IsValidTimeList(), non-const because of
    // use of boost::shared_from_this()!
    bool            ConnectedTo(const Branch_ptr family);

    // Debugging function.
    // Used by TimeList::RevalidateAllRanges(), must be able to handle "one-legged" forms
    // of all branchtypes (eg. coalescence and recombination).
    //
    // The base class implementation will assume that there exists exactly one child and
    // that there are no changes in the Range object between parent and child, and no
    // changes needed to the passed argument.
    virtual bool    RevalidateRange(FC_Status &) const;

    // GetActiveChild() is a helper function for GetValidChild()
    virtual const Branch_ptr GetActiveChild(long int) const { return Child(0); };

    // GetActivePanelChild() is a helper function for GetValidPanelChild()
    virtual const Branch_ptr GetActivePanelChild(long int) const { return Child(0); };

    // for writing GraphML output
    virtual void     AddGraphML(TiXmlElement *) const;
    virtual void     AddNodeInfo(TiXmlElement *) const {return;} ;
    virtual string   GetGraphMLNodeType() const = 0;
    virtual string   GetParentIDs() const;
    virtual string   GetChildIDs() const;
    virtual long int GetCanonicalID() const;
    virtual long int GetCanonicalParentID() const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// BASE branch - root end of tree - one child, no parent.

class BBranch : public Branch
{
  private:
    BBranch & operator=(const BBranch & src); // Assignment operator is undefined.

  protected:
    // Rather than returning a "fake" range for this bottom-most branch, we return a Null pointer.
    // Callers use an accessor function which checks this pointer with ASSERT.
    virtual Range * CreateRange() const { return NULL; };

  public:
    // Need this for TimeList constructor; will construct using CreateRange().  But a BBranch's Range
    // should never be accessed.  It's Range pointer is NULL, and GetRangePtr() will ASSERT on it.
    BBranch();

    BBranch(const BBranch & src): Branch(src) {}; // Copies the NULL Range pointer.

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~BBranch() {};

    virtual Branch_ptr Clone()               const;
    virtual branch_type Event()              const { return btypeBase; };
    virtual branch_group BranchGroup()       const { return bgroupBody; };

    // Tree summarization helpers.
    // Some subclass functions (not this one) return results via the reference third argument.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const;

    // Debugging function.
    virtual bool    CheckInvariant()          const;

    // for writing GraphML output
    virtual string GetGraphMLNodeType() const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// TIP branch - tip of tree - one parent, no children.

class TBranch : public Branch
{
  private:
    TBranch();                                // Default ctor is undefined.
    TBranch & operator=(const TBranch & src); // Assignment operator is undefined.

  protected:
    virtual Range * CreateRange(long int nsites, const rangeset & diseasesites) const;

  public:
    string  m_label;

    TBranch(const TipData & tipdata, long int nsites, const rangeset & diseasesites);
    TBranch(const TBranch & src) : Branch(src), m_label(src.m_label) {};

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~TBranch() {};

    virtual Branch_ptr Clone()                        const;
    virtual branch_type Event()                       const { return btypeTip; };
    virtual branch_group BranchGroup()                const { return bgroupTip; };

    virtual long int Cuttable()                       const { return 1; };
    virtual const Branch_ptr GetActiveChild(long int) const { return Branch::NONBRANCH; };

    // Tree summarization helpers.
    // Some subclass functions (not this one) return results via the reference third argument.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const;

    // Debugging functions.
    virtual bool    CheckInvariant()              const;
    virtual bool    operator==(const Branch & src) const;
    virtual bool    IsSameExceptForTimes(const Branch_ptr other) const;
    virtual bool    RevalidateRange(FC_Status &) const;
    virtual void    PrintInfo() const;

    // for writing GraphML output
    virtual void   AddNodeInfo(TiXmlElement *) const;
    virtual string GetGraphMLNodeType() const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// COALESCENCE branch - one parent, two children.

class CBranch : public Branch
{
  private:
    CBranch();                                // Default ctor is undefined.
    CBranch & operator=(const CBranch & src); // Assignment operator is undefined.

  protected:
    // If newbranchisinactive == true, then child1rangeptr is assumed to point to the inactive branch Range
    // and child2rangeptr to point to the active branch Range.
    virtual Range * CreateRange(const Range * const child1rangeptr, const Range * const child2rangeptr,
                                bool  newbranchisinactive, const rangeset & fcsites) const;

  public:
    CBranch(const Range * const child1rangeptr, const Range * const child2rangeptr, bool newbranchisinactive, const rangeset & fcsites);
    CBranch(const CBranch & src) : Branch(src) {};

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~CBranch() {};

    virtual Branch_ptr Clone()                  const;
    virtual branch_type Event()                 const { return btypeCoal; };
    virtual branch_group BranchGroup()          const { return bgroupBody; };

    virtual long int Cuttable()                 const { return 1; };
    virtual bool     CanRemove(Branch_ptr checkchild);
    virtual long int CountDown()                const { return -2; };
    virtual void     UpdateBranchRange(const rangeset & fcsites, bool dofc);
    virtual void     UpdateRootBranchRange(const rangeset & fcsites, bool dofc);
    virtual void     SetUpdateDL()                    { m_updateDL = true; };
    virtual void     ReplaceChild(Branch_ptr oldchild, Branch_ptr newchild);
    virtual Branch_ptr OtherChild(Branch_ptr badchild);
    virtual bool CanCalcDL(long int site) const;
    virtual bool ShouldCalcDL(long int site) const { return m_updateDL && CanCalcDL(site); };
    virtual const Branch_ptr GetActiveChild(long int site) const;

    // Tree summarization helpers.
    // Some subclass functions (this one does) return results via the reference third argument.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const;

    // Debugging functions.
    virtual bool    CheckInvariant()          const;
    virtual bool    RevalidateRange(FC_Status & fcstatus) const;

    // for writing GraphML output
    virtual string GetGraphMLNodeType() const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// BASE CLASS for many branchs like migration and disease - one parent, one child.

class PartitionBranch : public Branch
{
  private:
    PartitionBranch();                                        // Default ctor is undefined.
    PartitionBranch & operator=(const PartitionBranch & src); // Assignment operator is undefined.

  protected:
    Range * CreateRange(const Range * const childrangeptr) const;

  public:
    PartitionBranch(const Range * const childrangeptr);
    PartitionBranch(const PartitionBranch & src) : Branch(src) {};

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~PartitionBranch() {};

    virtual long int Cuttable()            const { return 0; };
    virtual branch_group BranchGroup()     const { return bgroupBody; };
    virtual void UpdateBranchRange(const rangeset & fcsites, bool dofc);
    virtual void UpdateRootBranchRange(const rangeset &, bool) { assert(false); };

    // Debugging function.
    virtual bool CheckInvariant()       const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// Abstract base class for migration-like branches (MIG, DIVMIG).

class MigLikeBranch : public PartitionBranch
{
  private:
    MigLikeBranch();                                      // Default ctor is undefined.
    MigLikeBranch & operator=(const MigLikeBranch & src); // Assignment operator is undefined.

  protected:
    // We accept PartitionBranch::CreateRange().

  public:
    MigLikeBranch(const Range * const protorangeptr);
    MigLikeBranch(const MigLikeBranch & src);

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~MigLikeBranch() {};
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// MIGRATION branch - one parent, one child.

class MBranch : public MigLikeBranch
{
  private:
    MBranch();                                // Default ctor is undefined.
    MBranch & operator=(const MBranch & src); // Assignment operator is undefined.

  protected:
    // We accept PartitionBranch::CreateRange().

  public:
    MBranch(const Range * const protorangeptr);
    MBranch(const MBranch & src);

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~MBranch() {};

    virtual Branch_ptr Clone()             const;
    virtual branch_type Event()            const { return btypeMig; };

    // Tree summarization helpers.
    // Some subclass functions (not this one) return results via the reference third argument.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const;

    // for writing GraphML output
    virtual string GetGraphMLNodeType() const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// MIGRATION when modeling divergence branch - one parent, one child.
// Migration nodes for Divergence Migration.

class DivMigBranch : public MigLikeBranch
{
  private:
    DivMigBranch();                                     // Default ctor is undefined.
    DivMigBranch & operator=(const DivMigBranch & src); // Assignment operator is undefined.

  protected:
    // We accept PartitionBranch::CreateRange().

  public:
    DivMigBranch(const Range * const protorangeptr);
    DivMigBranch(const DivMigBranch & src);

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~DivMigBranch() {};

    virtual Branch_ptr Clone()             const;
    virtual branch_type Event()            const { return btypeDivMig; };

    // Tree summarization helpers.
    // Some subclass functions (not this one) return results via the reference third argument.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const;

    // for writing GraphML output
    virtual string GetGraphMLNodeType() const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// DISEASE mutation branches.  NOT related to Divergence! - one parent one child.

class DBranch : public PartitionBranch
{
  private:
    DBranch();                                // Default ctor is undefined.
    DBranch & operator=(const DBranch & src); // Assignment operator is undefined.

  protected:
    // We accept PartitionBranch::CreateRange().

  public:
    DBranch(const Range * const protorangeptr);
    DBranch(const DBranch & src);

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~DBranch() {};

    virtual Branch_ptr Clone()             const;
    virtual branch_type Event()            const { return btypeDisease; };
    virtual branch_group BranchGroup()     const { return bgroupBody; };

    // Tree summarization helpers.
    // Some subclass functions (not this one) return results via the reference third argument.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const;

    // for writing GraphML output
    virtual string GetGraphMLNodeType() const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// EPOCH branch (used for divergence, but d was already taken by disease) - one parent, xxx child.

class EBranch : public PartitionBranch
{
  private:
    EBranch();                                // Default ctor is undefined.
    EBranch & operator=(const EBranch & src); // Assignment operator is undefined.

  protected:
    // We accept PartitionBranch::CreateRange().

  public:
    EBranch(const Range * const protorangeptr) : PartitionBranch(protorangeptr) {};
    EBranch(const EBranch & src) : PartitionBranch(src) {};

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~EBranch() {};

    virtual Branch_ptr Clone()         const;
    virtual branch_type Event()        const { return btypeEpoch; };
    virtual branch_group BranchGroup() const { return bgroupBody; };

    // Tree summarization helpers.
    // Some subclass functions (not this one) return results via the reference third argument.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const;

    // for writing GraphML output
    virtual string GetGraphMLNodeType() const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

// RECOMBINATION branch - one parent, one child
// Shares the child with another recombination branch which has a different parent.
// Use GetRecPartner() to find this partner.
// The other RBranch has the same time but transmits a different range of sites.

class RBranch : public Branch
{
  private:
    RBranch();                                // Default ctor is undefined.
    RBranch & operator=(const RBranch & src); // Assignment operator is undefined.

  protected:
    Range * CreateRange(const Range * const childrangeptr, bool isinactive,
                        const rangeset & transmittedsites, const rangeset & fcsites) const;

  public:
    RBranch(const Range * const childrangeptr, bool isinactive,
            const rangeset & transmittedsites, const rangeset & fcsites);
    RBranch(const RBranch & src) : Branch(src) {};

    // Base-class dtor deletes the Range object pointed to by "m_rangePtr" (assuming ptr is non-NULL).
    virtual ~RBranch() {};

    virtual Branch_ptr Clone()             const;
    virtual branch_type Event()            const { return btypeRec; };
    virtual branch_group BranchGroup()     const { return bgroupBody; };

    virtual void    CopyPartitionsFrom(Branch_ptr src);
    void    RecCopyPartitionsFrom(Branch_ptr src, FPartMap fparts, bool islow);

    virtual long int   Cuttable()          const { return 1; };
    virtual long int   CountDown()         const { return 1; };
    virtual void       UpdateBranchRange(const rangeset & fcsites, bool dofc);
    virtual void       UpdateRootBranchRange(const rangeset &, bool) { assert(false); };
    virtual void       ReplaceChild(Branch_ptr oldchild, Branch_ptr newchild);
    virtual bool       IsRemovableRecombinationLeg(const rangeset &) const;
    virtual Branch_ptr GetRecPartner() const;

    // Can be called on recombinant branch only; returns Littlelink (Biglink midpoint, if Biglinks enabled).
    virtual long int GetRecpoint() const { return GetRangePtr()->GetRecpoint(); };

    // Tree summarization helpers.
    // Some subclass functions (this one does) return results via the reference third argument.
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const;
    virtual void    ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const;

    virtual bool    operator==(const Branch & src) const;

    // Debugging functions.
    virtual bool    CheckInvariant()          const;
    virtual bool    IsSameExceptForTimes(const Branch_ptr other) const;
    virtual bool    RevalidateRange(FC_Status & fcstatus) const;

    // for writing GraphML output
    virtual string GetGraphMLNodeType() const;
    virtual void   AddNodeInfo(TiXmlElement *) const;
};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Free functions for use as STL predicates

class IsTipGroup : public std::unary_function<Branch_ptr, bool>
{
  public:
    bool operator()(const Branch_ptr t) { return t->BranchGroup() == bgroupTip; };
};

//------------------------------------------------------------------------------------

class IsBodyGroup : public std::unary_function<Branch_ptr, bool>
{
  public:
    bool operator()(const Branch_ptr t) { return t->BranchGroup() == bgroupBody; };
};

//------------------------------------------------------------------------------------

class IsCoalGroup : public std::unary_function<Branch_ptr, bool>
{
  public:
    bool operator()(const Branch_ptr t) { return t->Event() == btypeCoal; };
};

#endif // BRANCH_H

//____________________________________________________________________________________
