#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/config.h>
#include <saas/rtyserver/config/indexer_config.h>

TKeysIndexBuilder::TKeysIndexBuilder(const TRTYServerConfig& rtyConfig, const TString& componentName)
    : NRTYServer::IIndexComponentBuilder(componentName)
    , Config(rtyConfig.ComponentsConfig.Get<TKeysComponentConfig>(NRTYServer::KeysComponentName))
{
    CHECK_WITH_LOG(Config);
}

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

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

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

TKeysIndexBuilderMemory::TKeysIndexBuilderMemory(const TRTYServerConfig& rtyConfig, const TString& componentName)
    : TKeysIndexBuilder(rtyConfig, componentName)
    , Manager(new TKeysIndexManagerMemory(rtyConfig))
{
    Manager->Open();
}

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

void TKeysIndexBuilderMemory::Index(int /*threadID*/, const TParsedDocument& document, const ui32 docId) {
    const TKeysParsedEntity* entity = document.GetComponentEntity<TKeysParsedEntity>(NRTYServer::KeysComponentName);
    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 TKeysIndexBuilderDisk::DoClose(const NRTYServer::TBuilderCloseContext& context) {
    Maker.Close(context.RemapTable);
    return true;
}


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

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

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

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

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

void TKeysIndexBuilderDisk::Index(int threadID, const TParsedDocument& document, const ui32 docId) {
    const TKeysParsedEntity* entity = document.GetComponentEntity<TKeysParsedEntity>(NRTYServer::KeysComponentName);
    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);
}
