#include "processor.h"
#include "interface.h"

#include <saas/library/daemon_base/daemon/messages.h>
#include <search/panther/indexing/counts_to_panther/options.h>
#include <robot/library/oxygen/indexer/future/future.h>
#include <library/cpp/logger/global/global.h>


NRTYServer::TPantherProcessor::TPantherProcessor(
    const TFsPath& indexDirectory,
    const TFsPath& tmpDir,
    const NOxygen::TRTYPantherOptions& pantherOptions,
    TAtomicSharedPtr<IThreadPool> taskPool
)
    : NOxygen::TPantherCountsProcessor::TPantherCountsProcessor(
        indexDirectory / "indexcounts.",
        tmpDir,
        pantherOptions.GetMapperConfig(),
        pantherOptions.GetKeyInvOptions(),
        taskPool)
    , IndexDirectory(indexDirectory)
    , MapperConfig(pantherOptions.GetMapperConfig())
    , CountsToPantherOptions(pantherOptions.GetCountsToPantherOptions())
    , TaskPool(taskPool)
    , Implementation(NRTYServer::IPantherImplementation::TFactory::Construct(
        CountsToPantherOptions.HasVersion() ? FromString<NPanther::EPantherVersion>(CountsToPantherOptions.GetVersion()) : NPanther::PantherV0_1
    ))
{
    AssertCorrectConfig(!!Implementation, "missing Panther implementation");
    Booster = Implementation->CreateBoosterProcessor(indexDirectory, pantherOptions.GetCountsToPantherOptions());
}

NRTYServer::TPantherProcessor::~TPantherProcessor() {
}

TString NRTYServer::TPantherProcessor::GetClassName() const {
    return "TRTYPantherProcessor";
}

NOxygen::TTuplesUsageInfo NRTYServer::TPantherProcessor::GetRequiredTuples() const {
    NOxygen::TTuplesUsageInfo result = NOxygen::TPantherCountsProcessor::GetRequiredTuples();
    if (!!Booster) {
        NOxygen::TTuplesUsageInfo slaveTuples = Booster->GetRequiredTuples();
        result.Merge(slaveTuples);
    }
    return result;
}

void NRTYServer::TPantherProcessor::Start() {
    NOxygen::TPantherCountsProcessor::Start();
    if (!!Booster) {
        Booster->Start();
    }
}

NThreading::TFuture<NOxygen::TReturnObjectContext> NRTYServer::TPantherProcessor::Process(NOxygen::TObjectContext objectContext, ui32 tmpObjectId) {
    using namespace NOxygen;

    MaxDocId = std::max(MaxDocId, tmpObjectId);
    NThreading::TFuture<TReturnObjectContext> future = TPantherCountsProcessor::Process(objectContext, tmpObjectId);

    ITupleProcessor* booster = Booster.Get();

    if (Y_UNLIKELY(booster)) {
        NThreading::TFuture<TReturnObjectContext> slaveFuture = booster->Process(objectContext, tmpObjectId);
        slaveFuture.Wait();

        if (slaveFuture.HasException()) {
            slaveFuture.GetValue(); //throw
        }
    }
    return future;
}

void NRTYServer::TPantherProcessor::Finish(const NOxygen::TDocIdMap* map) {
    if (!!Booster) {
        Booster->Finish(map);
    }

    const ui32 count = map ? map->GetSize() : MaxDocId;

    INFO_LOG << "Creating counts file for " << IndexDirectory << Endl;
    NOxygen::TPantherCountsProcessor::Finish(map);

    INFO_LOG << "Creating panther file for " << IndexDirectory << Endl;
    NPanther::TCountsToPantherOptions options;
    NRTYServer::IPantherImplementation::ConvertPantherOptions(CountsToPantherOptions, options);
    options.MinUnigramDocs = (count + 1) / CountsToPantherOptions.GetMaxUnigramIdf();
    options.UseInvMmap = false;

    Implementation->ConvertCountsToPanther(IndexDirectory / "indexcounts.", IndexDirectory / "indexpanther.", options);
    INFO_LOG << "Created Panther for " << IndexDirectory << Endl;
}
