#include "engine.h"
#include "pool.h"
#include "connection.h"

#include <contrib/libs/mongo-c-driver/libmongoc/src/mongoc/mongoc.h>
#include <library/cpp/logger/global/global.h>


namespace NUtil {

    namespace {
//        inline void NoLogHandler(mongoc_log_level_t, const char*, const char*, void*) {}

        inline void MongoLogHandler(mongoc_log_level_t logLevel, const char* logDomain, const char* message, void*) {
            switch(logLevel) {
            case MONGOC_LOG_LEVEL_ERROR:
                ERROR_LOG << "[MONGO] " << logDomain << " " << message << Endl;
                break;
            case MONGOC_LOG_LEVEL_CRITICAL:
                FATAL_LOG << "[MONGO] " << logDomain << " " << message << Endl;
                break;
            case MONGOC_LOG_LEVEL_WARNING:
                WARNING_LOG << "[MONGO] " << logDomain << " " << message << Endl;
                break;
            case MONGOC_LOG_LEVEL_MESSAGE:
                NOTICE_LOG << "[MONGO] " << logDomain << " " << message << Endl;
                break;
            case MONGOC_LOG_LEVEL_INFO:
                INFO_LOG << "[MONGO] " << logDomain << " " << message << Endl;
                break;
            case MONGOC_LOG_LEVEL_DEBUG:
            //    DEBUG_LOG << "[MONGO] " << logDomain << " " << message << Endl;
            //    break;
            default:
                break;
            }
        }
    }

    TMongoEngine::TMongoEngine() {
        AtomicSet(Connections, 0);
        mongoc_init();
        mongoc_log_set_handler(&MongoLogHandler, nullptr);
    }

    TMongoEngine::~TMongoEngine() {
        CHECK_WITH_LOG(AtomicGet(Connections) == 0);
        mongoc_cleanup();
    }

    void TMongoEngine::ReleaseConnection() {
        AtomicDecrement(Instance().Connections);
    }

    void TMongoEngine::RegisterConnection() {
        AtomicIncrement(Instance().Connections);
    }

    TMongoEngine& TMongoEngine::Instance() {
        return *Singleton<TMongoEngine>();
    }

    TMongoEngine::TConnectionsPoolPtr TMongoEngine::CreateConnectionsPool(const TString& uri) {
        if (!uri)
            ythrow yexception() << "there is no mongo uri";
        return Instance().CreateConnectionsPoolPrivate(uri);
    }

    TMongoEngine::TConnectionPtr TMongoEngine::CreateConnection(const TString& host, ui16 port) {
        TString uri = TString("mongodb://") + host + ":" + ToString(port);
        return Instance().CreateConnectionPrivate(uri);
    }

    TMongoEngine::TConnectionPtr TMongoEngine::CreateConnection(const TString& uri) {
        return Instance().CreateConnectionPrivate(uri);
    }

    TMongoEngine::TConnectionPtr TMongoEngine::CreateConnectionPrivate(const TString& uri) {
        return new TMongoConnection(uri);
    }

    TMongoEngine::TConnectionsPoolPtr TMongoEngine::CreateConnectionsPoolPrivate(const TString& uri) {
        return new TMongoConnectionsPool(uri);
    }
}
