#include "cs_parsed_entity.h"
#include "cs_component.h"
#include <saas/rtyserver/indexer_core/document_parser.h>
#include <saas/rtyserver/config/config.h>
#include <saas/library/behaviour/behaviour.h>

void TCSComponentParser::Parse(TParsingContext& context) const {
    bool needInCheckFullFactorsList =
        context.Command != NRTYServer::TMessage::DEPRECATED__UPDATE_DOCUMENT &&
        context.Command != NRTYServer::TMessage::DELETE_DOCUMENT &&
        GetBehaviour(context.Command).IsContentMessage;

    const NRTYFactors::TConfig& factorsConfig = *context.Result.GetConfig().GetSearcherConfig().Factors;
    TCSParsedEntity* result = context.Result.GetComponentEntity<TCSParsedEntity>(CS_COMPONENT_NAME);
    VERIFY_WITH_LOG(result, "there is not CS entitiy in parsed doc");
    if (needInCheckFullFactorsList && factorsConfig.GetCommonStatFactors().size() != context.Document.CSInfoSize())
        throw yexception() << "Incorrect csInfo blocks count in proto";
    for (ui32 i = 0; i < context.Document.CSInfoSize(); ++i) {
        const NRTYServer::TMessage::TCSInfo& csInfo = context.Document.GetCSInfo(i);
        const NRTYFactors::TCSFactorsList::TPtr fInfo = factorsConfig.GetCommonStatFactors(csInfo.GetName());
        if (!fInfo) {
            throw yexception() << "documents cs block name is incorrect " << csInfo.GetName();
        }
        result->AddCSInfo(csInfo, context.Result, fInfo, needInCheckFullFactorsList);
    }
}


TCSParsedEntity::TCSParsedEntity(TConstructParams& params)
    : TParsedDocument::TParsedEntity(params)
{}

void TCSParsedEntity::MergeToProto(NRTYServer::TParsedDoc& pd, const NRTYServer::TDocSerializeContext& context) const {
    TParsedEntity::MergeToProto(pd, context);
    pd.MutableDocument()->ClearCSInfo();
    for (THashMap<TString, TDocumentCSInfo>::const_iterator i = FactorsByCS.begin(), e = FactorsByCS.end(); i != e; ++i) {
        NRTYServer::TMessage::TCSInfo* info = pd.MutableDocument()->AddCSInfo();
        info->SetName(i->first);
        i->second.Serialize(*info);

    }
}

void TCSParsedEntity::AddCSInfo(const NRTYServer::TMessage::TCSInfo& csInfo,
                                const TParsedDocument& doc, const NRTYFactors::TCSFactorsList::TPtr factorsInfo,
                                bool needInCheckFullFactorsList) {
    VERIFY_WITH_LOG(FactorsByCS.find(csInfo.GetName()) == FactorsByCS.end(), "Incorrect AddCSInfo method usage");
    TDocumentCSInfo& attrs = FactorsByCS[csInfo.GetName()];
    attrs.SetFValue(dynamic_cast<const TCSIndexComponent&>(Component).GetFunction(factorsInfo->GetFunctionName()).GetFResult(doc));
    attrs.SetFactorsInfo(factorsInfo->GetFactorsInfo());
    attrs.AddFactors(csInfo.GetFactors().GetNames(), csInfo.GetFactors().GetValues(), needInCheckFullFactorsList);
}

void TCSParsedEntity::DoApplyPatch(const TParsedDocument& doc) {
    const TCSParsedEntity* patch = doc.GetComponentEntity<TCSParsedEntity>(CS_COMPONENT_NAME);
    if (!patch)
        return;
    for (const auto& factors : patch->FactorsByCS)
        FactorsByCS[factors.first].ApplyPatch(factors.second);
}

void TDocumentCSInfo::ApplyPatch(const TDocumentCSInfo& patch) {
    patch.Apply(Values);
    for (ui32 i = 0; i < patch.GetChecks().size(); ++i)
        if (patch.GetChecks()[i])
            SetValue(i, patch.GetValues()[i], patch.Actions[i], true);
}
