#include "config.h"

#include <saas/rtyserver/config/layers.h>

#include <util/string/join.h>
#include <util/string/split.h>
#include <util/string/strip.h>

namespace {
    template <class TCont>
    inline void SplitStringBySetTo(const TString& string, const TStringBuf& delimiters, TCont& container) {
        TSetDelimiter<const TStringBuf::char_type> delim(delimiters.data());
        TContainerConsumer<TCont> intermediate(&container);
        TSkipEmptyTokens<TContainerConsumer<TCont>> consumer(&intermediate);

        SplitString(string.data(), string.data() + string.size(), delim, consumer);
    }
}

TRTYOxyConfig::TRTYOxyConfig() {
    for (ui32 i = 0; i < COUNT_FILTER_TYPES; ++i) {
        ArchiveLayers[(TFilterType)i];
    }
    const TString fullLayer = NRTYServer::NFullArchive::FullLayer;
    SplitStringBySetTo(fullLayer, " ,", ArchiveLayers[FOR_INDEX]);
}

bool TRTYOxyConfig::DoCheck() const {
    for (auto i = ArchiveLayers.begin(); i != ArchiveLayers.end(); ++i) {
        auto j = i;
        for (++j; j != ArchiveLayers.end(); ++j) {
            for (const auto& layer : i->second) {
                if (j->second.contains(layer)) {
                    FATAL_LOG << layer << " is in both ArchiveLayers" << i->first << " and ArchiveLayers" << j->first << Endl;
                    return false;
                }
            }
        }
    }
    return true;
}

void TRTYOxyConfig::DoInit(const TYandexConfig::Section& componentSection) {
    const TYandexConfig::Directives& dir = componentSection.GetDirectives();
    bool fullLayerUsed = false;

    for (auto& layers : ArchiveLayers) {
        SplitStringBySetTo(dir.Value("ArchiveLayers" + ::ToString(layers.first), Default<TString>()), " ,", layers.second);
        fullLayerUsed |= layers.second.contains(NRTYServer::NFullArchive::FullLayer);
    }
    SplitStringBySetTo(dir.Value("AdditionalRequiredTuples", Default<TString>()), " ,", AdditionalRequiredTuples);
    SplitStringBySetTo(dir.Value("AdditionalRequiredMergeTuples", Default<TString>()), " ,", AdditionalRequiredMergeTuples);
    SplitStringBySetTo(dir.Value("DbgOxyFlags", Default<TString>()), " ,", DbgOxyFlags);

    if (!fullLayerUsed) {
        ythrow yexception() << "FULL layer not configured";
    }
}

void TRTYOxyConfig::DoToString(IOutputStream& so) const {
    for (const auto& layers : ArchiveLayers) {
        so << "ArchiveLayers" << layers.first << ": " << JoinSeq(",", layers.second) << Endl;
    }
    so << "AdditionalRequiredTuples : " << JoinSeq(",", AdditionalRequiredTuples) << Endl;
    so << "AdditionalRequiredMergeTuples : " << JoinSeq(",", AdditionalRequiredMergeTuples) << Endl;
    so << "DbgOxyFlags : " << JoinSeq(",", DbgOxyFlags) << Endl;
}

template<>
void Out<TRTYOxyConfig::TFilterType>(IOutputStream& s, TTypeTraits<TRTYOxyConfig::TFilterType>::TFuncParam p) {
    switch (p) {
    case TRTYOxyConfig::NO: s << "NotFiltered"; break;
    case TRTYOxyConfig::FOR_INDEX: s << "FilteredForIndex"; break;
    case TRTYOxyConfig::FOR_MERGE_COMPLEMENT: s << "MergeComplement"; break;
    case TRTYOxyConfig::FOR_MERGE: s << "FilteredForMerge"; break;
    case TRTYOxyConfig::FOR_SAVE: s << "FilteredForSave"; break;
    case TRTYOxyConfig::COUNT_FILTER_TYPES: FAIL_LOG("invalid usage");
    }
}
