// $Id: sumfilehandler.cpp,v 1.22 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 */


#include <iostream>

#include "sumfilehandler.h"
#include "forceparam.h"
#include "chainout.h"
#include "chainpack.h"
#include "collmanager.h"
#include "registry.h"
#include "region.h"
#include "runreport.h"
#include "stringx.h"
#include "timex.h"
#include "treesum.h"
#include "xmlsum_strings.h"  // for xml sumfile handling

using namespace std;

SumFileHandler::SumFileHandler()
    : m_sumin(), m_sumout(),  m_lastRegion(0), m_lastReplicate(0),
      m_lastChain(-1),m_lastRegionChainSum(-1), m_lastReplicateChainSum(-1),
      m_lastReplicateSummary(0), m_regionSummary(false)
{
}

/****************************************************************************
 *
 * Sumfile Reading functions
 *
 ****************************************************************************/

// should be only reading fxn to read EOF, all others should not
void SumFileHandler::ReadInSumFile(ChainPack& chainpack,
                                   CollectionManager& collectionmanager,
                                   long int numchains)
{
    string infilename = registry.GetUserParameters().GetTreeSumInFileName();
    m_sumin.open(infilename.c_str(), ios::in );
    if (!m_sumin)
    {
        string err_string =  "Could not open \"" + infilename + "\".  "
            + "Please check that this file:\n"
            + "       1) exists in directory that lamarc is being run from,\n"
            + "       2) is read enabled, and\n"
            + "       3) is not in use by another program.\n";
        throw file_error( err_string );
    }

    string tag;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInSumFile", xmlsum::SUMFILE_START, tag );
    m_sumin >> tag;

    while ( (!m_sumin.eof()) && (tag != xmlsum::SUMFILE_END))
    {
        if( tag == xmlsum::COMMENT_START )
        {
            SkipComments();
        }
        else if( tag == xmlsum::CHAINPACK_START )
        {
            ReadInChainPack(chainpack);
        }
        else if( tag == xmlsum::CHAINSUM_START )
        {
            ReadInChainSum(chainpack, collectionmanager, numchains);
        }
        else if( tag == xmlsum::REPLICATE_SUMMARY_START )
        {
            ReadInReplicateSummary(chainpack);
        }
        else if( tag == xmlsum::END_REGION_START )
        {
            ReadInEndRegion(chainpack); //This no longer does anything.
        }
        else if( tag == xmlsum::REGION_SUMMARY_START )
        {
            ReadInRegionSummary(chainpack);
        }
        else  {//The file is formatted incorrectly.
            ReadInCheckFileFormat("ReadInSumFile", "a top-level sumfile tag", tag );
        }

        m_sumin >> tag;
    }
    m_sumin.close();
} // SumFileHandler::ReadInSumFile

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

// does not handle nested comments, but should eventually
// precondition:  last tag read in from stream in:   xmlsum::COMMENT_START
// postcondition: last string read in from stream in: xmlsum::COMMENT_END
void SumFileHandler::SkipComments()
{
    string comment;
    m_sumin >> comment;
    while ( !m_sumin.eof() && comment != xmlsum::COMMENT_END )
    {
        m_sumin >> comment;
        if (comment == xmlsum::COMMENT_START) //for nested comments.
        {
            SkipComments();
        }
    }
}

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

// populate ChainManager's chainpack with a chain summary.
// precondition:  last tag read in from stream in: xmlsum::CHAINPACK_START
// postcondition: last tag read in from stream in: xmlsum::CHAINPACK_END
void SumFileHandler::ReadInChainPack(ChainPack& chainpack)
{
    string tag;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInChainPack", xmlsum::NUMBER_START, tag );
    m_sumin >> m_lastRegion;
    m_sumin >> m_lastReplicate;
    m_sumin >> m_lastChain;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInChainPack", xmlsum::NUMBER_END, tag );
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInChainPack", xmlsum::CHAINOUT_START, tag );

    ChainOut co;
    ReadInChainOut(co);
    chainpack.SetChain(co, m_lastRegion, m_lastReplicate, m_lastChain);

    m_sumin >> tag;
    while (tag==xmlsum::ALPHA_START1)
    {
        m_sumin >> tag;
        ReadInCheckFileFormat( "ReadInChainPack", xmlsum::ALPHA_START2, tag );
        long int loc;
        m_sumin >> loc;
        m_sumin >> tag;
        ReadInCheckFileFormat( "ReadInChainPack", xmlsum::ALPHA_START3, tag );
        double alpha;
        m_sumin >> alpha;
        registry.GetDataPack().GetRegion(m_lastRegion).GetLocus(loc).GetDataModel()->
            SetAlpha(alpha, m_lastReplicate, m_lastChain+1);
        m_sumin >> tag;
        ReadInCheckFileFormat( "ReadInChainPack", xmlsum::ALPHA_END, tag );
        m_sumin >> tag;
    }
    ReadInCheckFileFormat( "ReadInChainPack", xmlsum::CHAINPACK_END, tag );
}

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

void SumFileHandler::ReadInReplicateSummary(ChainPack& chainpack)
{
    m_lastReplicateSummary++;
    string tag;
    ForceParameters fp(global_region);

    m_sumin>>tag;
    ReadInCheckFileFormat("ReadInReplicateSummary", xmlsum::ESTIMATES_START, tag );
    ReadInForceParameters(fp);

    double maxlike;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInReplicateSummary", xmlsum::MAXLIKE_START, tag );
    m_sumin >> maxlike;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInReplicateSummary", xmlsum::MAXLIKE_END, tag );
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInReplicateSummary", xmlsum::REPLICATE_SUMMARY_END, tag );

    ChainOut repout;
    repout.SetEstimates(fp);
    repout.SetLlikemle(maxlike);
    chainpack.SetSummaryOverReps(repout);

} // ReadInReplicateSummary

void SumFileHandler::ReadInEndRegion(ChainPack&)
{
    //This tag is only present when there is no Replicate Summary information.
    string tag;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInSumFile", xmlsum::END_REGION_END, tag );
}

void SumFileHandler::ReadInRegionSummary(ChainPack& chainpack)
{
    m_regionSummary = true;
    string tag;
    ForceParameters fp(global_region);

    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInRegionSummary", xmlsum::ESTIMATES_START, tag );
    ReadInForceParameters(fp);

    double maxlike;

    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInRegionSummary", xmlsum::MAXLIKE_START, tag );
    m_sumin >> maxlike;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInRegionSummary", xmlsum::MAXLIKE_END, tag );
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInRegionSummary", xmlsum::REGION_SUMMARY_END, tag );

    ForceSummary& forcesum = registry.GetForceSummary();
    ChainOut regionout;

    regionout.SetEstimates(fp);
    regionout.SetLlikemle(maxlike);
    chainpack.SetSummaryOverRegions(regionout);
    forcesum.SetOverallMLE(regionout);
} // ReadInRegionSummary

// populate chainout object c with data from the sumfile
// precondition:  last string read in from stream in: xmlsum::CHAINOUT_START
// postcondition: last string read in from stream in: xmlsum::CHAINOUT_END
void SumFileHandler::ReadInChainOut(ChainOut &c)
{
    string tag, srate;
    long int p1, p2;
    long int badtrees, stretchedtrees, tinytrees, zerodltrees;
    double accrate, llikemle, llikedata;
    time_t starttime, endtime;
    ForceParameters fp(global_region);

    do{
        m_sumin >> tag;
        if ( tag == xmlsum::BADTREES_START )
        {
            m_sumin >> badtrees;
            c.SetNumBadTrees( badtrees );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::BADTREES_END, tag );
        }
        if ( tag == xmlsum::STRETCHEDTREES_START )
        {
            m_sumin >> stretchedtrees;
            c.SetNumStretchedTrees( stretchedtrees );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::STRETCHEDTREES_END, tag );
        }
        if ( tag == xmlsum::TINYTREES_START )
        {
            m_sumin >> tinytrees;
            c.SetNumTinyPopTrees( tinytrees );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::TINYTREES_END, tag );
        }
        if ( tag == xmlsum::ZERODLTREES_START )
        {
            m_sumin >> zerodltrees;
            c.SetNumZeroDLTrees( zerodltrees );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::ZERODLTREES_END, tag );
        }
        if ( tag == xmlsum::ACCRATE_START )
        {
            m_sumin >> accrate;
            c.SetAccrate( accrate );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::ACCRATE_END, tag );
        }
        if ( tag == xmlsum::LLIKEMLE_START )
        {
            m_sumin >> llikemle;
            c.SetLlikemle( llikemle );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::LLIKEMLE_END, tag );
        }
        if ( tag == xmlsum::LLIKEDATA_START )
        {
            m_sumin >> llikedata;
            c.SetLlikedata( llikedata );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::LLIKEDATA_END, tag );
        }
        if ( tag == xmlsum::STARTTIME_START )
        {
            m_sumin >> starttime;
            c.SetStarttime( starttime );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::STARTTIME_END, tag );
        }
        if ( tag == xmlsum::ENDTIME_START )
        {
            m_sumin >> endtime;
            c.SetEndtime( endtime );
            m_sumin >> tag;
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::ENDTIME_END, tag );
        }
        if ( tag == xmlsum::RATES_START )
        {
            m_sumin >> tag;
            ratemap r;
            while ( tag == xmlsum::MAP_START )
            {
                m_sumin >> srate;
                m_sumin >> p1;
                m_sumin >> p2;
                m_sumin >> tag;
                pair<long int, long int> rpair(p1, p2);
                r.insert( make_pair(srate, rpair) );
                c.SetRates( r );
                ReadInCheckFileFormat( "ReadInChainOut", xmlsum::MAP_END, tag );
                m_sumin >> tag;
            }
            ReadInCheckFileFormat( "ReadInChainOut", xmlsum::RATES_END, tag );
        }
        if ( tag == xmlsum::ESTIMATES_START )
        {
            ReadInForceParameters(fp);
            c.SetEstimates(fp);
        }
        if ( tag == xmlsum::TEMPERATURES_START)
        {
            DoubleVec1d temperatures;
            if ( ReadInVec1D( temperatures, xmlsum::TEMPERATURES_END ) )
            {
                c.SetTemperatures( temperatures );
                c.SetNumtemps(temperatures.size());
            }
        }
        if ( tag == xmlsum::SWAPRATES_START)
        {
            DoubleVec1d swaprates;
            if ( ReadInVec1D( swaprates, xmlsum::SWAPRATES_END ) )
                c.SetSwaprates( swaprates );
        }
        if ( tag == xmlsum::BAYESUNIQUE_START)
        {
            LongVec1d bayesunique;
            if ( ReadInVec1D( bayesunique, xmlsum::BAYESUNIQUE_END ) )
                c.SetBayesUnique( bayesunique );
        }

    } while (tag != xmlsum::CHAINOUT_END);
} // ReadInChainOut

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

// populate forceparameter object fp with data from the sumfile
// precondition:  last string read in: xmlsum::ESTIMATES_START
// postcondition: last string read in: xmlsum::ESTIMATES_END
void SumFileHandler::ReadInForceParameters( ForceParameters& fp )
{
    vector<double> vd;
    string tag;

    m_sumin >> tag;
    while ( tag != xmlsum::ESTIMATES_END )
    {
        if ( tag == xmlsum::THETAS_START )
        {
            if ( ReadInVec1D( vd, xmlsum::THETAS_END ) )
                fp.SetGlobalThetas( vd );
        }
        if ( tag == xmlsum::MIGRATES_START )
        {
            if ( ReadInVec1D( vd, xmlsum::MIGRATES_END ) )
                fp.SetMigRates( vd );
        }
        if ( tag == xmlsum::DIVMIGRATES_START )
        {
            if ( ReadInVec1D( vd, xmlsum::DIVMIGRATES_END ) )
                fp.SetMigRates( vd );
        }
        if ( tag == xmlsum::RECRATES_START )
        {
            if ( ReadInVec1D( vd, xmlsum::RECRATES_END ) )
                fp.SetRecRates( vd );
        }
        if ( tag == xmlsum::GROWTHRATES_START )
        {
            if ( ReadInVec1D( vd, xmlsum::GROWTHRATES_END ) )
                fp.SetGrowthRates( vd );
        }
        if ( tag == xmlsum::LOGISTICSELECTION_START )
        {
            if ( ReadInVec1D( vd, xmlsum::LOGISTICSELECTION_END ) )
                fp.SetLogisticSelectionCoefficient( vd );
        }
        if ( tag == xmlsum::EPOCHTIMES_START )
        {
            if ( ReadInVec1D( vd, xmlsum::EPOCHTIMES_END ) )
                fp.SetEpochTimes( vd );
        }
        if ( tag == xmlsum::DISEASERATES_START )
        {
            if ( ReadInVec1D( vd, xmlsum::DISEASERATES_END ) )
                fp.SetDiseaseRates( vd );
        }
        if ( tag == xmlsum::GAMMAOVERREGIONS_START )
        {
            if ( ReadInVec1D( vd, xmlsum::GAMMAOVERREGIONS_END ) )
            {
                if ( !registry.GetRegionGammaInfo() )
                {
                    string msg = "Warning!  You are reading summary-file data ";
                    msg += "from a run in which you allowed the mutation rate ";
                    msg += "to vary over genomic regions according to a gamma ";
                    msg += "distribution, and in which the scaled shape parameter ";
                    msg += "of this distribution was estimated to be ";
                    msg += ToString(vd[0]);
                    msg += ".  In the present analysis, you have the gamma ";
                    msg += "distribution turned OFF, which will produce different ";
                    msg += "results.  You may wish to re-start LAMARC, and ";
                    msg += "turn the gamma distribution on, using the evolutionary ";
                    msg += "forces menu.";
                    registry.GetRunReport().ReportUrgent(msg);
                }
            }
        }
        m_sumin >> tag;
    }
    registry.GetForceSummary().ValidateForceParamOrBarf(fp);
    ReadInCheckFileFormat( "SumFileHandler::ReadInForceParameters", xmlsum::ESTIMATES_END, tag);
} // ReadInForceParameters

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

// populate vector vd with data from sumfile
// clears vd before adding doubles to it
// if vd not empty, return true, else return false
bool SumFileHandler::ReadInVec1D( vector<double>& vd, string endtag )
{
    string sdouble;
    m_sumin >> sdouble;
    vd.clear();
    while ( sdouble != endtag )
    {
        vd.push_back( atof(sdouble.c_str()) );
        m_sumin >> sdouble;
    }

    if (vd.size() > 0)
        return true;
    else
        return false;
} // ReadInVec1D

bool SumFileHandler::ReadInVec1D( vector<long int> & vd, string endtag )
{
    string slong;
    m_sumin >> slong;
    vd.clear();
    while ( slong != endtag )
    {
        vd.push_back( atol(slong.c_str()) );
        m_sumin >> slong;
    }

    if (vd.size() > 0)
        return true;
    else
        return false;
} // ReadInVec1D

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

void SumFileHandler::ReadInChainSum(ChainPack& chainpack, CollectionManager& collectionmanager, long int numchains)
{
    long int region, replicate;
    string tag;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInChainSum", xmlsum::REG_REP_START, tag );
    m_sumin >> region;
    m_sumin >> replicate;
    m_sumin >> tag;
    ReadInCheckFileFormat("ReadInChainSum", xmlsum::REG_REP_END, tag );
    m_sumin >> tag;

    m_lastRegionChainSum = region;
    m_lastReplicateChainSum = replicate;

    collectionmanager.StartChain(region, replicate, true);
    while (((tag == xmlsum::TREESUM_START) ||
            (tag == xmlsum::PARAM_SUMMARY_START))
           && (!m_sumin.eof()))
    {
        if (tag==xmlsum::TREESUM_START)
        {
            TreeSummary* ts = registry.GetProtoTreeSummary().Clone();
            ts->ReadInTreeSummary(m_sumin);
            collectionmanager.GetTreeColl(region, replicate)->AddTreeSummary(ts);
        }
        else if (tag==xmlsum::PARAM_SUMMARY_START)
        {
            m_sumin >> tag;
            ReadInCheckFileFormat("ReadInChainSum", xmlsum::NCOPY_START, tag );
            long int ncopy;
            m_sumin >> ncopy;
            m_sumin >> tag;
            ReadInCheckFileFormat("ReadInChainSum", xmlsum::NCOPY_END, tag );
            m_sumin >> tag;
            ReadInCheckFileFormat("ReadInChainSum", xmlsum::ESTIMATES_START, tag );
            ForceParameters fp(region);
            ReadInForceParameters(fp);
            collectionmanager.GetParamColl(region, replicate)->AddParamSummary(fp, ncopy);
            m_sumin >> tag;
            ReadInCheckFileFormat("ReadInChainSum", xmlsum::PARAM_SUMMARY_END, tag );

        }
        else
        {
            string eitheror = "either " + xmlsum::TREESUM_START + " or "
                + xmlsum::PARAM_SUMMARY_START;
            ReadInCheckFileFormat("ReadInChainSum", eitheror, tag);
        }
        m_sumin >> tag;
    }

    if (collectionmanager.GetSampleTrees())
    {
        ForceParameters fp(unknown_region);
        if (numchains >=2 )
        {
            fp = chainpack.GetChain(region, replicate, numchains-2).GetEstimates();
            //-2 is -1 for size->index, and -1 for next-to-last.
        }
        else if (numchains == 1)
        {
            ForceParameters fpstart(registry.GetForceSummary().GetStartParameters(), region);
            fp = fpstart;
        }
        else
        {
            //numchains is negative or zero?
            throw implementation_error
                ("The number of chains seems to be zero or negative.  This should be impossible.");
        }
        collectionmanager.GetTreeColl(region, replicate)->SetStartParameters(fp);

        //The old format had estimates here, but now they're optional.
        if (tag == xmlsum::ESTIMATES_START)
        {
            ForceParameters fp(region);
            ReadInForceParameters(fp);
            collectionmanager.GetTreeColl(region, replicate)->SetStartParameters(fp);
            m_sumin >> tag;
        }
    }

    ReadInCheckFileFormat("ReadInChainSum", xmlsum::CHAINSUM_END, tag );
    //We don't need AdjustSummaries since it was called if needed originally.

} // ReadInChainSum

// ReadInCheckFileFormat:  checks the file format one tag at a time
// args:
//   callingfxn  - should include class calling fxn belongs to
//   expectedtag - expected xml tag in sumfile
//   readtag     - xml tag just read in by the calling fxn
void SumFileHandler::ReadInCheckFileFormat(string callingfxn, string expectedtag, string readtag)
{
    if (readtag != expectedtag)
    {
        string sumfile =  registry.GetUserParameters().GetTreeSumInFileName();
        string err_string = callingfxn + " - " + sumfile + " has syntactic error.";
        err_string += " Expected " + expectedtag + " but read " + readtag + "\n";
        throw incorrect_xml(err_string);
    }
} // ReadInCheckFileFormat

/****************************************************************************
 *
 * Sumfile Writing functions
 *
 ****************************************************************************/

void SumFileHandler::WriteSumFileStart()
{
    // open file
    m_sumout.open(registry.GetUserParameters().GetTreeSumOutFileName().c_str(), ios::out );
    if (!m_sumout)
    {
        HandleSumOutFileFormatError("SumFileHandler::WriteSumFileStart");
    }

    // write preamble
    m_sumout << xmlsum::SUMFILE_START << endl;
    m_sumout << xmlsum::COMMENT_START << " Lamarc v. "
             << VERSION << endl
             << "     Please do not modify. " << xmlsum::COMMENT_END  << endl;

    // set the precision of the data (should be greater than that of outfile)
    m_sumout.precision(SUMFILE_PRECISION);
} // WriteSumFileStart

void SumFileHandler::WriteSumFileEnd(const ChainPack& chainpack)
{
    if ( m_sumout.is_open() )
    {
        // finish up
        m_sumout << xmlsum::COMMENT_START << " End summary file" << endl
                 << "\t Generated from run that started at: "
                 << PrintTime(chainpack.GetStartTime(), "%c") << endl
                 << "\t and ended at: " << PrintTime(chainpack.GetEndTime(), "%c")
                 << " " << xmlsum::COMMENT_END << endl;
        m_sumout << xmlsum::SUMFILE_END << endl;
        m_sumout.close();
    }
    else
        HandleSumOutFileFormatError("WriteSumFileEnd");
} // WriteSumFileEnd

void SumFileHandler::WriteLastChain(const ChainPack& chainpack)
{
    chainpack.WriteLastChain(m_sumout);
}

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

// currently called after tree generation/processing done
// currently outputs necessary data to skip tree gen to calculate MLE's

void SumFileHandler::WriteChainSumStart( long int whichregion, long int whichreplicate,
                                         const CollectionManager& collectionmanager )
{
    if ( m_sumout.is_open() )
    {
        m_sumout << xmlsum::CHAINSUM_START << endl
                 << "\t" << xmlsum::REG_REP_START << " " << whichregion << " "
                 << whichreplicate << " " << xmlsum::REG_REP_END << endl;

        collectionmanager.WriteThisChainsCollections(&m_sumout);
    }
    else
        HandleSumOutFileFormatError("WriteChainSumStart");
} // WriteChainSumsStart

void SumFileHandler::WriteChainSumEnd(const CollectionManager& collectionmanager )
{
    if (m_sumout.is_open())
    {
        collectionmanager.WriteLastSummaries();
        m_sumout << xmlsum::CHAINSUM_END << endl;
    }
    else
        HandleSumOutFileFormatError("WriteChainSumEnd");
}

//Write summary info if more than one region is summarized.
void SumFileHandler::WriteRegionSummary(ForceParameters& fp, double maxlike)
{
    if ( m_sumout.is_open() )
    {
        m_sumout << xmlsum::REGION_SUMMARY_START << endl;
        fp.WriteForceParameters(m_sumout, 1);
        m_sumout << "\t" << xmlsum::MAXLIKE_START
                 << " " << maxlike << " "
                 << xmlsum::MAXLIKE_END << endl;
        m_sumout << xmlsum::REGION_SUMMARY_END << endl;
    }
    else
        HandleSumOutFileFormatError("WriteRegionSummary");
} // WriteRegionSummary

//Write summary info if more than one replicate is summarized.
void SumFileHandler::WriteReplicateSummary( ForceParameters& fp, double maxlike, const ChainPack&)
{
    if ( m_sumout.is_open() )
    {
        m_sumout << xmlsum::REPLICATE_SUMMARY_START << endl;
        fp.WriteForceParameters(m_sumout, 1);
        m_sumout << "\t" << xmlsum::MAXLIKE_START
                 << " " << maxlike << " "
                 << xmlsum::MAXLIKE_END << endl;
        m_sumout << xmlsum::REPLICATE_SUMMARY_END << endl;
    }
    else
        HandleSumOutFileFormatError("WriteReplicateSummary");
} // WriteReplicateSummary

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

// purpose: called if sumfile is closed when a summarizing fxn expected it
//    to be open.
// causes:  user could have done something to sumfile, or lamarc was
//   unable to open it in WriteSumFileStart now also called by
//   non-Summarize fxns, ie TreeSummary::ReadInTreeSummary
void SumFileHandler::HandleSumOutFileFormatError(string callingfxn)
{
    if (registry.GetUserParameters().GetWriteSumFile())
    {
        string sumfile    =  registry.GetUserParameters().GetTreeSumOutFileName();
        string err_string =  "In function, " + callingfxn + ", file," + sumfile
            + " unexpectedly closed or could not be opened and is no longer valid."
            + "  Possible causes of this problem include, but are not limited to: "
            + "1) read permissions for this file are not or are no longer enabled."
            + "2) this file was unexpectedly moved, renamed, or deleted. "
            + "Continuing, but without writing to the summary file any more.\n";
        registry.GetRunReport().ReportUrgent(err_string);
        registry.GetUserParameters().SetWriteSumFile(false);
    }
} // HandleSumOutFileFormatError

// WriteWhatWasRead is called when the user is both reading and writing to a
//  summary file.  This function writes everything at once, instead of doing
//  it piecemeal within DoChain/DoReplicate/etc. as it would normally.
//
//  This function relies on ReadInRecover working properly and setting
//  the recover* member variables if the read summary file was not complete.
void SumFileHandler::WriteWhatWasRead(bool recoversumfile,
                                      long int recover_region,
                                      long int recover_replicate,
                                      long int recover_chaintype,
                                      long int recover_chain,
                                      bool recover_redochain,
                                      bool recover_redomaximization,
                                      long int, //nregions, but it was unused.
                                      long int nreplicates,
                                      const ChainPack& chainpack,
                                      const CollectionManager& collectionmanager)
{
    if (m_sumout.is_open())
    {
        m_sumout << xmlsum::COMMENT_START
                 << "  This summary file should match the input summary file "
                 << registry.GetUserParameters().GetTreeSumInFileName()
                 << ",\n";
        if (recover_redochain)
        {
            m_sumout << "      with the exception of the final chainpack, which was re-created. ";
        }
        else
            m_sumout << "      up until that file's end. ";
        m_sumout << xmlsum::COMMENT_END  << endl;

        long int total_chains = 0 ;
        for (int i=0; i<NCHAINTYPES; i++ )
        {
            total_chains += registry.GetChainParameters().GetNChains(i);
        }

        long int last_region = recover_region + 1;
        for (long int rw_region = 0; rw_region < last_region; rw_region++ )
        {
            long int last_replicate = nreplicates;
            if (rw_region == last_region-1)
            {
                //This is the last region, so the number of replicates might be
                // different than the full number.
                last_replicate = recover_replicate+1;
            }
            for (long int rw_replicate = 0; rw_replicate < last_replicate; rw_replicate++ )
            {
                long int last_chain = total_chains;
                if ((rw_replicate == last_replicate-1) &&
                    (rw_region == last_region-1))
                {
                    //This is the last replicate, so the number of chains might be
                    // different than the full number.
                    last_chain = 0;
                    for (int i = 0; i < recover_chaintype; i++ )
                    {
                        last_chain += registry.GetChainParameters().GetNChains(i);
                    }
                    last_chain += recover_chain;
                    if (recover_redomaximization)
                    {
                        //We have chain summaries we need to write
                        last_chain++;
                    }
                }
                for (long int rw_chain = 0; rw_chain < last_chain; rw_chain++)
                {
                    bool last_loop = false;
                    if ((rw_region == last_region-1) &&
                        (rw_replicate == last_replicate-1) &&
                        (rw_chain == last_chain-1))
                    {
                        last_loop = true;
                    }
                    if ((rw_chain == total_chains-1) &&
                        (!last_loop || !recover_redochain))
                    {
                        //Write out the chain summary.
                        WriteChainSumStart(rw_region, rw_replicate, collectionmanager);
                        collectionmanager.WriteAllSummaries(rw_region, rw_replicate, m_sumout);
                        m_sumout << xmlsum::CHAINSUM_END << endl;
                    }
                    if (!last_loop || !recover_redomaximization)
                    {
                        //Write out the chainpack.
                        chainpack.WriteChain(m_sumout, rw_region, rw_replicate, rw_chain);
                    }
                }
            }
            if (chainpack.GetLenRegionsVec() - 1 >= rw_region)
            {
                //Write the summary over replicates
                ChainOut rw_chainout = chainpack.GetRegion(rw_region);
                double rw_maxlike = rw_chainout.GetLlikemle();
                ForceParameters rw_fp = rw_chainout.GetEstimates();
                WriteReplicateSummary(rw_fp, rw_maxlike, chainpack);
            }
        }
        if (chainpack.GetLenOverallVec() != 0)
        {
            //Write the summary over regions
            ChainOut rw_chainout = chainpack.GetOverall();
            double rw_maxlike = rw_chainout.GetLlikemle();
            ForceParameters rw_fp = rw_chainout.GetEstimates();
            WriteRegionSummary(rw_fp, rw_maxlike);
        }

        if (recoversumfile)
        {
            m_sumout << xmlsum::COMMENT_START
                     << "  New information past this point. "
                     << xmlsum::COMMENT_END  << endl;
        }
        else
            WriteSumFileEnd(chainpack);
    }
    else
        HandleSumOutFileFormatError("SumFileHandler::WriteWhatWasRead");
} // WriteWhatWasRead

void SumFileHandler::WriteVec1D( ofstream& sumout, vector<double> &vd)
{
    vector<double>::iterator itstart = vd.begin();
    vector<double>::iterator itend   = vd.end();
    if ( sumout.is_open() )
    {
        for( ; itstart != itend; ++itstart )
            sumout << *itstart << " ";
    }
    else
        SumFileHandler::HandleSumOutFileFormatError("WriteVec1D");
} // WriteVec1D

void SumFileHandler::WriteVec1D( ofstream& sumout, vector<long int> & vd)
{
    vector<long int>::iterator itstart = vd.begin();
    vector<long int>::iterator itend   = vd.end();
    if ( sumout.is_open() )
    {
        for( ; itstart != itend; ++itstart )
            sumout << *itstart << " ";
    }
    else
        SumFileHandler::HandleSumOutFileFormatError("WriteVec1D");
} // WriteVec1D

void SumFileHandler::CloseSumOut()
{
    m_sumout.close();
}

//____________________________________________________________________________________
