

#include <cstring>
#include <algorithm>

#include "debugcollector.hpp"
#include "util.hpp"

void DebugCollector::flush() {
    if (need_flush_) {
        eng::string str = oss_.str();
        if (!str.empty()) {
            if (is_regular_) n_regular_ += 1;
            lines_.push_back(str);
            oss_.str("");
        }
        need_flush_ = false;
    }
}

DebugCollector::DebugCollector() : n_regular_(0), need_flush_(false), is_regular_(true), active_(false) {
}

DebugCollector::DebugCollector(const eng::string &targets) 
    : n_regular_(0), need_flush_(false), is_regular_(true), active_(false) {
    targets_ = util::split(targets, ',');
    std::sort(targets_.begin(), targets_.end());
}

bool DebugCollector::use(const char *target) {
    int lo = 0;
    int hi = targets_.size();
    while (hi > lo) {
        int mid = (hi + lo) >> 1;
        int cmp = strcmp(targets_[mid].c_str(), target);
        if (cmp == 0) return true;
        if (cmp > 0) hi = mid;
        else lo = mid + 1;
    }
    return false;
}

bool DebugCollector::do_line() {
    if (active_) {
        flush();
        need_flush_ = true;
        is_regular_ = true;
        return true;
    } else return false;
}

bool DebugCollector::do_header() {
    flush();
    need_flush_ = true;
    is_regular_ = false;
    return true;
}

void DebugCollector::dump(std::ostream &os) {
    flush();
    for (const eng::string &line : lines_) {
        os << line << std::endl;
    }
}

DebugBlock::DebugBlock(DebugCollector *dbc, const char *target) {
    dbc_ = dbc;
    if (dbc) {
        n_regular_ = dbc->n_regular_;
        n_lines_ = dbc->lines_.size();
        active_ = (!dbc->active_) && (dbc->use(target));
        if (active_) dbc_->active_ = true;
    }
}

DebugBlock::~DebugBlock() {
    if (dbc_) {
        dbc_->flush();
        // If no regular lines have been added,
        // remove all header lines that were added.
        if (dbc_->n_regular_ == n_regular_) {
            if (dbc_->lines_.size() != n_lines_) {
                dbc_->lines_.resize(n_lines_);
            }
        }
        if (active_) dbc_->active_ = false;
    }
}

