#include <core/statistics.h>
#include <core/macro.h>
#include <iostream>
#include <sstream>

StatsCounter::StatsCounter(const std::string &category, const std::string &name)
    : m_category(category), m_name(name), m_value(0)
{
    Statistics::getInstance().registerCounter(this);
}

__attribute__((optnone)) Statistics& Statistics::getInstance()
{
    static Statistics instance;
    return instance;
}

void Statistics::registerCounter(StatsCounter *counter)
{
    std::string key = counter->getCategory() + "." + counter->getName();
    if (m_counters.find(key) != m_counters.end())
    {
        std::cerr << "Warning: Counter " << key << " already registered" << std::endl;
    }
    m_counters[key] = counter;
}

__attribute__((optnone)) StatsCounter &Statistics::getCounter(const std::string &category, const std::string &name)
{
    std::string key = category + "." + name;
#pragma omp critical
    {
        if (m_counters.find(key) == m_counters.end())
        {
            StatsCounter *counter = new StatsCounter(category, name);
            return *counter;
        }
    }
    return *m_counters[key];
}

std::string Statistics::getStats()
{
    std::ostringstream oss;
    oss << "------------------------------------------------------------" << std::endl;
    for (auto it = m_counters.begin(); it != m_counters.end(); ++it)
    {
        const StatsCounter *counter = it->second;
        oss << counter->m_category << "." << counter->m_name << std::endl;
        char temp[128];
        snprintf(temp, sizeof(temp), "    -  %s : %lu", counter->getName().c_str(), counter->getValue());
        oss << temp << std::endl;
    }
    oss << "------------------------------------------------------------";

    return oss.str();
}

void Statistics::printStats()
{
    std::cout << getStats() << std::endl;
}

INACTIVE_FN(Statistics_getInstance, &Statistics::getInstance);
INACTIVE_FN(Statistics_getCounter, &Statistics::getCounter);
