#include "tuples_list.h"

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

#include <util/generic/algorithm.h>

namespace NOxygen {

    TTuplesListProcessor::TTuplesListProcessor(const TString& outputDir, const TTuplesListsAndFilters& filtersAndLists)
        : Initialized(false)
        , OutputDir(outputDir)
        , FiltersAndLists(filtersAndLists)
    {}

    TTuplesUsageInfo TTuplesListProcessor::GetRequiredTuples() const {
        return TTuplesUsageInfo();
    }

    void TTuplesListProcessor::Start() {
        Initialized = false;
    }

    TFuture<TReturnObjectContext> TTuplesListProcessor::Process(TObjectContext objectContext, ui32 /*tmpObjectId*/) {
        if (Initialized) {
            TTupleNameSet intersection;
            TTupleNameSet objectTuples = objectContext.GetTupleLabels();
            for (auto&& i : Tuples) {
                if (objectTuples.contains(i)) {
                    intersection.insert(i);
                }
            }
            Tuples = intersection;
        } else {
            Initialized = true;
            Tuples = objectContext.GetTupleLabels();
        }
        return TReturnObjectContext::FutureOk;
    }

    void TTuplesListProcessor::Finish(const TDocIdMap* /*map*/) {
        if (Initialized) {
            TTupleNameSetByLayers tuplesByLayers(Tuples, FiltersAndLists);
            SaveTuplesList(OutputDir, tuplesByLayers);
        }
    }

    bool TTuplesListProcessor::LoadTuplesList(const TString& dir, TTupleNameSetByLayers& tuples) {
        TIndexMetadataProcessor processor(dir);
        if (processor->TuplesListSize() == 1 && processor->GetTuplesList(0).GetLayer().empty())
            processor->MutableTuplesList(0)->SetLayer(NRTYServer::NFullArchive::FullLayer);
        for (unsigned int l = 0; l < processor->TuplesListSize(); ++l) {
            TTupleNameSet& ts = tuples[processor->GetTuplesList(l).GetLayer()];
            for (unsigned int i = 0; i < processor->GetTuplesList(l).TuplesSize(); ++i)
                ts.insert(processor->GetTuplesList(l).GetTuples(i));
        }
        return true;
    }

    void TTuplesListProcessor::SaveTuplesList(const TString& dir, const TTupleNameSetByLayers& tuples) {
        TIndexMetadataProcessor processor(dir);
        processor->ClearTuplesList();
        for (const auto& layer : tuples) {
            auto& lay = *processor->AddTuplesList();
            lay.SetLayer(layer.first);
            for (const auto& i : layer.second)
                lay.AddTuples(i);
        }
    }

    TTuplesListProcessor::TTupleNameSetByLayers::TTupleNameSetByLayers(const TTupleNameSet& tuples, const TTuplesListsAndFilters& filters) {
        for (auto&& layer : filters.GetLayersSet()) {
            const TTupleNameSet* tuplesByFilter = filters.GetFilterTuples(layer);
            CHECK_WITH_LOG(tuplesByFilter);
            for (auto&& i : tuples) {
                if (tuplesByFilter->contains(i))
                    operator[](layer).insert(i);

            }
        }
    }

    void TTuplesListProcessor::TTupleNameSetByLayers::Intersect(const TTupleNameSetByLayers& tuplesSet) {
        for (const auto& srcLayer : tuplesSet) {
            NOxygen::TTupleNameSet forDelete;
            NOxygen::TTupleNameSet& resultLayer = operator[](srcLayer.first);
            for (const auto& i : resultLayer)
                if (!srcLayer.second.contains(i))
                    forDelete.insert(i);
            for (const auto& i : forDelete)
                resultLayer.erase(i);
        }
    }
} // namespace NOxygen
