#include "Debug.hpp"

#include "PathHelper.hpp"


std::ofstream TSE::Debug::logFile;
const std::string fileName = "log.txt";
const std::string fileNameOld = "lastlog.txt";

std::vector<void(*)(const std::string&, const TSE::LogEntryType&)> TSE::Debug::onLogCallbacks = std::vector<void(*)(const std::string&, const LogEntryType&)>();

int luaPrintRedirect(lua_State* L)
{
    int n = lua_gettop(L);

    std::string out;
    out.reserve(256);

    for (int i = 1; i <= n; ++i) {
        const char* s = lua_tostring(L, i);
        if (s)
            out += s;
        else
            out += "<non-string>";
        if (i < n)
            out += "\t";
    }

    TSE_LOG(out);
    return 0;
}

void TSE::Debug::Init()
{
    std::string path = "";
    std::string oldpath = "";
    GetAppDataPath(path);
    CombinePaths(oldpath, path, fileNameOld);
    CombinePaths(path, path, fileName);

    if(FileExists(path))
    {
        if(FileExists(oldpath))
        {
            std::remove(oldpath.c_str());
        }
        std::rename(path.c_str(), oldpath.c_str());
    }

    CreateFileWriting(logFile, path);

    luabridge::getGlobalNamespace(TSE_LUA_STATE)
        .beginNamespace("debug")
            .addFunction("log", TSE::Debug::Log)
            .addFunction("warning", TSE::Debug::Warning)
            .addFunction("error", TSE::Debug::Error)
        .endNamespace();
    lua_pushcfunction(TSE_LUA_STATE, luaPrintRedirect);
    lua_setglobal(TSE_LUA_STATE, "print");
}

void TSE::Debug::Log(string msg)
{
    std::cout << msg << std::endl;
    logFile << msg << std::endl;
    for(auto fnc : onLogCallbacks)
    {
        fnc(msg, LogEntryType::Log);
    }
}

void TSE::Debug::Error(string msg)
{
    std::cerr << "[Error] " << msg << std::endl;
    logFile << "[Error] " << msg << std::endl;
    for(auto fnc : onLogCallbacks)
    {
        fnc("[Error] " + msg, LogEntryType::Error);
    }
}

void TSE::Debug::Warning(string msg)
{
    std::cout << "[Warning] " << msg << std::endl;
    logFile << "[Warning] " << msg << std::endl;
    for(auto fnc : onLogCallbacks)
    {
        fnc("[Warning] " + msg, LogEntryType::Warning);
    }
}

void TSE::Debug::Close()
{
    logFile.flush();
    logFile.close();
}

void TSE::Debug::AddCallback(void (*func)(const std::string &, const LogEntryType &))
{
    onLogCallbacks.push_back(func);
}
