#include "builder.h"
#include "const.h"
#include "config.h"
#include "parsed_entity.h"

#include <saas/rtyserver/config/common_indexers_config.h>
#include <saas/rtyserver/config/indexer_config.h>

TTrigramIndexBuilder::TTrigramIndexBuilder(const TRTYServerConfig& rtyConfig, const TString& componentName)
    : NRTYServer::IIndexComponentBuilder(componentName)
    , Config(rtyConfig.ComponentsConfig.Get<TTrigramComponentConfig>(NRTYServer::TrigramComponentName))
{
    CHECK_WITH_LOG(Config);
}

bool TTrigramIndexBuilderMemory::Stop() {
    return true;
}

bool TTrigramIndexBuilderMemory::DoClose(const NRTYServer::TBuilderCloseContext& /*context*/) {
    Manager->Close();
    return true;
}

NRTYServer::IIndexComponentManager* TTrigramIndexBuilderMemory::GetManager() {
    return Manager;
}

TTrigramIndexBuilderMemory::TTrigramIndexBuilderMemory(const TRTYServerConfig& rtyConfig, const TString& componentName)
    : TTrigramIndexBuilder(rtyConfig, componentName)
    , Manager(new TTrigramIndexManagerMemory(rtyConfig))
{
    Manager->Open();
}

bool TTrigramIndexBuilderMemory::Start() {
    return true;
}

void TTrigramIndexBuilderMemory::Index(int /*threadID*/, const TParsedDocument& document, const ui32 docId) {
    const TTrigramParsedEntity* entity = document.GetComponentEntity<TTrigramParsedEntity>(NRTYServer::TrigramComponentName);
    CHECK_WITH_LOG(entity);
    Manager->RemoveDocids({docId});
    for (auto&& i : entity->GetData()) {
        for (auto&& hash : i.second) {
            TSet<SUPERLONG> positions;
            for (auto pos : hash.second) {
                TWordPosition::SetDoc(pos, docId);
                positions.insert(pos);
            }
            Manager->AddData(i.first, hash.first, positions);
        }
    }
}

bool TTrigramIndexBuilderDisk::DoClose(const NRTYServer::TBuilderCloseContext& context) {
    Maker.Close(context.RemapTable);
    return true;
}

void TTrigramIndexBuilderDisk::DoDiscard() {
    Maker.Discard();
}

NRTYServer::IIndexComponentManager* TTrigramIndexBuilderDisk::GetManager() {
    return nullptr;
}

TTrigramIndexBuilderDisk::TTrigramIndexBuilderDisk(const TPathName& dir, const NRTYServer::TIndexerConfig& config, const TString& componentName)
    : TTrigramIndexBuilder(config.Common.Owner, componentName)
    , Maker(config.Threads, dir.PathName(), "index.trigram.", 10000)
{
}

bool TTrigramIndexBuilderDisk::Start() {
    Maker.Start();
    return true;
}

bool TTrigramIndexBuilderDisk::Stop() {
    Maker.Stop();
    return true;
}

void TTrigramIndexBuilderDisk::Index(int threadID, const TParsedDocument& document, const ui32 docId) {
    const TTrigramParsedEntity* entity = document.GetComponentEntity<TTrigramParsedEntity>(NRTYServer::TrigramComponentName);
    CHECK_WITH_LOG(entity);
    TMap<TString, TVector<SUPERLONG>> positionsByKeys;
    for (auto&& i : entity->GetData()) {
        for (auto&& hash : i.second) {
            const TString key(TString::Join(i.first, '@', hash.first));
            TVector<SUPERLONG>& positions = positionsByKeys[key];
            for (SUPERLONG pos : hash.second) {
                TWordPosition::SetDoc(pos, docId);
                positions.push_back(pos);
            }
        }
    }
    for (auto& pos : positionsByKeys) {
        Maker.StorePositions(threadID, pos.first.data(), pos.second.data(), pos.second.size());
    }
    Maker.IncDoc(threadID);
}
