/***************************** LICENSE START ***********************************

 Copyright 2022 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvLog.h"

#include <cassert>
#include <iostream>
#include <regex>
#include <vector>

#include "MvAbstractApplication.h"
#include "MvMiscellaneous.h"

MvAbstractApplication* MvLog::app_ = nullptr;
std::string MvLog::detailsBeginId_="_MVLOGBEGINDETAILS_";
std::string MvLog::detailsEndId_="_MVLOGENDDETAILS_";

//---------------------------------
// MvLog
//---------------------------------

MvLog::MvLog() = default;

MvLog::~MvLog()
{
    output(os_.str());
}

void MvLog::registerApp(MvAbstractApplication* app)
{
    app_ = app;
}

MvLog& MvLog::popup()
{
    popup_ = true;
    return *this;
}

std::ostringstream& MvLog::info()
{
    level_ = MvLogLevel::INFO;
    return os_;
}

std::ostringstream& MvLog::err()
{
    level_ = MvLogLevel::ERROR;
    return os_;
}

std::ostringstream& MvLog::errNoExit()
{
    level_ = MvLogLevel::ERROR;
    exitOnError_ = false;
    return os_;
}

std::ostringstream& MvLog::warn()
{
    level_ = MvLogLevel::WARN;
    return os_;
}

std::ostringstream& MvLog::dbg()
{
    level_ = MvLogLevel::DBG;
    return os_;
}

// to be used in MV_FN_INFO with __PRETTY_FUNCTION__
std::string MvLog::formatFuncInfo(const std::string& t)
{
    // extracts the function name from the __PRETTY_FUNCTION__
    // string (as t) and returns either:
    // - "classsame::function() "
    // - "function() "

    static std::regex rx(R"((\w+(::)?\w+\())");
    auto it = std::sregex_iterator(t.begin(), t.end(), rx);
    if (it != std::sregex_iterator()) {
        return it->str() + ") ";
    }
    return t + " ";
}

// to be used in MV_FN_INFO with __func__
std::string MvLog::formatFuncInfoBasic(const std::string& t)
{
    return t + "() ";
}

void MvLog::output(const std::string& oriMsg)
{
    if (app_) {
        std::string msg, details;
        parseDetails(oriMsg, msg, details);
        if (exitOnError_ && level_ == MvLogLevel::ERROR) {
            std::string t = msg + "\n\nThe program will terminate!";
            app_->toLog(t, details, level_, popup_);
            app_->exitWithError();
        }
        else {
            app_->toLog(msg, details, level_, popup_);
        }
    }
}

void MvLog::parseDetails(const std::string& ori, std::string& msg, std::string& details)
{
    auto pos = ori.find(detailsBeginId_);
    if (pos != std::string::npos) {
        msg = ori.substr(0, pos);
        details = ori.substr(pos + detailsBeginId_.size());
        details = metview::replace(details, detailsEndId_, "");
    } else {
        msg = ori;
    }
}

const std::string& MvLog::detailsBegin()
{
    return detailsBeginId_;
}

const std::string& MvLog::detailsEnd()
{
    return detailsEndId_;
}

//--------------------------------------------
// Overload ostringstream for various objects
//--------------------------------------------

// std::ostream& operator <<(std::ostream &stream,const std::vector<std::string>& vec)
//{
//     stream << "[";
//     for(size_t i=0; i < vec.size(); i++)
//     {
//         if(i > 0) stream << ",";
//         stream << vec[i];
//     }
//     stream << "]";

//    return stream;
//}
