#include "search_config_builder.h"

#include <search/config/default_config.h>

#include <saas/library/daemon_base/daemon/messages.h>
#include <saas/rtyserver/search/factory/factory.h>
#include <saas/rtyserver/pruning_config/pruning_config.h>
#include <saas/rtyserver/config/const.h>
#include <saas/rtyserver/config/config.h>
#include <saas/rtyserver/config/searcher_config.h>
#include <saas/rtyserver/config/indexer_config.h>
#include <saas/rtyserver/config/realm_config.h>
#include <saas/rtyserver/config/common_indexers_config.h>

#include <util/folder/dirut.h>

TSearchConfigBuilder::TSearchConfigBuilder(const TRTYServerConfig& config)
    : Config(config)
    , ExternalSearchCreator(NRTYServer::IExternalSearchCreator::TFactory::Construct(config.GetSearcherConfig().ExternalSearch))
{
}

TSearchConfigBuilder::~TSearchConfigBuilder() {
}

void TSearchConfigBuilder::ApplyMainConfig(TSearchConfig* searchConfig, const TPathName& dir, NRTYServer::TSearcherConfig::TSearchConfigType searcherType) const {
    TString dirPath(dir.PathName());
    SlashFolderLocal(dirPath);

    searchConfig->ProtoCollection_.SetRequestThreads(0);
    searchConfig->ProtoCollection_.SetSnippetThreads(0);
    searchConfig->ProtoCollection_.SetLongReqsThreads(0);
    searchConfig->ProtoCollection_.SetSnippetAdaptiveThreads(Config.GetSearcherConfig().ServerOptions.SnippetAdaptiveThreads);
    searchConfig->ProtoCollection_.SetSnippetAdaptiveQueueSize(Config.GetSearcherConfig().ServerOptions.SnippetAdaptiveQueueSize);
    searchConfig->ProtoCollection_.SetUseSuperMind(false);
    searchConfig->ProtoCollection_.SetCollectionName(Config.GetSearcherConfig().SearchPath.size() ? Config.GetSearcherConfig().SearchPath.front() : TString());
    searchConfig->ProtoCollection_.SetEnableCheckConfig(true);
    searchConfig->UserDirectives["numbers_style"] = "NO_ZEROS";
    searchConfig->UserDirectives["RTYSnippets"] = TString();
    searchConfig->ProtoCollection_.SetPolite(true);
    // Already initialized from TRTYServerConfig::TBallocOptions
    searchConfig->InitializeBallocOptions = false;

    if (searcherType == NRTYServer::TSearcherConfig::sctBase) {
        searchConfig->ProtoServer_.SetPort(Config.GetBaseSearcherConfig().Port);
        searchConfig->OverriddenPort = Config.GetBaseSearcherConfig().Port;
        searchConfig->RawPassages = Config.GetSearcherConfig().RawPassages;
        searchConfig->CommonSourceOptions.TwoStepQuery = Config.GetSearcherConfig().TwoStepQuery;
        for (TVector<TSearchSource>::iterator i = searchConfig->SearchSources.begin(),
            e = searchConfig->SearchSources.end(); i != e; ++i) {
            i->Remote.TwoStepQuery = Config.GetSearcherConfig().TwoStepQuery;
        }
        searchConfig->WorkDir = dirPath;
        searchConfig->IndexDir = dirPath;
        searchConfig->IndexName = dirPath + "index";

        searchConfig->ProtoCollection_.SetUseIndexMapping(true);
        searchConfig->ProtoCollection_.SetReleaseIndexMapping(true);

        if (Config.GetSearcherConfig().DelegationIsActive()) {
            if (!!Config.GetSearcherConfig().LoadLogBase) {
                searchConfig->LoadLog = Config.GetSearcherConfig().LoadLogBase;
            }
            if (!!Config.GetSearcherConfig().PassageLogBase) {
                searchConfig->PassageLog = Config.GetSearcherConfig().PassageLogBase;
            }
        }
        if (!searchConfig->LockIndexFiles.Defined())
            searchConfig->LockIndexFiles = TIndexFileEntries();
        if (!searchConfig->PrefetchIndexFiles.Defined())
            searchConfig->PrefetchIndexFiles = TIndexFileEntries();

        if (Config.NoMorphology) {
            searchConfig->MorphologyLanguages = TLangMask();
        } else {
            if (Config.MorphologyLanguages.empty())
                searchConfig->MorphologyLanguages = LI_DEFAULT_REQUEST_LANGUAGES;
            else
                searchConfig->MorphologyLanguages = NLanguageMasks::CreateFromList(Config.MorphologyLanguages);
            searchConfig->PreferedMorphologyLanguages = NLanguageMasks::CreateFromList(Config.PreferedMorphologyLanguages);
        }
        searchConfig->EnableWildCards = Config.GetSearcherConfig().WildcardSearch;
        searchConfig->ProtoCollection_.SetReArrangeOptions(Config.GetSearcherConfig().ReArrangeOptions);
        searchConfig->ProtoCollection_.SetStartTaskScheduler(false);
        if (Config.Pruning->PruningOn()) {
            searchConfig->Pruning = true;
            searchConfig->UserDirectives["PruningMode"] = "FullSorted";
        } else {
            searchConfig->NoPruningData = true;
        }

        if (!!Config.GetSearcherConfig().ArchivePolicy) {
            if (Config.GetSearcherConfig().ArchivePolicy == ARCHIVE_POLICY_INMEM)
                searchConfig->UserDirectives["InMemoryArchive"] = TString();
            else if (Config.GetSearcherConfig().ArchivePolicy == ARCHIVE_POLICY_INMEMLOCK)
                searchConfig->UserDirectives["LockedInMemoryArchive"] = TString();
            else if (Config.GetSearcherConfig().ArchivePolicy == ARCHIVE_POLICY_MAPMEM)
                searchConfig->UserDirectives["MemoryMappedArchive"] = TString();
            else if (Config.GetSearcherConfig().ArchivePolicy == ARCHIVE_POLICY_MAPMEMLOCK)
                searchConfig->UserDirectives["MemoryMappedArchive"] = "Locked";
            else if (Config.GetSearcherConfig().ArchivePolicy == ARCHIVE_POLICY_DISK)
                searchConfig->UserDirectives["ArchiveOpenMode"] = "File";
            else if (Config.GetSearcherConfig().ArchivePolicy == ARCHIVE_POLICY_DISK_NO_CACHE)
                searchConfig->UserDirectives["ArchiveOpenMode"] = "DirectFile";
            else
                AssertCorrectConfig(false, "%s", "Incorrect ArchivePolicyEnum value");
        }

        searchConfig->ArchiveType = Config.GetSearcherConfig().ArchiveType;
        searchConfig->MultipartArchiveConfig = Config.GetCommonIndexers().TextArchiveParams;

        searchConfig->UserDirectives["NoIndexGeneration"] = "yes";
        if (Config.GetSearcherConfig().ArchiveCacheSizeMb)
            searchConfig->UserDirectives["CacheArchive"] = ::ToString(Config.GetSearcherConfig().ArchiveCacheSizeMb);
        searchConfig->CutHttpFromUrl = false;
        if (!!Config.GetSearcherConfig().ReqAttrList) {
            searchConfig->ReqAttrList.Reset(new TReqAttrList(*Config.GetSearcherConfig().ReqAttrList));
            searchConfig->QueryLanguage = Config.GetSearcherConfig().QueryLanguage;
        }
        if (Config.GetSearcherConfig().Limits.size()) {
            searchConfig->GroupingLimits.Parse(Config.GetSearcherConfig().Limits);
        }
    }

    if (searcherType == NRTYServer::TSearcherConfig::sctMemory) {
        searchConfig->ProtoServer_.SetPort(Config.GetBaseSearcherConfig().Port);
        searchConfig->OverriddenPort = Config.GetBaseSearcherConfig().Port;
        searchConfig->OxygenOptions = Config.GetIndexerMemoryConfig().GetOxygenOptions();
        searchConfig->RealTimeMaxDocs = Max<ui32>(Config.GetIndexerMemoryConfig().MaxDocuments, 10);
        searchConfig->RealTimeGarbageCollectionTime = Config.GetIndexerMemoryConfig().GarbageCollectionTime;
        searchConfig->ProtoCollection_.SetReArrangeOptions(Config.GetSearcherConfig().ReArrangeOptions);
        searchConfig->RealTimeMaxAge = 0;
        searchConfig->RealTimeConfigDir = Config.GetRealmListConfig().GetMainRealmConfig().RealmDirectory; // this is probably obsolete already
        searchConfig->RealTimeMaxExtraUrlHashesPerDocId = Config.GetSearcherConfig().EnableUrlHash ? 0 : Max<size_t>();
        searchConfig->RealTimeLoadC2P = Config.GetIndexerMemoryConfig().RealTimeLoadC2P;
        searchConfig->RealTimeFeatureConfig = Config.GetIndexerMemoryConfig().RealTimeFeatureConfig;
    }

    if (searcherType == NRTYServer::TSearcherConfig::sctMeta) {
        searchConfig->TwoStepQuery = Config.GetSearcherConfig().TwoStepQuery;
        searchConfig->SearchSources[0].ProtoConfig_.SetIndexName(Config.GetRealmListConfig().GetMainRealmConfig().RealmDirectory + "index");
        searchConfig->DefaultScatterOptions.ConnectTimeouts.push_back(TDuration::MilliSeconds(1000));
        searchConfig->ProtoCollection_.SetNTiers(1);
        if (ExternalSearchCreator) {
            searchConfig->CgiFilterOptions = ExternalSearchCreator->CreateMetaCgiFilter();
        }
        searchConfig->TiersLimitTable.push_back(0);
        searchConfig->WaitForAllSources = true;
        searchConfig->DefaultScatterOptions.TimeoutTable.push_back(Config.GetSearcherConfig().GetScatterTimeout());
        if (Config.GetSearcherConfig().RequestLimits.size()) {
            searchConfig->RequestLimits.Parse(Config.GetSearcherConfig().RequestLimits);
        }
        if (Config.GetDaemonConfig().ShouldLockExecutablePages()) {
            searchConfig->ProtoCollection_.SetLockMXNetFile(true); //mlock models on int
        }
        searchConfig->AsyncSearch = Config.GetSearcherConfig().AsyncSearch;
        searchConfig->CacheOptions = Config.GetSearcherConfig().CacheOptions;
        searchConfig->FastCacheOptions = Config.GetSearcherConfig().FastCacheOptions;
        searchConfig->ProtoCollection_.SetReArrangeOptions(Config.GetSearcherConfig().ReArrangeOptions);
        auto& searchPageTemplate = *searchConfig->ProtoCollection_.MutableSearchPageTemplate();
        searchPageTemplate.SetReportMethod(Config.GetSearcherConfig().ReportMethod);
        searchPageTemplate.SetReportModuleName(Config.GetSearcherConfig().ReportModule);
        if (searchPageTemplate.GetReportMethod() == "perl")
            searchPageTemplate.SetReportPhtml(searchPageTemplate.GetReportModuleName());
        searchConfig->ProtoServer_.SetPort(Config.GetSearcherConfig().ServerOptions.Port);
        searchConfig->OverriddenPort = Config.GetSearcherConfig().ServerOptions.Port;
        if (Config.GetSearcherConfig().ReAskBaseSearches) {
            searchConfig->ReAskOptions.ReAskIncompleteSources = true;
            searchConfig->ReAskOptions.MinReAskDelay = TDuration::Zero();
            searchConfig->ReAskOptions.ReAskTimeout = TDuration::Zero();
        }
        if (!!Config.GetSearcherConfig().LoadLogMeta) {
            searchConfig->LoadLog = Config.GetSearcherConfig().LoadLogMeta;
        }
        if (!!Config.GetSearcherConfig().PassageLogMeta) {
            searchConfig->PassageLog = Config.GetSearcherConfig().PassageLogMeta;
        }
        searchConfig->MergeOptions.SkipSameDocids = Config.GetSearcherConfig().SkipSameDocids;
        searchConfig->MergeOptions.MergeMultiplier = Config.GetSearcherConfig().MergeMultiplier;
        searchConfig->BroadcastFetch = Config.GetSearcherConfig().BroadcastFetch;
    }
}
