#include "archive.h"
#include "builder.h"
#include "config.h"
#include "globals.h"
#include "manager.h"
#include "parsed_entity.h"

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

#include <kernel/tarc/memory/archive_buffer.h>

#include <kernel/tarc/iface/arcface.h>
#include <kernel/tarc/iface/tarcio.h>

#include <util/stream/buffer.h>

namespace {
    const TString ArcSuffix = "fastarc";
}

void TRTYFastArchiveBuilder::Index(int threadID, const TParsedDocument& document, const ui32 docId) {
    auto entity = document.GetComponentEntity<TRTYFastArchiveParsedEntity>(FASTARCHIVE_COMPONENT_NAME);
    const TFastArchiveDocWriter& writer = entity->GetWriter();

    TFastArchiveDoc doc(&GetStringPool());
    {
        TGuard<TMutex> guard(PoolLock);
        doc.FillFrom(writer);
    }
    Index(docId, doc, threadID);
}

void TRTYFastArchiveBuilder::Index(ui32 docId, TFastArchiveDoc& doc, int threadId /*= 0*/) {
    doc.SetDocId(docId);
    DoStoreDocument(threadId, docId, doc);
}

TRTYFastArchiveDiskBuilder::TRTYFastArchiveDiskBuilder(const NRTYServer::TIndexerConfig& indexerConfig,
    const TRTYFastArchiveConfig& componentConfig, const TString& indexFilesPrefix, const TString& componentName)
    : TRTYFastArchiveBuilder(componentName)
    , IndexerConfig(indexerConfig)
    , ComponentConfig(componentConfig)
    , IndexDir(indexFilesPrefix)
{
    for (ui32 i = 0; i < IndexerConfig.Threads; ++i) {
        ArchiveFile.push_back(new TOFStream(IndexDir + "/tmp" + ToString(i) + '_' + ArcSuffix, 1 << 23));
        WriteArchiveHeader(*ArchiveFile.back(), FastArchiveVersion, ComponentConfig.GetFastProperties());
    }
}

bool TRTYFastArchiveDiskBuilder::DoClose(const NRTYServer::TBuilderCloseContext& context) {
    for (ui32 i = 0; i < IndexerConfig.Threads; ++i) {
        ArchiveFile[i]->Flush();
    }
    ArchiveFile.clear();

    TVector<TString> portions;
    const TString target = IndexDir + "/index" + ArcSuffix;
    for (ui32 i = 0; i < IndexerConfig.Threads; i++) {
        portions.push_back(IndexDir + "/tmp" + ToString(i) + '_' + ArcSuffix);
    }

    TFastArchivePortionsMerger portionsMerger(portions, target, FastArchiveVersion,
                                              context.RemapTable ? &(*context.RemapTable)[0] : nullptr,
                                              context.RemapTable ? context.RemapTable->size() : 0);
    return portionsMerger.Merge();
}

void TRTYFastArchiveDiskBuilder::DoStoreDocument(int threadId, ui32 /*docId*/, const TFastArchiveDoc& doc) {
    IOutputStream& out = *ArchiveFile[threadId];
    CHECK_WITH_LOG(doc.Serialize(out));
}

TFastArchiveStringPool& TRTYFastArchiveDiskBuilder::GetStringPool() {
    return StringPool;
}

TRTYFastArchiveMemoryBuilder::TRTYFastArchiveMemoryBuilder(const NRTYServer::TIndexerConfig& indexerConfig, const TRTYFastArchiveConfig& componentConfig, const TString& componentName)
    : TRTYFastArchiveBuilder(componentName)
    , IndexerConfig(indexerConfig)
    , ComponentConfig(componentConfig)
{
    BulkArchive.Docs.resize(IndexerConfig.MaxDocuments);
}

bool TRTYFastArchiveMemoryBuilder::DoClose(const NRTYServer::TBuilderCloseContext& /*context*/) {
    return true;
}

void TRTYFastArchiveMemoryBuilder::DoStoreDocument(int /*threadId*/, ui32 docId, const TFastArchiveDoc& doc) {
    VERIFY_WITH_LOG(docId == doc.GetDocId(), "docid mismatch");
    VERIFY_WITH_LOG(docId < BulkArchive.Docs.size(), "incorrect docid");

    TGuard<TMutex> guard(ArchiveLock);
    BulkArchive.Docs[docId] = doc;
}

NRTYServer::IIndexComponentManager* TRTYFastArchiveMemoryBuilder::GetManager() {
    return new TRTYFastArchiveMemoryManager(BulkArchive, ComponentConfig);
}

TFastArchiveStringPool& TRTYFastArchiveMemoryBuilder::GetStringPool() {
    return BulkArchive.Pool;
}
