#include "cs_component.h"
#include "cs_builder.h"
#include "cs_manager.h"
#include "cs_parsed_entity.h"
#include <saas/rtyserver/indexer_core/abstract_model.h>
#include <saas/rtyserver/merger/library/merger.h>
#include <kernel/walrus/yxformbuf.h>
#include <library/cpp/wordpos/wordpos.h>
#include <saas/rtyserver/components/erf/erf_disk.h>
#include <saas/rtyserver/components/erf/erf_writer.h>
#include <saas/rtyserver/config/searcher_config.h>
#include <saas/rtyserver/factors/factors_config.h>

namespace {
    bool IsUsed(const TRTYServerConfig& Config) {
        return !!Config.GetSearcherConfig().Factors && Config.GetSearcherConfig().Factors->GetCommonStatFactors().size();
    }
}

TCSIndexComponent::TCSIndexComponent(const TRTYServerConfig& config)
    : IIndexComponent(IsUsed(config))
    , Config(config)
    , FactorsInfo(Config.GetSearcherConfig().Factors->GetCommonStatFactors())
{
    const bool defaultChecked = false;
    const TIndexFile::EPrefetchPolicy defaultPrefetchPolicy = TIndexFile::ppDisable;

    for (TCSFactorsInfo::const_iterator i = FactorsInfo.begin(); i != FactorsInfo.end(); ++i) {
        const TString& file = TNamedBlocksErf::GetErfFileName(i->first);
        IndexFiles.insert(TIndexFile(file, defaultChecked, defaultPrefetchPolicy));
        IndexFiles.insert(TIndexFile(file + ".hdr", defaultChecked, defaultPrefetchPolicy));
        TFunctionPtr func = ICSFunction::TFactory::Construct(i->second->GetFunctionName());
        VERIFY_WITH_LOG(!!func, "unknown cs func %s", i->second->GetFunctionName().data());
        FunctionByName[i->second->GetFunctionName()] = func;
    }
}

NRTYServer::IParsedEntity::TPtr TCSIndexComponent::BuildParsedEntity(NRTYServer::IParsedEntity::TConstructParams& params) const {
    return new TCSParsedEntity(params);
}

NRTYServer::IComponentParser::TPtr TCSIndexComponent::BuildParser() const {
    return new TCSComponentParser{};
}

THolder<NRTYServer::IIndexComponentBuilder> TCSIndexComponent::CreateBuilder(const NRTYServer::TBuilderConstructionContext& context) const {
    return MakeHolder<TCSBuilder>((context.Config.GetType() == "memory") ? "" : context.TempDir.PathName(), context.Config, GetName());
}

THolder<NRTYServer::IIndexComponentManager> TCSIndexComponent::CreateManager(const NRTYServer::TManagerConstructionContext& context) const {
    return MakeHolder<TCSManager>((context.Config.GetType() == "memory") ? "" : context.Dir.PathName(), context.Config.Common.Owner);
}

const TCSIndexComponent::TIndexFiles& TCSIndexComponent::GetIndexFiles() const {
    return IndexFiles;
}

bool TCSIndexComponent::DoMerge(const NRTYServer::TMergeContext& context) const {
    for (TCSFactorsInfo::const_iterator i = FactorsInfo.begin(), e = FactorsInfo.end(); i != e; ++i) {
        TVector<TNamedBlocksErf::TPtr> sources;
        TBasicFactorStorage erfBlock(i->second->GetFactorsList().size());
        for (ui32 src = 0; src < context.Context.Sources.size(); ++src) {
            sources.push_back(new TNamedBlocksErf(context.Context.Sources[src], Config, i->second->GetFactorsInfo(), i->first, false, CS_COMPONENT_NAME));
            sources.back()->Open();
        }
        for (ui32 dst = 0; dst < context.Context.Dests.size(); ++dst) {
            TNamedBlocksErf::TPtr dest = new TNamedBlocksErf(context.Context.Dests[dst], Config, i->second->GetFactorsInfo(), i->first, false, CS_COMPONENT_NAME);
            dest->Open();
            for (ui32 docid = 0; docid < context.Context.Decoder->GetNewDocsCount(dst); ++docid) {
                TRTYMerger::TAddress oldAddress;
                if (context.Context.Decoder->NewToOld(dst, docid, oldAddress) && sources[oldAddress.ClusterId]->ReadRaw(erfBlock, oldAddress.DocId))
                    dest->Add(sources[oldAddress.ClusterId]->GetFValue(oldAddress.DocId), docid, erfBlock);
            }
            dest->Close(nullptr);
        }
        for (ui32 src = 0; src < context.Context.Sources.size(); ++src)
            sources[src]->Close(nullptr);
    }
    return true;
}

