/**
 * Set the file extension.
 */
void AbstractFileMonitor::addFileExtension(const std::string &s, bool dir)
{
    
    // compute the working filename
    if ( dir == false )
    {
        RbFileManager fm = RbFileManager(filename);
        working_file_name = fm.getFilePath() + fm.getPathSeparator() + fm.getFileNameWithoutExtension() + s + "." + fm.getFileExtension();
    }
    else
    {
        RbFileManager fm = RbFileManager(filename);
        working_file_name = fm.getFilePath() + fm.getPathSeparator() + s + fm.getPathSeparator() + fm.getFileName();
    }
    
}
/**
 * Should we stop now?
 * Yes, if the minimum ESS is larger than the provided threshold.
 */
bool GewekeStoppingRule::stop( size_t g )
{
    
    bool passed = true;
    
    for ( size_t i = 1; i <= numReplicates; ++i)
    {
        std::string fn = filename;
        if ( numReplicates > 1 )
        {
            RbFileManager fm = RbFileManager(filename);
            fn = fm.getFilePath() + fm.getPathSeparator() + fm.getFileNameWithoutExtension() + "_run_" + StringUtilities::to_string(i) + "." + fm.getFileExtension();
        }
        
        TraceContinuousReader reader = TraceContinuousReader( fn );
        
        // get the vector of traces from the reader
        std::vector<Trace> &data = reader.getTraces();
        
        size_t maxBurnin = 0;
        
        for ( size_t j = 0; j < data.size(); ++j)
        {
            Trace &t = data[j];
            const std::vector<double> &v = t.getValues();
            size_t b = burninEst->estimateBurnin( v );
            if ( maxBurnin < b )
            {
                maxBurnin = b;
            }
        }
        
        GewekeTest gTest = GewekeTest( alpha, frac1, frac2 );
        
        for ( size_t j = 0; j < data.size(); ++j)
        {
            RevBayesCore::Trace &t = data[j];
            const std::vector<double> &v = t.getValues();
            t.setBurnin( maxBurnin );
            t.computeStatistics();
            
            passed &= gTest.assessConvergenceSingleChain( v, maxBurnin );
        }
        
    }
    
    
    return passed;
}
void PowerPosteriorAnalysis::summarizeStones( void )
{
    // create the directory if necessary
    RbFileManager f = RbFileManager(filename);
    f.createDirectoryForFile();
    
    std::ofstream outStream;
    outStream.open( filename.c_str(), std::fstream::out);
    outStream << "state\t" << "power\t" << "likelihood" << std::endl;

    /* Append each stone */
    for (size_t idx = 0; idx < powers.size(); ++idx)
    {
        RbFileManager fm = RbFileManager(filename);
        std::string stoneFileName = fm.getFileNameWithoutExtension() + "_stone_" + idx + "." + fm.getFileExtension();
        
        RbFileManager f = RbFileManager(fm.getFilePath(), stoneFileName);

        // read the i-th stone
        std::ifstream inStream;
        inStream.open( f.getFullFileName().c_str(), std::fstream::in);
        if (inStream.is_open())
        {
            bool header = true;
            std::string line = "";
            while ( std::getline (inStream,line) )
            {
                // we need to skip the header line
                if ( header == true )
                {
                    header  = false;
                }
                else
                {
                    outStream << line << std::endl;
                }
                
            }
            inStream.close();
        }
        else
        {
            std::cerr << "Problem reading stone " << idx+1 << " from file " << stoneFileName << "." << std::endl;
        }

    }

}
/**
 * Combine output for the monitor.
 * Overwrite this method for specialized behavior.
 */
void AbstractFileMonitor::combineReplicates( size_t n_reps )
{
    
    if ( enabled == true )
    {
        
        std::fstream combined_output_stream;
        
        int sample_number = 0;
        
        // open the stream to the file
        combined_output_stream.open( filename.c_str(), std::fstream::out);
        combined_output_stream.close();
        combined_output_stream.open( filename.c_str(), std::fstream::in | std::fstream::out);
        
        for (size_t i=0; i<n_reps; ++i)
        {
            std::stringstream ss;
            ss << "_run_" << (i+1);
            std::string s = ss.str();
            RbFileManager fm = RbFileManager(filename);
            std::string current_file_name = fm.getFilePath() + fm.getPathSeparator() + fm.getFileNameWithoutExtension() + s + "." + fm.getFileExtension();
            
            RbFileManager current_fm = RbFileManager(current_file_name);
            std::ifstream current_input_stream;
            
            if ( current_fm.openFile(current_input_stream) == false )
            {
                throw RbException( "Could not open file '" + current_file_name + "'." );
            }
            
            std::string read_line = "";
            size_t lines_skipped = 0;
            size_t lines_to_skip = 1;
            while (std::getline(current_input_stream,read_line))
            {
                ++lines_skipped;
                if ( lines_skipped <= lines_to_skip)
                {
                    if ( i == 0 )
                    {
                        // write output
                        combined_output_stream << read_line;

                        // add a new line
                        combined_output_stream << std::endl;
                    }
                    continue;
                }
                
                std::vector<std::string> fields;
                StringUtilities::stringSplit(read_line, separator, fields);
                
                // add the current sample number
                combined_output_stream << sample_number;
                ++sample_number;
                for (size_t j=1; j<fields.size(); ++j)
                {
                    // add a separator before every new element
                    combined_output_stream << separator;

                    // write output
                    combined_output_stream << fields[j];
                }
                // add a new line
                combined_output_stream << std::endl;
                
            };
            
            fm.closeFile( current_input_stream );

        }
        
        combined_output_stream.close();

    }

}
void PowerPosteriorAnalysis::runStone(size_t idx, size_t gen)
{
    
    // create the directory if necessary
    RbFileManager fm = RbFileManager(filename);
    std::string stoneFileName = fm.getFileNameWithoutExtension() + "_stone_" + idx + "." + fm.getFileExtension();

    RbFileManager f = RbFileManager(fm.getFilePath(), stoneFileName);
    f.createDirectoryForFile();
    
    std::fstream outStream;
    outStream.open( f.getFullFileName().c_str(), std::fstream::out);
    outStream << "state\t" << "power\t" << "likelihood" << std::endl;
    
    // reset the counters for the move schedules
    sampler->reset();
    
//    if ( sampler->getCurrentGeneration() == 0 )
//    {
//    }
    
    /* Reset the monitors */
    //    for (size_t i=0; i<replicates; ++i)
    //    {
    //        for (size_t j=0; i<runs[i].getMonitors().size(); i++)
    //        {
    //            runs[i].getMonitors()[j].reset( kIterations);
    //        }
    //    }
    
    // reset the stopping rules
//    for (size_t i=0; i<rules.size(); ++i)
//    {
//        rules[i].runStarted();
//    }

    
    size_t burnin = size_t( ceil( 0.25*gen ) );
    
    size_t printInterval = size_t( round( fmax(1,gen/20.0) ) );
    size_t digits = size_t( ceil( log10( powers.size() ) ) );
    
    /* Run the chain */
    if ( processActive )
    {
        std::cout << "Step ";
        for (size_t d = size_t( ceil( log10( idx+1.1 ) ) ); d < digits; d++ )
        {
            std::cout << " ";
        }
        std::cout << (idx+1) << " / " << powers.size();
        std::cout << "\t\t";
    }
    
    // set the power of this sampler
    sampler->setLikelihoodHeat( powers[idx] );
    sampler->setStoneIndex( idx );
    
    
    // Monitor
    sampler->startMonitors(gen);
    sampler->monitor(0);
    
    double p = powers[idx];
    for (size_t k=1; k<=gen; k++)
    {
        
        if ( processActive )
        {
            if ( k % printInterval == 0 )
            {
                std::cout << "**";
                std::cout.flush();
            }
        }
        
        sampler->nextCycle( true );

        // Monitor
        sampler->monitor(k);
        
        // sample the likelihood
        if ( k > burnin && k % sampleFreq == 0 )
        {
            // compute the joint likelihood
            double likelihood = sampler->getModelLnProbability();
            outStream << k << "\t" << p << "\t" << likelihood << std::endl;
        }
            
    }
    
    if ( processActive )
    {
        std::cout << std::endl;
    }
    
    outStream.close();
    
    
}