// $Id: curvefiles.cpp,v 1.6 2018/01/03 21:33:02 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: Mary Kuhner, Jon Yamato, and Joseph Felsenstein */


#include <cassert>
#include <fstream>
#include <iostream>

#include "bayesanalyzer_1d.h"
#include "curvefiles.h"
#include "parameter.h"
#include "registry.h"
#include "spreadsheet.h"
#include "stringx.h"
#include "vectorx.h"

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

void writeCurveHeader(  std::ofstream &     curvefileStream,
                        std::string         pname,
                        long                paramnum,
                        long                regions,
                        long                replicates,
                        BayesAnalyzer_1D &  ba)
{

    curvefileStream << "Bayesian likelihood curve for " << pname << std::endl;

    curvefileStream << "Overall curve represents " << replicates
                    << " replicate(s) for each of " << regions
                    << " different genomic regions" << std::endl;

    curvefileStream << "The prior for this parameter was ";
    if(ba.GetIsLog(paramnum))
    {
        curvefileStream << "logarithmic";
    }
    else
    {
        curvefileStream << "flat";
    }
    curvefileStream << std::endl;

    long numpoints = ba.GetNumUniquePoints(paramnum);
    double width   = ba.GetKernelWidth(paramnum);
    curvefileStream << "It was created from "
                    << numpoints << " unique data points." << std::endl;
    curvefileStream << "Its kernel width was " << width << "." << std::endl;

    const ParamVector paramvec(true);
    double low  = paramvec[paramnum].GetPrior().GetLowerBound();
    double high = paramvec[paramnum].GetPrior().GetUpperBound();
    curvefileStream << "The prior ranged from " << low << " to " << high << ".";
    if(ba.GetIsLog(paramnum))
    {
        double llow  = SafeLog(low);
        double lhigh = SafeLog(high);
        curvefileStream << " (In log space: " << llow << " to " << lhigh << ").";
    }
    curvefileStream << std::endl;
    curvefileStream << std::endl;

}

double getMinIndex( BayesAnalyzer_1D &  ba,
                    const Parameter &   param,
                    long                paramnum)
{
    double minIndex = ba.GetMinParamValFromCurve(FLAGLONG, paramnum);

    long numRegions = registry.GetDataPack().GetNRegions();
    for(long int i = 0; i < numRegions; i++)
    {
        double thisRegionMin = ba.GetMinParamValFromCurve(i, paramnum);
        minIndex = (thisRegionMin < minIndex) ? thisRegionMin : minIndex;
    }

    return minIndex;
}

double getMaxIndex( BayesAnalyzer_1D &  ba,
                    const Parameter &   param,
                    long                paramnum)
{
    double maxIndex = ba.GetMaxParamValFromCurve(FLAGLONG, paramnum);

    long numRegions = registry.GetDataPack().GetNRegions();
    for(long int i = 0; i < numRegions; i++)
    {
        double thisRegionMax = ba.GetMaxParamValFromCurve(i, paramnum);
        maxIndex = (thisRegionMax > maxIndex) ? thisRegionMax : maxIndex;
    }

    return maxIndex;
}

double getIncrement(BayesAnalyzer_1D &  ba,
                    const Parameter &   param,
                    long                paramnum)
{
    double increment = ba.GetBinWidthFromCurve(FLAGLONG, paramnum);

#ifndef NDEBUG  // Needed only to run assert() in debug mode.
    long numRegions = registry.GetDataPack().GetNRegions();
    for(long int i = 0; i < numRegions; i++)
    {
        double thisIncrement = ba.GetBinWidthFromCurve(i, paramnum);
        assert(increment == thisIncrement);
    }
#endif // NDEBUG

    return increment;
}

void WriteOneConsolidatedCurveFile( std::string         filePrefix,
                                    BayesAnalyzer_1D &  ba,
                                    const Parameter &   param,
                                    long                paramnum)
{
    assert(param.IsVariable());

    // EWFIX.REFACTOR
    string pname = param.GetShortName();
    string::size_type i = pname.find("/");
    while (i != string::npos)
    {
        pname.replace(i,1,"+");
        i = pname.find("/");
    }

    long regions = registry.GetDataPack().GetNRegions();
    long replicates = registry.GetChainParameters().GetNReps();

    // find out min, max, and increment for regions in this param
    // EWFIX -- doesn't handle replicates yet
    double minIndex  = getMinIndex (ba,param,paramnum);
    double maxIndex  = getMaxIndex (ba,param,paramnum);
    double increment = getIncrement(ba,param,paramnum);

    std::string fileName = makeFileName(filePrefix,pname);
    std::ofstream curvefileStream;
    curvefileStream.precision(10);
    curvefileStream.open(fileName.c_str(),std::ios::out);

    long rowCount = 2 + (maxIndex - minIndex) / increment;

    bool hasReplicates = replicates > 1;
    bool multiRegion =   regions > 1;
    long colCount = hasReplicates ? regions * (replicates+1) : regions;
    colCount = multiRegion ? colCount + 1 : colCount;

    bool isLog = ba.GetIsLog(paramnum);

    writeCurveHeader(curvefileStream,pname,paramnum,regions,replicates,ba);

    std::string item;

    // name of parameter, giving Ln or not as appropriate
    if(isLog)
    {
        item = "\"Ln(" + pname + ")\"";
    }
    else
    {
        item = "\"" + pname + "\"";
    }
    curvefileStream << item;

    // first comes the overall estimate
    item = "\"Like(" + pname + ":Overall)\"";
    curvefileStream << "," << item;

    // then, each region in turn
    if(multiRegion)
    {
        for(long regNo=0;regNo < regions; regNo++)
        {
            item = "\"Like(" + pname + ":reg" + ToString(regNo+1)+ ")\"";
            curvefileStream << "," << item;

            if(hasReplicates)
            {
                for(long repNo=0;repNo < replicates; repNo++)
                {
                    item = "\"Like(" + pname + ":reg" + ToString(regNo+1)
                        + ":rep" + ToString(repNo+1)
                        + ")\"";
                    curvefileStream << "," << item;
                }
            }
        }
    }
    else
    {
        if(hasReplicates)
        {
            for(long repNo=0;repNo < replicates; repNo++)
            {
                item = "\"Like(" + pname +
                    + ":rep" + ToString(repNo+1)
                    + ")\"";
                curvefileStream << "," << item;
            }
        }
    }
    curvefileStream << std::endl;

    // Now, the values

    for(long rowIndex = 1; rowIndex < rowCount; rowIndex++)
    {
        double pval = minIndex + (double)(rowIndex - 1) * increment;
        double pvalOrExp = isLog ? exp(pval) : pval;
        curvefileStream << pval;

        double val = ba.GetLikeAtValForAllRegions(pvalOrExp,paramnum);
        curvefileStream << "," << val;

        if(multiRegion)
        {
            for(long regNo=0;regNo<regions;regNo++)
            {
                val = ba.GetLikeAtValForRegion(pvalOrExp,regNo,paramnum);
                curvefileStream << "," << val;
                if(hasReplicates)
                {
                    for(long repNo=0;repNo < replicates; repNo++)
                    {
                        val = ba.GetLikeAtValForReplicate(pvalOrExp,regNo,repNo,paramnum);
                        curvefileStream << "," << val;
                    }
                }
            }
        }
        else
        {
            if(hasReplicates)
            {
                for(long repNo=0;repNo < replicates; repNo++)
                {
                    val = ba.GetLikeAtValForReplicate(pvalOrExp,0,repNo,paramnum);
                    curvefileStream << "," << val;
                }
            }
        }
        curvefileStream << std::endl;
    }

    curvefileStream.close();
    registry.GetUserParameters().AddCurveFileName(fileName);

}

void WriteConsolidatedCurveFiles(std::string filePrefix, BayesAnalyzer_1D& ba)
{

    const ParamVector paramvec(true);
    for (long pnum=0; pnum<static_cast<long>(paramvec.size()); pnum++)
    {
        const Parameter & param = paramvec[pnum];
        if (!param.IsVariable()) continue;
        WriteOneConsolidatedCurveFile(filePrefix,ba,param,pnum);

    }
}

//____________________________________________________________________________________
