// $Id: intervaldata.h,v 1.26 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 */


/*
  This file contains two closely related classes used in storing
  TreeSummaries.  The first class, Interval, represents all data
  gathered from one time interval in a given tree.  It holds a
  "next" pointer to the next Intervals *of a given event type* (for
  example, a coalescent Interval, one with a coalescence event at
  the bottom, will hold a pointer to the next coalescent Interval).
  These pointers are NULL when there is no such Interval.

  Intervals are meant to be kept within an ordered std::list that
  keeps them in time order; the "next" system is independent of
  that and is used by maximizer code that requires lightning-fast
  access to the next event of the same type.

  The second class, IntervalData, contains and manages Intervals
  and also contains and manages the force-specific Summary objects
  that offer access to them.

  Written by Mary Kuhner
*/

#ifndef INTERVALDATA_H
#define INTERVALDATA_H

#include <fstream>
#include <list>
#include <map>

#include "constants.h"
#include "defaults.h"
#include "range.h"                      // For Link-related typedefs and constants.
#include "types.h"
#include "vectorx.h"
// #include "summary.h" for management of summaries

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

class Summary;

typedef std::map<string, double> Forcemap;
typedef std::map<string, double>::iterator Forcemapiter;
typedef std::map<force_type, Summary*> Summap;

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

struct Interval
{
    double m_endtime;                   // time at the rootward end of the interval
    // We do not store starttime but rely on computing it on the fly.
    LongVec1d m_xpartlines;             // length is cross partition
    LongVec2d m_partlines;              // length is partition force by partition
    Linkweight m_recweight;             // used only for recombination (Link weight)
    xpart_t m_oldstatus;                // used for partition events
    // Also used for coal events, tracks xpart index.
    xpart_t m_newstatus;                // used for partition events
    long int m_recpoint;                // used only for recombination (Littlelink)
    Interval * m_next;                  // points to the next interval of the same force or NULL

    // The following is used only if both recombination and a local partition force are in effect.
    LongVec1d m_partnerpicks;           // length is (local) partition forces

    force_type m_type;

    // The Interval class could be refactored to be polymorphic by force, which would alleviate
    // some issues here with writing out the data, but would be tricky elsewhere, since
    // the interval list would have to be pointers.
    Interval(double etime, const LongVec2d& plines,
             const LongVec1d& xlines, Linkweight recweight, long int ostat, long int nstat,
             long int recpoint, const LongVec1d& picks, force_type ftype)
        : m_endtime(etime),
          m_xpartlines(xlines),
          m_partlines(plines),
          m_recweight(recweight),
          m_oldstatus(ostat),
          m_newstatus(nstat),
          m_recpoint(recpoint),
          m_next(NULL),
          m_partnerpicks(picks),
          m_type(ftype)
    {};

    // Warning WARNING -- this will lead to intertwined lists if much usage
    //   is made of std::list functionality!
    // Believe it or not, we accept the default copy constructor and
    // operator=.  The pointers are NOT owning, and copying them is
    // necessary for its current usage.
};

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

class IntervalData
{
  private:
    IntervalData& operator=(const IntervalData&); // not defined
    IntervalData(const IntervalData& src);        // not defined

  public:

    // The following is a List for iterator stability
    // warning WARNING -- do not use std::list functionality that
    // modifies the whole list at once (like splice or operator=).
    // Non-modifying or single element modifying are usable.
    std::list<Interval> m_intervals;

    // We must define the default constructor, since we disallow
    // the copy constructor and that prevents compiler generation of it.
    IntervalData() {};

    Interval * AddInterval(Interval * prev, double time, const LongVec2d & pk,
                           const LongVec1d & xk, Linkweight recweight, xpart_t ostat, xpart_t nstat,
                           long int recpoint, const LongVec1d & picks, force_type type);

    // This AddInterval variant is used when a dummy interval is being added as part of fatal attraction
    // prevention code.  It's sole purpose is to prevent "fatal attraction" to a zero recombination rate.
    // It is always called with arguments specifying a "fake" interval.
    Interval * AddDummyInterval(Interval * prev, Linkweight recweight, xpart_t ostat,
                                xpart_t nstat, long int recpoint, force_type type);

    unsigned long int size() { return m_intervals.size(); };

    std::list<Interval>::iterator begin() { return m_intervals.begin(); };
    std::list<Interval>::const_iterator begin() const { return m_intervals.begin(); };
    std::list<Interval>::iterator end() { return m_intervals.end(); };
    std::list<Interval>::const_iterator end() const { return m_intervals.end(); };
    void clear() { m_intervals.clear(); };

    // This function is used when writing tree summaries with growth.
    void WriteIntervalData(std::ofstream& sumout) const;

    // debug function
    void PrintIntervalData() const;

};

#endif // INTERVALDATA_H

//____________________________________________________________________________________
