#include "guarded_document.h"
#include "file_index_modify_guard.h"
#include "index_component_storage.h"
#include <util/generic/buffer.h>
#include <saas/protos/rtyserver.pb.h>
#include <saas/library/behaviour/behaviour.h>
#include <saas/rtyserver/common/search_area_modifier.h>
#include <saas/rtyserver/config/config.h>
#include <saas/rtyserver/config/shards_config.h>

void TGuardedDocument::BuildLockName() {
    TString hashData = "URL" + ParsedDoc->GetDocSearchInfo().GetHash().Quote();
    LockName = ToString(FnvHash<ui64>(hashData.data(), hashData.size()));
}

bool TGuardedDocument::IsEmpty() const {
    return ParsedDoc->IsEmpty();
}

TGuardedDocument::~TGuardedDocument() {
    if (!!Replier)
        Replier->Reply();
//    VERIFY_WITH_LOG(IsLocked, "Incorrect guarded document usage");
}

void TGuardedDocument::InitDocument(const NRTYServer::TMessage::TDocument& document) {
    try {
        TIndexComponentsStorage::Instance().GetDocumentParser().Parse(*ParsedDoc, document, Command, NRTYServer::TDocParseContext());
    } catch (...) {
        SetStatus(NRTYServer::TReply::INCORRECT_DOCUMENT, CurrentExceptionMessage());
        Correct = false;
        TString hashData = "INCORRECT:" + ToString(*MessageId) + "/COMMAND" + ToString((int)Command);
        LockName = ToString(FnvHash<ui64>(hashData.data(), hashData.size()));
    }
    if (GetDocument().IsDeprecated()) {
        SetStatus(NRTYServer::TReply::DEPRECATED, "document deadline expired");
        Correct = false;
        TString hashData = "INCORRECT:" + ToString(*MessageId) + "/COMMAND" + ToString((int)Command);
        LockName = ToString(FnvHash<ui64>(hashData.data(), hashData.size()));
    }
    if (Correct)
        BuildLockName();
}

bool TGuardedDocument::TryLockIndexer() {
    if (GetBehaviour(Command).IsModification) {
        if (IsQueryProcessorMessage(Command, GetDocument().GetQueryDel())) {
            TryMultiGuard.Reset(new TTryMultiGuardIncompatibleAction(TFileIndexModifyGuard::Get(), Config.GetShardsConfig().Number));
            if (!TryMultiGuard->Locked())
                return false;
        } else {
            const size_t shard = GetDocument().GetShard();
            TryGuard.Reset(new TTryGuardIncompatibleAction(TFileIndexModifyGuard::Get()[shard]));
            if (!TryGuard->WasAcquired())
                return false;
        }
    }
    return true;
}

bool TGuardedDocument::UnLockIndexers() {
    TryMultiGuard.Destroy();
    TryGuard.Destroy();
    return true;
}
