#pragma once

#include "zones_description_interface.h"

#include <saas/rtyserver/config/fwd.h>
#include <saas/rtyserver/factors/factors_config.h>
#include <saas/rtyserver/merger/library/block_merger.h>
#include <saas/util/transaction.h>
#include <kernel/externalrelev/sent_zones.h>
#include <util/stream/input.h>
#include <util/stream/output.h>

class TZonesDescription: public NZonesMakeup::IZonesDescription, public NRTYMerger::IHeader {
public:
    TZonesDescription(IInputStream& in, const TZonesDescription& baseDescription);
    TZonesDescription(IInputStream& in, const TRTYServerConfig& config);
    TZonesDescription(const TRTYServerConfig& config);
// IHeader
    virtual void Merge(IHeader* header) override;
    virtual void SerializeForMerger(IOutputStream& os, ui32 docsCount) override;
    virtual void DeserializeForMerger(IInputStream& os) override;
// IZonesDescription
    virtual NZonesMakeup::TZoneId GetZoneId(NZonesMakeup::TZoneNumber zoneNumber) const override;
    virtual NZonesMakeup::TZoneCode Decode(const TString& name) override;
    virtual const TString& GetZoneName(NZonesMakeup::TZoneNumber zoneNumber) const override;
    virtual NZonesMakeup::TZoneNumber GetZoneCount() const override;
    virtual NZonesMakeup::TZoneMask GetZonesMask(NZonesMakeup::EZoneRole role) const override;
    virtual void DecodeSpans(NZonesMakeup::TSpansZones& spansZones, const NZonesMakeup::IZonesDescription& currentDescription, bool unsafe = false) override;
    virtual NZonesMakeup::TLengthZones DecodeLengths(const NZonesMakeup::TLengthZones& lengthZones, const NZonesMakeup::IZonesDescription& currentDescription, bool unsafe = false) override;
    virtual void Serialize(IOutputStream& out) override;
    virtual bool Deserialize(IInputStream& in) override;
    virtual NZonesMakeup::TZoneCode AddZone(const TString& name) override;
    virtual NZonesMakeup::TZoneCode AddZoneUnsafe(const TString& name) override;

    // Own methods
    NZonesMakeup::TZoneId DecodeZonesSet(const NZonesMakeup::TZoneId& zonesSet, const NZonesMakeup::IZonesDescription& currentDescription);
    bool AddFactorsData();
    bool CheckFactorsSequence();

    bool GetFeatureIndex(const ui32 zoneNumber, const NZoneFactors::TZoneFactorType zoneFactor, const EFormClass matchLevel, ui32& featureIndex) const;
    ui32 GetFactorsZonesCount() const;
    ui32 GetSnippetsDeniedMask() const {
        return SnippetsDeniedMask;
    }
    ui32 GetTitleZoneMask() const {
        return TitleZoneMask;
    }

private:
    class TZoneInfo {
    public:
        TZoneInfo(const TString& name, const NZonesMakeup::TZoneCode& zc);
        void AddInfo(NZoneFactors::TZoneFactorType zft, EFormClass form, int index);
        int GetIndex(NZoneFactors::TZoneFactorType zft, EFormClass form) const;
        const TString& GetName() const;
        NZonesMakeup::TZoneId GetCode() const { return ZC.ZoneId;  }
    private:
        TString Name;
        TVector<int> IndexByForm;
        NZonesMakeup::TZoneCode ZC;
    };

private:
    void BuildByFactorsConfig();
    bool ZoneIsPermittedToSnippet(const TString& name) const;
    bool ZoneIsTitle(const TString& name) const;
    void AddFactorInfo(const NRTYFactors::TFactor& factor);
    void FillDeniedZones();
    void FillTitleZones();

private:
    static const int SerializeVersion;
    THashMap<TString, NZonesMakeup::TZoneCode> ZoneCodes;
    TVector<TZoneInfo> Zones;
    const NRTYFactors::TConfig* Factors;
    const TRTYServerConfig& Config;
    ITransaction Transaction;
    ui32 SnippetsDeniedMask;
    ui32 TitleZoneMask;
    ui32 FactorsZonesCount; // number of bm25 usage zones
    typedef TSet<TString, TGreater<TString> > TDeniedZones;
    TDeniedZones DeniedZonesTemplates;
    TDeniedZones DeniedZones;
    TDeniedZones TitleZones;
};


typedef TAtomicSharedPtr<TZonesDescription> TZonesDescriptionPtr;

