#include "read_write_makeup_manager.h"

using namespace NZonesMakeup;

TReadWriteRTYMakeupManager::TReadWriteRTYMakeupManager(const TPathName& indexDir, const TRTYServerConfig& config, bool canReuseDocIds, bool useMemoryPool, bool doClean)
: TRTYMakeupManager(indexDir.PathName() + HdrFileName, indexDir.PathName() + DocsFileName, config, useMemoryPool, doClean)
, CountDocs(0)
, CanReuseDocIds(canReuseDocIds)
, TempStorageAllocator(useMemoryPool)
, AllocatorStorage(useMemoryPool)
{}

TReadWriteRTYMakeupManager::TReadWriteRTYMakeupManager(ui32 docsCount, const TRTYServerConfig& config, bool canReuseDocIds, bool useMemoryPool, bool doClean)
: TRTYMakeupManager(TString(), TString(), config, useMemoryPool, doClean)
, CountDocs(0)
, CanReuseDocIds(canReuseDocIds)
, TempStorageAllocator(useMemoryPool)
, AllocatorStorage(useMemoryPool)
{
    Documents.resize(docsCount, TDocumentMakeup(this, false));
}

void TReadWriteRTYMakeupManager::PrintPoolSizes() const {
    if (!!TempStorageAllocator.GetPool()) {
        TRTYMakeupManager::PrintPoolSizes();
        DEBUG_LOG << "MemPoolTempStorage: " << TempStorageAllocator.GetPool()->MemoryAllocated() << Endl;
    }
}

void TReadWriteRTYMakeupManager::BuildMakeup(ui32 docId) {
    Resize(docId);
    TGuardIncompatibleAction gia(TransactionResize);
    MutableDocument(docId).BuildMakeup();
}

void TReadWriteRTYMakeupManager::MarkDocNoZones(ui32 docId) {
    AddDocument(docId, TDocumentMakeup(this, true), true);
}

void TReadWriteRTYMakeupManager::Resize(ui32 docId) {
    if (Documents.size() <= docId) {
        TGuardTransaction gt(TransactionResize);
        if (Documents.size() <= docId) {
            DEBUG_LOG << "documents makeup size grow from " << Documents.size() << " to " << docId + 1 << Endl;
            Documents.resize(docId + 1, TDocumentMakeup(this, false));
        }
    }
}

void TReadWriteRTYMakeupManager::AddDocument(ui32 docId, const TDocumentMakeup& doc, bool rawCopy) {
    Resize(docId);
    TGuardIncompatibleAction gia(TransactionResize);
    VERIFY_WITH_LOG(CanReuseDocIds || !Documents[docId].GetIsCorrectDocument(), "Duplication document addition for MakeupManager (%d)", docId);
    if (rawCopy)
        Documents[docId] = doc;
    else {
        VERIFY_WITH_LOG(doc.GetIsCorrectDocument(), "doc for add to documents makeup info is incorrect");
        Documents[docId] = TDocumentMakeup(this, doc);
        VERIFY_WITH_LOG(Documents[docId].GetIsCorrectDocument(), "doc after write is incorrect");
    }
    ++CountDocs;
}

void TReadWriteRTYMakeupManager::Serialize(IOutputStream& hdrOut, IOutputStream& docsOut, const TVector<ui32>* remapTable) const {
    TGuardTransaction gt(TransactionResize);
    if (remapTable) {
        TMap<ui32, ui32> remap;
        ui32 countDocs = 0;
        for (int i = 0; i < remapTable->ysize(); i++)
            if ((*remapTable)[i] != REMAP_NOWHERE) {
                remap[(*remapTable)[i]] = i;
                countDocs++;
            }
        ZonesDescription->SerializeForMerger(hdrOut, countDocs);
        DEBUG_LOG << "Serialization for " << countDocs << " docs. real docs count " << CountDocs << Endl;
        for (TMap<ui32, ui32>::const_iterator i = remap.begin(), e = remap.end(); i != e; ++i) {
            const ui32 id = i->second;
            VERIFY_WITH_LOG(Documents[id].GetIsCorrectDocument(), "Incorrect document usage attempt for docId %u of %lu", id, Documents.size());
            Documents[id].Serialize(docsOut, false);
        }
    } else {
        DEBUG_LOG << "Serialization withno remap for " << CountDocs << " docs" << Endl;
        ZonesDescription->SerializeForMerger(hdrOut, CountDocs);
        for (ui32 i = 0; i < CountDocs; ++i) {
            Documents[i].Serialize(docsOut, false);
        }
    }
    hdrOut.Finish();
    docsOut.Finish();
}

void TReadWriteRTYMakeupManager::DeserializeDocuments(IInputStream& in, ui32 version, ui32 countDocs) {
    CountDocs = countDocs;
    TGuardTransaction gt(TransactionResize);
    Documents.resize(CountDocs, TDocumentMakeup(this, true));
    for (ui32 i = 0; i < CountDocs; i++)
        Documents[i].Deserialize(in, version, false);

    PrintPoolSizes();

    if (GetDoClean() && !! AllocatorStorage.GetSpansZonesAllocator().GetPool())
        AllocatorStorage.GetSpansZonesAllocator().GetPool()->Clear();
}

void TReadWriteRTYMakeupManager::DeserializeDocument(ui32 docId, IInputStream& in) {
    int version = 1;
    in.Load(&version, sizeof(version));
    AddDocument(docId, TDocumentMakeup(this, in, version, true), true);
}

void TReadWriteRTYMakeupManager::SerializeDocument(ui32 docId, IOutputStream& out) const {
    TGuardIncompatibleAction gia(TransactionResize);
    out.Write(&SerializeVersion, sizeof(SerializeVersion));
    GetDocument(docId).Serialize(out, true);
}

TSentenceZones TReadWriteRTYMakeupManager::GetSentZones(const ui32 docId, const ui32 sent) const {
    TGuardIncompatibleAction gia(TransactionResize);
    VERIFY_WITH_LOG(docId < Documents.size(), "Incorrect document identifier");
    const TDocumentMakeup& doc = Documents[docId];
    if (CanReuseDocIds && !doc.GetIsCorrectDocument())
        return 0;
    return doc.GetSentZones(sent);
}

const TDocumentMakeup& TReadWriteRTYMakeupManager::GetDocument(int docId) const {
    TGuardIncompatibleAction gia(TransactionResize);
    VERIFY_WITH_LOG(docId < Documents.ysize(), "Incorrect docid for MakeupManager (GetDocument)");
    return Documents[docId];
}

TDocumentMakeup& TReadWriteRTYMakeupManager::MutableDocument(int docId) {
    VERIFY_WITH_LOG(docId < Documents.ysize(), "Incorrect docid for MakeupManager (GetDocument)");
    if (!Documents[docId].GetIsCorrectDocument())
        AddDocument(docId, TDocumentMakeup(this, true), true);
    return Documents[docId];
}

ui32 TReadWriteRTYMakeupManager::GetDocumentsCount() const {
    return Documents.size();
}

ui32 TReadWriteRTYMakeupManager::GetZoneLength(const ui32 docId, const ui32 zoneNumber) const {
    return Documents[docId].GetZoneLengthInWords(zoneNumber);
}

void TReadWriteRTYMakeupManager::StoreZone(ui32 docid, NZonesMakeup::TZoneNumber numZone, ui16 sentBegin, ui16 wordBegin, ui32 wordBeginInDoc, ui16 sentEnd, ui16 wordEnd, ui32 wordEndInDoc) {
    Resize(docid);
    TGuardIncompatibleAction gia(TransactionResize);
    MutableDocument(docid).StoreZone(numZone, sentBegin, wordBegin, wordBeginInDoc, sentEnd, wordEnd, wordEndInDoc);
}

bool TReadWriteRTYMakeupManager::operator != (const TReadWriteRTYMakeupManager& other) const {
    return !operator ==(other);
}

bool TReadWriteRTYMakeupManager::operator == (const TReadWriteRTYMakeupManager& other) const {
    TGuardIncompatibleAction gia(TransactionResize);
    if (GetDocumentsCount() != other.GetDocumentsCount())
        return false;
    for (ui32 i = 0; i < GetDocumentsCount(); ++i)
        if (GetDocument(i) != other.GetDocument(i))
            return false;
    return true;
}

IMakeupWritableStorage* TReadWriteRTYMakeupManager::GetMakeupStorage() {
    return this;
}

TOptionalAllocator& TReadWriteRTYMakeupManager::GetTempStorageAllocator() {
    return TempStorageAllocator;
}

bool TReadWriteRTYMakeupManager::IsCorrectDocument(ui32 docid) const {
    if (docid >= Documents.size())
        return false;
    return Documents[docid].GetIsCorrectDocument();

}

ui32 TReadWriteRTYMakeupManager::GetSentsCount(ui32 docid) const {
    CHECK_WITH_LOG(docid < Documents.size());
    return Documents[docid].GetSentCount();
}

NZonesMakeup::TZoneNumber TReadWriteRTYMakeupManager::DecodeZone(const TString& name) {
    return GetZonesDescription()->Decode(name).ZoneNumber;
}

void TReadWriteRTYMakeupManager::AddZone(const TString& name) {
    GetZonesDescription()->AddZone(name);
}

void TReadWriteRTYMakeupManager::AddZoneUnsafe(const TString& name) {
    GetZonesDescription()->AddZoneUnsafe(name);
}


TMakeupAllocatorsStorage& TReadWriteRTYMakeupManager::GetAllocatorsStorage() {
    return AllocatorStorage;
}
