#include "archive_op.h"
#include "attrs_op.h"
#include "doc_infos.h"
#include "docurl_op.h"
#include "keyinv_op.h"
#include "lengths_builder_op.h"
#include "merger.h"
#include "multipart.h"

#include <saas/rtyserver/common/should_stop.h>

#include <ysite/yandex/erf/tf.h>

#include <kernel/tarc/docdescr/docdescr.h>
#include <kernel/tarc/iface/tarcio.h>
#include <kernel/walrus/advmerger.h>
#include <kernel/m2n/remaptable.h>
#include <kernel/m2n/groupattrs.h>

#include <library/cpp/digest/md5/md5.h>
#include <kernel/keyinv/indexfile/seqreader.h>
#include <library/cpp/logger/global/global.h>

#include <util/datetime/base.h>
#include <util/memory/pool.h>
#include <util/stream/file.h>
#include <util/generic/map.h>
#include <util/generic/set.h>
#include <util/generic/utility.h>
#include <util/generic/vector.h>
#include <util/generic/yexception.h>

bool TRTYMerger::MergeActors(const TRTYMerger::TContext& context, TMergeDocInfos& infos, TVector<TSimpleSharedPtr<IMergerOperator> >& actors) {
    for (auto& i : actors) {
        const TString& stage = i->GetName();
        if (ShouldStop(StopFlag)) {
            INFO_LOG << "Merge operation " << stage << " skipped" << Endl;
            return false;
        }

        TInstant timeMerge = Now();
        INFO_LOG << "Start merge operation " << stage << Endl;
        if (!i->Merge(StopFlag, infos, context)) {
            INFO_LOG << "Merge operation " << stage << (ShouldStop(StopFlag) ? " interrupted: " : " failed: ") << Now() - timeMerge << Endl;
            return false;
        }
        INFO_LOG << "Merge operation " << stage << " finished: " << Now() - timeMerge << Endl;
    }
    return true;
}

bool TRTYMerger::MergeIndicies(const TRTYMerger::TContext& context) {
    TMergeDocInfos infos(context.Sources.size(), context.Decoder, context.Info);
    if (infos.IsEmpty()) {
        return true;
    }

    if (!MergeActors(context, infos, MergerOperatorsWithoutUpdater)) {
        return false;
    }
    if (context.Callback)
        context.Callback->OnBeforeUpdatableMerging();
    if (!MergeActors(context, infos, MergerOperatorsWithUpdater)) {
        return false;
    }

    return true;
}

TRTYMerger::TRTYMerger(const std::atomic<bool>* stopFlag, ui64 operations)
    : StopFlag(stopFlag)
{
    if (operations & otKI)
        MergerOperatorsWithoutUpdater.push_back(new TKeyInvMerger);
    if (operations & otArch)
        MergerOperatorsWithoutUpdater.push_back(new TArchiveMerger);
    if (operations & otMpArch)
        MergerOperatorsWithoutUpdater.push_back(new TMultipartArchiveMerger);
    if (operations & otLength)
        MergerOperatorsWithoutUpdater.push_back(new TLengthBuilder);
    if (operations & otDocUrl)
        MergerOperatorsWithoutUpdater.push_back(new TDocUrlMerger);
    if (operations & otAttrs)
        MergerOperatorsWithUpdater.push_back(new TAttrsMerger);
    Y_VERIFY(MergerOperatorsWithoutUpdater.size() + MergerOperatorsWithUpdater.size(), "Incorrect TRTYMerger usage in construction");
}
