// $Id: chainpack.h,v 1.26 2018/01/03 21:32:54 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 */


#ifndef CHAINPACK_H
#define CHAINPACK_H

#include <fstream>
#include <vector>
#include <algorithm>

#include "vectorx.h"
#include "chainout.h"
#include "constants.h"
#include "definitions.h"

/************************************************************************
 This class collects ChainOut objects containing the results of all
 chains, as well as a summary for each region and an overall summary.
 It is filled by the chain manager and used by the output report.

 It implements the following rules:

 If only one replicate was run, the regional result is the result
 from its last chain.  If multiple replicates were run, there is a
 separate regional result summing all replicates.

 If only one region was run, the overall result is the result from
 that region.  If multiple regions were run, there is a separate
 overall result summing all regions.

 ChainPack adds timestamps to each summary object indicating the
 times of the chains which it summarizes.  The calling program does
 not need to set timestamps on the summaries, but it does need to set
 timestamps on the individual chain objects.

 DEBUG There is currently a logic problem involving summary times when there
 is only one region.

 (MDEBUG:  Mary looked at this 3/23/2005.  The class is badly designed
 and should be redesigned so that the regional and overall results always
 exist (removes a lot of nasty special case code and kills the logic
 bug) but this is a fairly large refactoring and is being deferred till
 after 2.0.)

 While it is being filled up by the chain manager, the ChainPack
 is in an inconsistent state (for example, it may have two regions
 but no overall summary) and should generally not be touched by
 anyone else.

 Written by:  Mary Kuhner September 2000
*************************************************************************/

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

    vector<vector<vector<ChainOut> > >  m_chains;    // output of each chain
    // dim: reg X rep X cha
    vector<ChainOut>                    m_regions;   // summed over reps
    // dim: reg
    vector<ChainOut>                    m_overall;   // summed over regions
    // dim: really a scalar but kept
    // as a vector for convenience
    long int m_currentChain;
    long int m_currentRep;
    long int m_currentRegion;

    long int    RegionsSoFar()   const   {return(static_cast<long int>(m_chains.size()));};
    DoubleVec1d CalcMean(const DoubleVec2d& src)  const;

  public:

    ChainPack() : m_currentChain(0), m_currentRep(0), m_currentRegion(0) {}; ~ChainPack() {};

    // Inspector functions
    ChainOut  GetChain(long int region, long int rep, long int chain) const;
    ChainOut  GetLastChain()                                          const;
    ChainOut  GetLastChain(long int region)                           const;
    ChainOut  GetRegion(long int region)                              const;
    ChainOut  GetOverall()                                            const;
    long int  GetLenRegionsVec()                                      const;
    long int  GetLenOverallVec()                                      const;
    time_t    GetStartTime()                                          const;
    time_t    GetStartTime(long int region)                           const;
    time_t    GetEndTime()                                            const;
    DoubleVec1d   RegionalMeanParams()                                const;
    DoubleVec1d   OverallMeanParams()                                 const;

    vector<vector<vector<ChainOut > > > GetAllChains()                const;

    // Mutator functions
    // These change their arguments--do not make the arguments const!
    void SetChain(ChainOut& chout, long int region, long int rep, long int chain);
    void SetChain(ChainOut& chout);
    void ResetLastChain(ChainOut& chout, long int region);
    void RemoveLastChain();
    void SetSummaryOverReps(ChainOut& chout);
    void ResetSummaryOverReps(ChainOut& chout, long int region);
    void SetSummaryOverRegions(ChainOut& chout);

    void EndReplicate() { ++m_currentRep; m_currentChain = 0; };
    void EndRegion()    { ++m_currentRegion; m_currentRep = 0; m_currentChain = 0;};
    void EndRegionIfNecessary(long int region);
    void EndRegionsOrRepsAsNeeded(long int maxreps, long int maxchains);

    //Summary file functions to write out chain info
    void WriteLastChain   ( std::ofstream& out ) const ;
    void WriteChain       ( std::ofstream& out, long int, long int, long int ) const;
    void WriteChainOut    ( std::ofstream& out, const ChainOut& chout) const;
    void WriteForceParameters ( std::ofstream& out, const ForceParameters& fp ) const;
    void WriteAlphas(std::ofstream& sumout, long int reg, long int rep, long int chain) const;

    //Function to test whether we're assembling correctly.
    void VerifyPosition   ( long int test_reg, long int test_rep, long int test_chain) ;
};

#endif // CHAINPACK_H

//____________________________________________________________________________________
