// $Id: userparam.cpp,v 1.52 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 <fstream>

#include "local_build.h"

#include "errhandling.h"
#include "force.h"
#include "region.h"
#include "registry.h"
#include "stringx.h"
#include "timex.h"
#include "userparam.h"
#include "xml_strings.h"  // for ToXML()

#ifdef DMALLOC_FUNC_CHECK
#include "/usr/local/include/dmalloc.h"
#endif

using std::string;
using std::vector;

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

string UserParameters::BuildFileName(string prefix, string regionname, long repCount, string ext) const
{
    string rname = SpacesToUnderscores(regionname);
    return prefix + "_" + rname + "_" + ToString(repCount+1) + "." + ext;
}

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

UserParameters::UserParameters(string curvefileprefix,
                               string mapfileprefix,
                               string reclocfileprefix,
                               string tracefileprefix,
                               string newicktreefileprefix,
#ifdef LAMARC_QA_TREE_DUMP
                               string argfileprefix,
#endif // LAMARC_QA_TREE_DUMP
                               string datafilename,
                               string profileprefix,
                               string resultsfilename,
                               string treesuminfilename,
                               string treesumoutfilename,
                               string xmloutfilename,
                               string xmlreportfilename,
                               verbosity_type   verbosity,
                               verbosity_type   progress,
                               bool   plotPost,
                               bool   usesystemclock,
                               bool   readsumfile,
                               bool   writesumfile,
                               bool   writecurvefiles,
                               bool   writereclocfiles,
                               bool   writetracefiles,
                               bool   writenewicktreefiles,
#ifdef LAMARC_QA_TREE_DUMP
                               bool   writeargfiles,
                               bool   writemanyargs,
#endif // LAMARC_QA_TREE_DUMP
                               long   randomSeed,
                               time_t programstarttime)
    :
    m_curvefileprefix(curvefileprefix),
    m_mapfileprefix(mapfileprefix),
    m_reclocfileprefix(reclocfileprefix),
    m_tracefileprefix(tracefileprefix),
    m_newicktreefileprefix(newicktreefileprefix),
#ifdef LAMARC_QA_TREE_DUMP
    m_argfileprefix(argfileprefix),
#endif // LAMARC_QA_TREE_DUMP
    m_datafilename(datafilename),
    m_profileprefix(profileprefix),
    m_resultsfilename(resultsfilename),
    m_treesuminfilename(treesuminfilename),
    m_treesumoutfilename(treesumoutfilename),
    m_xmloutfilename(xmloutfilename),
    m_xmlreportfilename(xmlreportfilename),
    m_verbosity(verbosity),
    m_progress(progress),
    m_plotPost(plotPost),
    m_usesystemclock(usesystemclock),
    m_readsumfile(readsumfile),
    m_writesumfile(writesumfile),
    m_writecurvefiles(writecurvefiles),
    m_writereclocfiles(writereclocfiles),
    m_writetracefiles(writetracefiles),
    m_writenewicktreefiles(writenewicktreefiles),
#ifdef LAMARC_QA_TREE_DUMP
    m_writeargfiles(writeargfiles),
    m_writemanyargs(writemanyargs),
#endif // LAMARC_QA_TREE_DUMP
    m_randomSeed(randomSeed),
    m_programstarttime(programstarttime)
{
    // we establish defaults for the user parameters here.
    // they can be overriden both by the data file and by
    // the menu.

    //LS DEBUG:  move to the output manager when one exists.
    string regionname = registry.GetDataPack().GetRegion(0).GetRegionName();
    m_currentReclocFileName     = BuildFileName(m_reclocfileprefix,    regionname,-1, "txt");
    m_currentTraceFileName      = BuildFileName(m_tracefileprefix,     regionname,-1, "txt");
    m_currentNewickTreeFileName = BuildFileName(m_newicktreefileprefix,regionname,-1, "txt");
#ifdef LAMARC_QA_TREE_DUMP
    m_currentArgFileName        = BuildFileName(m_argfileprefix,       regionname,-1, "xml");
#endif // LAMARC_QA_TREE_DUMP

    m_currentBestLike = -DBL_MAX;
    m_currentStep = 0;
}

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

StringVec1d UserParameters::ToXML(unsigned long nspaces) const
{
    StringVec1d xmllines;
    string line = MakeIndent(MakeTag(xmlstr::XML_TAG_FORMAT),nspaces);
    xmllines.push_back(line);

    nspaces += INDENT_DEPTH;

    string mytag;

    mytag = MakeTag(xmlstr::XML_TAG_CONVERT_OUTPUT);
    line = MakeIndent(mytag, nspaces) + " "
        + ToString(registry.GetConvertOutputToEliminateZeroes()) + " "
        + MakeCloseTag(mytag);
    xmllines.push_back(line);

    if (GetUseSystemClock())
    {
        xmllines.push_back("");
        line = MakeIndent(xmlstr::XML_COMMENT_SEED_FROM_CLOCK_0,nspaces);
        xmllines.push_back(line);
        line = MakeIndent(xmlstr::XML_COMMENT_SEED_FROM_CLOCK_1,nspaces);
        xmllines.push_back(line);
        mytag = MakeTag(xmlstr::XML_TAG_SEED_FROM_CLOCK);
        line = MakeIndent(mytag,nspaces) + ToString(GetRandomSeed()) + MakeCloseTag(mytag);
        xmllines.push_back(line);
        xmllines.push_back("");
    }
    else
    {
        mytag = MakeTag(xmlstr::XML_TAG_SEED);
        line = MakeIndent(mytag,nspaces) + ToString(GetRandomSeed()) + MakeCloseTag(mytag);
        xmllines.push_back(line);
    }

    mytag = MakeTag(xmlstr::XML_TAG_VERBOSITY);
    line = MakeIndent(mytag,nspaces) + ToString(GetVerbosity()) + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_PROGRESS_REPORTS);
    line = MakeIndent(mytag,nspaces) + ToString(GetProgress()) + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_RESULTS_FILE);
    line = MakeIndent(mytag,nspaces) + GetResultsFileName() + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_USE_IN_SUMMARY);
    line = MakeIndent(mytag,nspaces) + ToStringTF(GetReadSumFile()) + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_IN_SUMMARY_FILE);
    line = MakeIndent(mytag,nspaces) + GetTreeSumInFileName() + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_USE_OUT_SUMMARY);
    line = MakeIndent(mytag,nspaces) + ToStringTF(GetWriteSumFile()) + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_OUT_SUMMARY_FILE);
    line = MakeIndent(mytag,nspaces) + GetTreeSumOutFileName() + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_USE_CURVEFILES);
    line = MakeIndent(mytag,nspaces) + ToStringTF(GetWriteCurveFiles()) + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_CURVEFILE_PREFIX);
    line = MakeIndent(mytag,nspaces) + GetCurveFilePrefix() + MakeCloseTag(mytag);
    xmllines.push_back(line);

    //LS DEBUG:  add this
#if 0
    mytag = MakeTag(xmlstr::XML_TAG_MAPFILE_PREFIX);
    line = MakeIndent(mytag,nspaces) + GetMapFilePrefix() + MakeCloseTag(mytag);
    xmllines.push_back(line);
#endif

    mytag = MakeTag(xmlstr::XML_TAG_USE_RECLOCFILE);
    line = MakeIndent(mytag,nspaces) + ToStringTF(GetWriteReclocFiles())
        + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_RECLOCFILE_PREFIX);
    line = MakeIndent(mytag,nspaces) + GetReclocFilePrefix() + MakeCloseTag(mytag);
    xmllines.push_back(line);

    mytag = MakeTag(xmlstr::XML_TAG_USE_TRACEFILE);
    line = MakeIndent(mytag,nspaces) + ToStringTF(GetWriteTraceFiles())
        + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_TRACEFILE_PREFIX);
    line = MakeIndent(mytag,nspaces) + GetTraceFilePrefix() + MakeCloseTag(mytag);
    xmllines.push_back(line);

    mytag = MakeTag(xmlstr::XML_TAG_USE_NEWICKTREEFILE);
    line = MakeIndent(mytag,nspaces) + ToStringTF(GetWriteNewickTreeFiles())
        + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_NEWICKTREEFILE_PREFIX);
    line = MakeIndent(mytag,nspaces) + GetNewickTreeFilePrefix()
        + MakeCloseTag(mytag);
    xmllines.push_back(line);

#ifdef LAMARC_QA_TREE_DUMP
    mytag = MakeTag(xmlstr::XML_TAG_USE_ARGFILES);
    line = MakeIndent(mytag,nspaces) + ToStringTF(GetWriteArgFiles())
        + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_MANY_ARGFILES);
    line = MakeIndent(mytag,nspaces) + ToStringTF(GetWriteManyArgs())
        + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_ARGFILE_PREFIX);
    line = MakeIndent(mytag,nspaces) + GetArgFilePrefix()
        + MakeCloseTag(mytag);
    xmllines.push_back(line);
#endif // LAMARC_QA_TREE_DUMP

    mytag = MakeTag(xmlstr::XML_TAG_OUT_XML_FILE);
    line = MakeIndent(mytag,nspaces) + GetXMLOutFileName() + MakeCloseTag(mytag);
    xmllines.push_back(line);

    mytag = MakeTag(xmlstr::XML_TAG_REPORT_XML_FILE);
    line = MakeIndent(mytag,nspaces) + GetXMLReportFileName() + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_PROFILE_PREFIX);
    line = MakeIndent(mytag,nspaces) + GetProfilePrefix() + MakeCloseTag(mytag);
    xmllines.push_back(line);

    nspaces -= INDENT_DEPTH;

    line = MakeIndent(MakeCloseTag(xmlstr::XML_TAG_FORMAT),nspaces);
    xmllines.push_back(line);

    return xmllines;
} // ToXML

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

void UserParameters::UpdateFileNamesAndSteps(long region, long replicate,
                                             bool readsumfile)
{
    string regionname = registry.GetDataPack().GetRegion(region).GetRegionName();
    m_currentReclocFileName     = BuildFileName(m_reclocfileprefix,    regionname,replicate, "txt");
    m_currentTraceFileName      = BuildFileName(m_tracefileprefix,     regionname,replicate, "txt");
    m_currentNewickTreeFileName = BuildFileName(m_newicktreefileprefix,regionname,replicate, "txt");
#ifdef LAMARC_QA_TREE_DUMP
    m_currentArgFileName        = BuildFileName(m_argfileprefix,       regionname,replicate, "xml");
#endif // LAMARC_QA_TREE_DUMP

    m_currentStep = 0;
    //If we're in a non-bayesian run, and if we're collecting tracer data, we
    // need to start things off here.
    //
    // Er, this is ugly design.  LS DEBUG

    //Note:  Below are the headers for the tracer file; the contents are
    // written in CollectionManager::WriteTraceFile(...) in collmanager.cpp
    if (GetWriteTraceFiles() && !readsumfile)
    {
        std::ofstream tracefile;
        tracefile.open(m_currentTraceFileName.c_str(),std::ios::trunc);
        tracefile << "Step\tLn(Data Likelihood)";
        if (registry.GetChainParameters().IsBayesian())
        {
            const vector<Force*>& forces = registry.GetForceSummary().GetAllForces();
            vector<Force*>::const_iterator force;
            for (force = forces.begin(); force != forces.end(); ++force)
            {
                vector<string> paramnames = (*force)->GetAllParamNames();
                vector<string>::iterator name;
                for (name = paramnames.begin(); name != paramnames.end(); ++name)
                {
                    if (!(*name).empty())
                    {
                        tracefile << "\t" << *name;
                    }
                }
            }
        }
        tracefile << std::endl;
        tracefile.close();
        AddTraceFileName(m_currentTraceFileName);
    }
    if (GetWriteReclocFiles() && !readsumfile)
    {
        std::ofstream reclocfile;
        reclocfile.open(m_currentReclocFileName.c_str(),std::ios::trunc);
        reclocfile.close();
        AddReclocFileName(m_currentReclocFileName);
    }

#ifdef LAMARC_QA_TREE_DUMP
    if (GetWriteArgFiles() && !readsumfile)
    {
        std::ofstream argfile;
        argfile.open(m_currentArgFileName.c_str(),std::ios::trunc);
        argfile.close();
        AddArgFileName(m_currentArgFileName);
    }
#endif
}

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

void UserParameters::UpdateWriteTraceFile(long region, long replicate)
{
    //m_currentTraceFileName should be accurate.  We should not have written
    // to it during this run of LAMARC, but we might have written to it
    // during the previous run.  If so, we'll just append.  If not, we'll
    // create a new file by calling UpdateFileNamesAndSteps.
    std::ifstream tracefile;
    tracefile.open(m_currentTraceFileName.c_str(), std::ios::in );
    if (!tracefile)
    {
        UpdateFileNamesAndSteps(region, replicate, false);
    }
}

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

long UserParameters::GetNextStep(long initialOrFinal)
{
    m_currentStep += registry.GetChainParameters().GetInterval(initialOrFinal); // EWFIX.CHAINTYPE
    return m_currentStep;
}

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

void UserParameters::AddCurveFileName (const std::string name)
{
    m_curvefilenames.push_back(name);
}

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

void UserParameters::AddMapFileName (const std::string name)
{
    m_mapfilenames.push_back(name);
}

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

void UserParameters::AddProfileName (const std::string name)
{
    m_profilenames.push_back(name);
}

//------------------------------------------------------------------------------------
// RSGNOTE: Called, but result is never used.

void UserParameters::AddReclocFileName (const std::string name)
{
    m_reclocfilenames.insert(name);
}

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

void UserParameters::AddTraceFileName (const std::string name)
{
    m_tracefilenames.insert(name);
}

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

void UserParameters::AddNewickTreeFileName (const std::string name)
{
    m_newicktreefilenames.insert(name);
}

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

#ifdef LAMARC_QA_TREE_DUMP
void UserParameters::AddArgFileName (const std::string name)
{
    m_argfilenames.insert(name);
}
#endif // LAMARC_QA_TREE_DUMP

//____________________________________________________________________________________
