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

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

#include <util/generic/string.h>
#include <util/string/cast.h>

namespace NUtil {

    TMongoConnection::TMongoConnection(const TString& uri) {
        Uri = mongoc_uri_new(uri.data());
        if (!Uri)
            ythrow TMongoException() << "Can't parse mongo uri string";

        Client = mongoc_client_new_from_uri(Uri);
        CHECK_WITH_LOG(!!Client);
        TMongoEngine::RegisterConnection();
    }

    TMongoConnection::TMongoConnection(TMongoConnectionsPool* pool)
        : Uri(nullptr)
        , Pool(pool)
    {
        CHECK_WITH_LOG(!!Pool);
        Client = Pool->PopRawClient();
        CHECK_WITH_LOG(!!Client);
        TMongoEngine::RegisterConnection();
    }

    TMongoConnection::~TMongoConnection() {
        ActiveCollections.clear();
        ActiveFs.clear();

        if (!!Pool) {
            Pool->PushRawClient(Client);
        } else {
            mongoc_client_destroy(Client);
            mongoc_uri_destroy(Uri);
        }
        TMongoEngine::ReleaseConnection();
    }

    TMongoGridFs& TMongoConnection::GetGridFs(const TString& db, const TString& fs) {
        TString fullName = db + "." + fs;
        if (!ActiveFs.contains(fullName)) {
            TMongoGridFs::TPtr newFs(new TMongoGridFs(this, db, fs));
            ActiveFs[fullName] = newFs;
        }
        return *(ActiveFs[fullName].Get());
    }

    TMongoCollection& TMongoConnection::GetCollection(const TString& db, const TString& collection) {
        TString fullName = db + "." + collection;
        if (!ActiveCollections.contains(fullName)) {
            TMongoCollection::TPtr newCollection(new TMongoCollection(this, db, collection));
            ActiveCollections[fullName] = newCollection;
        }
        return *(ActiveCollections[fullName].Get());
    }

    mongoc_client_t* TMongoConnection::GetRawConnection() {
        return Client;
    }
}
