#pragma once

#include "makeup_manager.h"
#include "document_makeup.h"
#include <library/cpp/wordpos/wordpos.h>

template<class T>
class TReadOnlyRTYMakeupManager : public TRTYMakeupManager {
public:
    TReadOnlyRTYMakeupManager(const TPathName& indexDir, const TRTYServerConfig& config);

public: // ISentenceZonesReader
    virtual TSentenceZones GetSentZones(const ui32 docId, const ui32 sent) const;
    virtual ui32 GetZoneLength(const ui32 docId, const ui32 zoneNumber) const;

public: // NRTYServer::IIndexComponentManager
    virtual ui32 GetDocumentsCount() const;

public: // IMakeupStorage
    virtual TMakeupAllocatorsStorage& GetAllocatorsStorage();

protected:
    virtual void DeserializeDocuments(IInputStream& in, ui32 version, ui32 countDocs);
    virtual bool IsCorrectDocument(ui32 docid) const;
    virtual ui32 GetSentsCount(ui32 docid) const;

private:
    struct TDocumentDescription {
        ui64 SentsBegin : DOC_LEVEL_Bits + BREAK_LEVEL_Bits;
        ui64 LengthZonesBegin : DOC_LEVEL_Bits + 7;
        ui16 SentsCount : BREAK_LEVEL_Bits;
        ui8 LengthZonesCount : 7;
    };
    typedef TVector<TDocumentDescription> TDocuments;
    typedef TVector<NZonesMakeup::TLengthZones::value_type> TLengthZonesStorage;
    typedef TVector<T> TSentsMakeupStorage;
    TSentsMakeupStorage SentsMakeup;
    TLengthZonesStorage LengthZones;
    TDocuments Documents;
};

template <class T>
TReadOnlyRTYMakeupManager<T>::TReadOnlyRTYMakeupManager(const TPathName& indexDir, const TRTYServerConfig& config)
    : TRTYMakeupManager(indexDir.PathName() + HdrFileName, indexDir.PathName() + DocsFileName, config, false, true)
{}

template <class T>
TSentenceZones TReadOnlyRTYMakeupManager<T>::GetSentZones(const ui32 docId, const ui32 sent) const {
    VERIFY_WITH_LOG(docId < Documents.size(), "Incorrect document identifier");
    const TDocumentDescription& doc = Documents[docId];
    return sent < doc.SentsCount ? SentsMakeup[doc.SentsBegin + sent] : 0;
}

template <class T>
ui32 TReadOnlyRTYMakeupManager<T>::GetZoneLength(const ui32 docId, const ui32 zoneNumber) const {
    VERIFY_WITH_LOG(docId < Documents.size(), "Incorrect document identifier");
    const TDocumentDescription& doc = Documents[docId];
    return zoneNumber < doc.LengthZonesCount ? LengthZones[doc.LengthZonesBegin + zoneNumber] : 0;
}

template <class T>
ui32 TReadOnlyRTYMakeupManager<T>::GetDocumentsCount() const {
    return Documents.size();
}

template <class T>
void TReadOnlyRTYMakeupManager<T>::DeserializeDocuments(IInputStream& in, ui32 version, ui32 countDocuments) {
    Documents.resize(countDocuments);
    for (size_t i = 0; i < countDocuments; ++i) {
        NZonesMakeup::TDocumentMakeup doc(this, true);
        doc.Deserialize(in, version, false);
        ui64 zonesCount = doc.GetZoneLength().size();
        ui64 sentsCount = doc.GetSentsMakeup().size();
        Documents[i].LengthZonesBegin = LengthZones.size();
        Documents[i].LengthZonesCount = zonesCount;
        Documents[i].SentsBegin = SentsMakeup.size();
        Documents[i].SentsCount = sentsCount;
        SentsMakeup.insert(SentsMakeup.end(), doc.GetSentsMakeup().begin(), doc.GetSentsMakeup().end());
        LengthZones.insert(LengthZones.end(), doc.GetZoneLength().begin(), doc.GetZoneLength().end());
    }
    NOTICE_LOG << "Makeup info for " << DocsFileToOpen << ". Documents: " << Documents.size() << ". SentsMakeup: " << SentsMakeup.size() << ". LengthZones: " << LengthZones.size() << Endl;
}

template <class T>
bool TReadOnlyRTYMakeupManager<T>::IsCorrectDocument(ui32 docid) const {
    return docid < Documents.size();
}

template <class T>
ui32 TReadOnlyRTYMakeupManager<T>::GetSentsCount(ui32 docid) const {
    CHECK_WITH_LOG(docid < Documents.size());
    return Documents[docid].SentsCount;
}

template <class T>
TMakeupAllocatorsStorage& TReadOnlyRTYMakeupManager<T>::GetAllocatorsStorage() {
    return TMakeupAllocatorsStorage::Default();
}
