/*
 * outputHelper.cpp
 *
 *  Created on: 01. 03. 2021
 *      Author: Martin Prokopic
 */

#include "helpers.h"

using object::Object;
using measurements::MeasurementFrame;
using measurements::TimeDataFrame;
using measurements::MemoryDataFrame;
using measurements::MeasurementResults;

std::ostream & operator << ( std::ostream & os, const std::chrono::microseconds & ms ) {
    os << ms.count ( );
    return os;
}
MeasurementFrame helpers::sumFrames(const ext::vector < MeasurementFrame > & frames ) {
    MeasurementFrame res ( frames[0].name, frames[0].type, frames[0].parentIdx );
    res.subIdxs = frames[0].subIdxs;

    for(auto & frame : frames) {
        res.time.duration += frame.time.duration;
        res.time.inFrameDuration += frame.time.inFrameDuration;
        res.memory.highWatermark += frame.memory.highWatermark;
        res.memory.inFrameHighWatermark += frame.memory.inFrameHighWatermark;
    }

    return res;
}

void helpers::writeResults (  const MeasurementFrame & frame, ext::vector < object::Object > data) {
    data.push_back(Object(frame.time.duration.count()));
    data.push_back(Object(frame.memory.highWatermark));
    printCsvRow(data);
}

void helpers::writeResults ( const std::string & name, ext::vector < object::Object > data ) {
//    auto & frame = findFrameByName(measurements::results(), name);
    auto frames = findFramesByName(measurements::results(), name);
    auto frame = sumFrames(frames);
    writeResults(frame, data);
}

unsigned helpers::rand ( unsigned int min, unsigned int max ) {
    return ( ext::random_devices::semirandom ( ) % ( max - min )) + min;
}

ext::vector<MeasurementFrame> helpers::findFramesByName(const MeasurementResults & results, const std::string & name) {
    ext::vector<MeasurementFrame> res;
    std::function<void(unsigned)> dfs = [&](unsigned idx) {
        auto & n = results.frames[idx].name;
        if(std::equal(n.begin(), n.end(), name.begin(), name.end())) {
            res.push_back ( results.frames[ idx ] );
            return;
        }

        for(unsigned subIdx : results.frames[idx].subIdxs)
            dfs(subIdx);
    };

    dfs(0);
    return res;
}

const measurements::MeasurementFrame &
helpers::findFrameByName ( const measurements::MeasurementResults & results, const std::string & name ) {
    ext::deque < unsigned > bfs;
    bfs.push_back(0);

    while(!bfs.empty()) {
        unsigned idx = bfs.front();
        bfs.pop_front();

        auto & n = results.frames[idx].name;
        if(std::equal(n.begin(), n.end(), name.begin(), name.end()))
            return results.frames[idx];

        for(unsigned subIdx : results.frames[idx].subIdxs)
            bfs.push_back(subIdx);
    }

    throw exception::CommonException("");
}
