#include "merger_config.h"

#include "config.h"
#include "get_value.h"
#include "sys_env.h"

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

namespace NRTYServer {

TMergerConfig::TMergerConfig(const TRTYServerConfig& owner)
    : MaxSegments(10)
    , Enabled(true)
    , Threads(4)
    , MaxDocumentsToMerge(1 << DOC_LEVEL_Bits)
    , MergerCheckPolicy(mcpTime)
    , SegmentsSort(ESegmentsSort::Size)
    , DocIdGenerator(EDocIdGenerator::Default)
    , TimingCheckIntervalMilliseconds(300000)
    , NewIndexDefermentSec(0)
    , MaxDeadlineDocs(0)
    , WriteOption(owner.SysEnv->Io.find("BatchWrite")->second)
    , ClearRemoved(true)
    , LockPolicy(ELockPolicy::OnSwitch)
    , TmpfsDir("")
    , MaxPrepsToUseTmpfs(0)
    , Owner(owner)
{
}

void TMergerConfig::Init(const TYandexConfig::Section& section) {
    Init(section.GetDirectives());
    TYandexConfig::TSectionsMap children = section.GetAllChildren();
    auto mdpk = children.find("MaxDocsPerKps");
    if (mdpk != children.end())
        MaxDocsPerKps.Init(*mdpk->second);
}

void TMergerConfig::Init(const TYandexConfig::Directives& directives) {
    GET_VALUE(MaxSegments);
    GET_VALUE(MaxDocumentsToMerge);
    GET_VALUE(MergerCheckPolicy);
    GET_VALUE(SegmentsSort);
    GET_VALUE(DocIdGenerator);
    GET_VALUE(TimingCheckIntervalMilliseconds);
    GET_VALUE(NewIndexDefermentSec);
    GET_VALUE(MaxDeadlineDocs);
    GET_VALUE(TmpfsDir);
    GET_VALUE(MaxPrepsToUseTmpfs);
    ui32 WriteSpeedBytes = 0;
    GET_VALUE(WriteSpeedBytes);
    if (WriteSpeedBytes) {
        WriteOption = TThrottle::TOptions::FromMaxPerSecond(WriteSpeedBytes, TDuration::Seconds(1));
    }
    GET_VALUE_DEF(ClearRemoved);
    GET_VALUE(Enabled);
    GET_VALUE(Threads);
    if (directives.contains("IndexSwitchSystemLockName") && !directives.contains("IndexSwitchSystemLockFile")) {
        directives.GetValue("IndexSwitchSystemLockName", IndexSwitchSystemLockFile);
    } else {
        GET_VALUE(IndexSwitchSystemLockFile);
    }
    GET_VALUE(LockPolicy);
}

TString TMergerConfig::ToString() const {
    TString s;
    TStringOutput so(s);

    so << "<Merger>" << Endl;
    so << "Enabled : " << Enabled << Endl;
    so << "Threads : " << Threads << Endl;
    so << "MaxSegments : " << MaxSegments << Endl;
    so << "MaxDocumentsToMerge : " << MaxDocumentsToMerge << Endl;
    so << "MergerCheckPolicy : " << MergerCheckPolicy << Endl;
    so << "SegmentsSort : " << SegmentsSort << Endl;
    so << "DocIdGenerator : " << DocIdGenerator << Endl;
    so << "TimingCheckIntervalMilliseconds : " << TimingCheckIntervalMilliseconds << Endl;
    so << "NewIndexDefermentSec : " << NewIndexDefermentSec << Endl;
    so << "MaxDeadlineDocs : " << MaxDeadlineDocs << Endl;
    so << "WriteSpeedBytes : " << WriteOption.GetUnitsPerSecond() << Endl;
    so << "ClearRemoved : " << ClearRemoved << Endl;
    so << "IndexSwitchSystemLockFile : " << IndexSwitchSystemLockFile << Endl;
    so << "LockPolicy : " << LockPolicy << Endl;
    so << "TmpfsDir : " << TmpfsDir << Endl;
    so << "MaxPrepsToUseTmpfs : " << MaxPrepsToUseTmpfs << Endl;
    if (MaxDocsPerKps.Enabled())
        so << MaxDocsPerKps.ToString() << Endl;
    so << "</Merger>" << Endl;
    return s;
}

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

TMergerConfig::TMaxDocsPerKps::TMaxDocsPerKps() {
    Map[0] = 0;
}

ui64 TMergerConfig::TMaxDocsPerKps::Get(ui64 kps) const {
    auto i = Map.find(kps);
    if (i != Map.end())
        return i->second;
    return Map.begin()->second;
}

void TMergerConfig::TMaxDocsPerKps::Init(const TYandexConfig::Section& section) {
    section.GetDirectives().GetValue("Default", Map[0]);
    TYandexConfig::TSectionsMap children = section.GetAllChildren();
    auto i = children.find("Exceptions");
    if (i != children.end()) {
        for (const auto& dir : i->second->GetDirectives()) {
            Map[FromString<ui64>(dir.first)] = FromString<ui64>(dir.second);
        }
    }
}

TString TMergerConfig::TMaxDocsPerKps::ToString() const {
    TStringStream so;
    so << "<MaxDocsPerKps>" << Endl;
    so << "Default:" << Map.begin()->second << Endl;
    if (Map.size() > 1) {
        so << "<Exceptions>" << Endl;
        for (const auto& i : Map) {
            if (i.first)
                so << i.first << ":" << i.second << Endl;
        }
        so << "</Exceptions>" << Endl;
    }
    so << "</MaxDocsPerKps>" << Endl;
    return so.Str();
}

bool TMergerConfig::TMaxDocsPerKps::Enabled() const {
    return Map.size() > 1 || Map.begin()->second;
}

}
