#include "component.h"
#include "builder.h"
#include "config.h"
#include "disk_manager.h"
#include "manager.h"
#include "parsed_entity.h"

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

#include <saas/util/system/stream_digest.h>

TTrigramComponent::TTrigramComponent(const TRTYServerConfig& config)
    : IIndexComponent(config.ComponentsSet.contains(NRTYServer::TrigramComponentName))
    , Config(config)
{
    IndexFiles.insert(TIndexFile(NRTYServer::TrigramKeyFileName, true, TIndexFile::ppLock));
    IndexFiles.insert(TIndexFile(NRTYServer::TrigramInvFileName, true, TIndexFile::ppLock));
}

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

TString TTrigramComponent::GetName() const {
    return NRTYServer::TrigramComponentName;
}

bool TTrigramComponent::GetInfoChecker(NRTYServer::TInfoChecker& info) const {
    info.Version = 2;
    return true;
}

THolder<NRTYServer::IIndexComponentBuilder> TTrigramComponent::CreateBuilder(const NRTYServer::TBuilderConstructionContext& context) const {
    if (context.Config.GetType() == "memory") {
        return MakeHolder<TTrigramIndexBuilderMemory>(context.Config.Common.Owner, GetName());
    }

    return MakeHolder<TTrigramIndexBuilderDisk>(context.TempDir, context.Config, GetName());
}

THolder<NRTYServer::IIndexComponentManager> TTrigramComponent::CreateManager(const NRTYServer::TManagerConstructionContext& context) const {
    switch (context.IndexType) {
        case IIndexController::PREPARED:
        case IIndexController::FINAL:
            return MakeHolder<TTrigramIndexManagerDisk>(context.Dir.PathName(), context.Config.Common.Owner);
        case IIndexController::DISK:
        case IIndexController::MEMORY:
            return nullptr;
        default:
            FAIL_LOG("Incorrect index type");
    }
}

bool TTrigramComponent::DoMerge(const NRTYServer::TMergeContext& context) const {
    try {
        TRTYMerger::TContext contextCopy = context.Context;
        contextCopy.AdditionalSuffixIndexName = ".trigram.";
        contextCopy.WriteSentLens = false;
        TRTYMerger merger(nullptr, TRTYMerger::otKI);
        merger.MergeIndicies(contextCopy);
        return true;
    } catch (...) {
        ERROR_LOG << "Can't merge Trigram Component for " << context.Context.TempDir << ": " << CurrentExceptionMessage() << Endl;
        return false;
    }
}

NRTYServer::IComponentParser::TPtr TTrigramComponent::BuildParser() const {
    return new TTrigramComponentParser(Config);
}

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

bool TTrigramComponent::CheckKeyInv(const NRTYServer::TNormalizerContext& context) const {
    try {
        TRTYKIReader ki(context.Dir.PathName(), "trigram");
        ki.Open();
        bool result = ki.IsOpen();
        if (result)
            ki.Close();
        else
            ERROR_LOG << "Cannot open keyinv in " << context.Dir.PathName() << "/index.trigram" << Endl;
        return result;
    } catch (...) {
        ERROR_LOG << "Cannot open keyinv in " << context.Dir.PathName() << "/index.trigram:" << CurrentExceptionMessage() << Endl;
        return false;
    }
}

bool TTrigramComponent::DoAllRight(const NRTYServer::TNormalizerContext& context) const {
    TTrigramIndexManagerDisk manager(context.Dir.PathName(), context.Config);
    NRTYServer::TManagerTryGuard guard(manager);
    return manager.IsOpened();
}

bool TTrigramComponent::CheckConfig() const {
    return true;
}

void TTrigramComponent::CheckAndFix(const NRTYServer::TNormalizerContext& context) const {
    if (!CheckKeyInv(context))
        FixKeyInv(context);
}

void TTrigramComponent::FixKeyInv(const NRTYServer::TNormalizerContext& context) const {
    INFO_LOG << "Try repair keyinv in " << context.Dir.PathName() << "/index.trigram..." << Endl;
    const NRTYServer::TRealmConfig& realmConfig = Config.GetRealmListConfig().GetRealmConfigByConfigName(context.GetRealmName());
    TTrigramIndexBuilderDisk builder(context.Dir, realmConfig.GetIndexerConfigDisk(), GetName());
    builder.Start();
    builder.Stop();
    builder.Close(NRTYServer::TBuilderCloseContext(context.Dir, context.Dir, nullptr, nullptr));
    INFO_LOG << "Try repair keyinv in " << context.Dir.PathName() << "/index.trigram...OK" << Endl;
}
