#include "indexer_config.h"

#include "common_indexers_config.h"
#include "config.h"
#include "get_value.h"

#include <robot/library/oxygen/indexer/processor/protos/config.pb.h>

#include <library/cpp/wordpos/wordpos.h>

namespace NRTYServer {

TIndexerConfig::TIndexerConfig(const NRTYServer::TCommonIndexersConfig& common)
    : Threads(1)
    , DocumentsQueueSize(1000)
    , ConnectionTimeout(60)
    , MaxDocuments(1 << DOC_LEVEL_Bits)
    , MaxSegments(0)
    , Common(common)
    , RealmConfig(nullptr)
{
}

TIndexerConfigMemory::TIndexerConfigMemory(const NRTYServer::TCommonIndexersConfig& common)
    : TIndexerConfig(common)
    , Enabled(true)
    , GarbageCollectionTime(10)
    , MaxDocumentsReserveCapacityCoeff(4)
    , DocumentsLimit(0)
{
    MaxDocuments = 1000;
}

const TIndexerConfigDisk& TIndexerConfigMemory::PretendAsDisk() const {
    CHECK_WITH_LOG(!!DiskConfig);
    return *DiskConfig;
}

TIndexerConfigDisk::TIndexerConfigDisk(const NRTYServer::TCommonIndexersConfig& common)
    : TIndexerConfig(common)
    , CloseThreads(1)
    , SearchEnabled(false)
    , PortionDocCount(900)
    , WaitCloseForMerger(false)
    , OxygenOptionsPtr(nullptr)
{
}

TIndexerConfig::~TIndexerConfig() = default;

void TIndexerConfig::Init(const TYandexConfig::Section* section) {
    InitByDirectives(section->GetDirectives());
    TypePort = GetType() + ":" + ::ToString(Common.ServerOptions.Port);
}

const TString& TIndexerConfig::GetDirectory() const {
    return Common.Owner.IndexDir;
}

void TIndexerConfig::InitByDirectives(const TYandexConfig::Directives& directives) {
    GET_VALUE(DocumentsQueueSize);
    GET_VALUE(Threads);
    GET_VALUE(ConnectionTimeout);
    GET_VALUE(TimeToLiveSec);
    GET_VALUE(TimeToLiveExtra);
    GET_VALUE(AllowSameUrls);
    GET_VALUE(PhaseToLiveSec);
    GET_VALUE(DbgMaxDocumentsTotal);
    GET_VALUE(PreparatesMode);
}

void TIndexerConfigDisk::InitByDirectives(const TYandexConfig::Directives& directives) {
    TIndexerConfig::InitByDirectives(directives);
    GET_VALUE(MaxDocuments);
    GET_VALUE(MaxSegments);
    GET_VALUE(PortionDocCount);
    GET_VALUE(WaitCloseForMerger);
    GET_VALUE(SearchObjectsDirectory);
    GET_VALUE_DEF(CloseThreads);
    GET_VALUE(SearchEnabled);
}

void TIndexerConfigMemory::InitByDirectives(const TYandexConfig::Directives& directives) {
    TIndexerConfig::InitByDirectives(directives);
    if (!TimeToLiveSec)
        TimeToLiveSec = 20;
    GET_VALUE(Enabled);
    GET_VALUE_DEF(GarbageCollectionTime);
    GET_VALUE_DEF(MaxDocumentsReserveCapacityCoeff);
    GET_VALUE_DEF(DocumentsLimit);
    GET_VALUE(RealTimeLoadC2P);
    GET_VALUE(RealTimeFeatureConfig);
    GET_VALUE(RealTimeExternalFilesPath);
    GET_VALUE(RealTimeOxygenOptionsFile);
    RealTimeOxygenOptions = ::GetOxygenOptions(RealTimeOxygenOptionsFile, Common.Owner.ConfigPatcher ? Common.Owner.ConfigPatcher->GetPreprocessor() : nullptr);
    MaxDocuments = 0;
    GET_VALUE(MaxDocuments);
    if (!MaxDocuments)
        MaxDocuments = 2000;
    if (Common.Owner.IndexerDiskConfig->SearchEnabled) {
        DiskConfig.Reset(new TIndexerConfigDisk(Common));
        DiskConfig->InitByDirectives(directives);
        DiskConfig->TimeToLiveSec = TimeToLiveSec;
        DiskConfig->AllowSameUrls = AllowSameUrls;
        DiskConfig->PhaseToLiveSec = PhaseToLiveSec;
        DiskConfig->Threads = Common.Owner.IndexerDiskConfig->Threads;
        DiskConfig->MaxDocuments = MaxDocuments;
        DiskConfig->OxygenOptionsPtr = RealTimeOxygenOptions.Get();
        DiskConfig->PreparatesMode = PreparatesMode;
    }
}

namespace {
    const TString INDEXER_TYPE_DISK("disk");
    const TString INDEXER_TYPE_MEMORY("memory");
}

const TString& TIndexerConfigDisk::GetType() const {
    return INDEXER_TYPE_DISK;
}

const NOxygen::TOxygenOptions* TIndexerConfigDisk::GetOxygenOptions() const {
    return OxygenOptionsPtr ? OxygenOptionsPtr : Common.OxygenOptions.Get();
}

const TString& TIndexerConfigMemory::GetType() const {
    return INDEXER_TYPE_MEMORY;
}

const NOxygen::TOxygenOptions* TIndexerConfigMemory::GetOxygenOptions() const {
    return RealTimeOxygenOptions ? RealTimeOxygenOptions.Get() : Common.OxygenOptions.Get();
}

void TIndexerConfig::ToString(TStringOutput& so) const {
    TString tag = GetType();
    tag.to_upper(0, 1);
    so << "<" << tag << ">" << Endl;
        ToStringDirectives(so);
    so << "</" << tag << ">" << Endl;
}

void TIndexerConfig::ToStringDirectives(TStringOutput& so) const {
    so << "DocumentsQueueSize : " << DocumentsQueueSize << Endl
       << "Threads : " << Threads << Endl
       << "TimeToLiveSec : " << TimeToLiveSec << Endl
       << "TimeToLiveExtra : " << TimeToLiveExtra << Endl
       << "AllowSameUrls: " << AllowSameUrls << Endl
       << "PhaseToLiveSec : " << PhaseToLiveSec << Endl
       << "PreparatesMode : " << PreparatesMode << Endl
       << "ConnectionTimeout : " << ConnectionTimeout << Endl
       << "DbgMaxDocumentsTotal : " << DbgMaxDocumentsTotal << Endl;
}

void TIndexerConfigDisk::ToStringDirectives(TStringOutput& so) const {
    TIndexerConfig::ToStringDirectives(so);
    so << "MaxDocuments : " << MaxDocuments << Endl
       << "CloseThreads : " << CloseThreads << Endl
       << "SearchEnabled : " << SearchEnabled << Endl
       << "PortionDocCount : " << PortionDocCount << Endl
       << "WaitCloseForMerger : " << WaitCloseForMerger << Endl
       << "SearchObjectsDirectory : " << SearchObjectsDirectory << Endl
       << "MaxSegments : " << MaxSegments << Endl;
}

void TIndexerConfigMemory::ToStringDirectives(TStringOutput& so) const {
    TIndexerConfig::ToStringDirectives(so);
    so << "MaxDocuments : " << MaxDocuments << Endl;
    so << "Enabled : " << Enabled << Endl;
    so << "GarbageCollectionTime : " << GarbageCollectionTime << Endl;
    so << "MaxDocumentsReserveCapacityCoeff : " << MaxDocumentsReserveCapacityCoeff << Endl;
    so << "DocumentsLimit : " << DocumentsLimit << Endl;
    so << "RealTimeLoadC2P : " << RealTimeLoadC2P << Endl;
    so << "RealTimeFeatureConfig : " << RealTimeFeatureConfig << Endl;
    so << "RealTimeExternalFilesPath : " << RealTimeExternalFilesPath << Endl;
    so << "RealTimeOxygenOptionsFile : " << RealTimeOxygenOptionsFile << Endl;
    if (DiskConfig) {
        so << "<DiskConfig>" << Endl;
        DiskConfig->ToStringDirectives(so);
        so << "</DiskConfig>" << Endl;
    }
}

}
