#pragma once

#include "interfaces.h"

#include <saas/rtyserver/factors/factors_blocks.h>

#include <library/cpp/logger/global/global.h>

namespace NRTYAnn {

    template<class T>
    class TSimpleVectorAccessor : public IDataBlockAccessor {
    public:
        TSimpleVectorAccessor(ui32 size)
            : IDataBlockAccessor(size * sizeof(T))
        {}

        TArrayRef<const char> Get(ui32 index) const override {
            VERIFY_WITH_LOG(!!BlockBegining, "No data was set");
            ui32 offset = index * sizeof(T);
            CHECK_WITH_LOG(offset < Size);
            return TArrayRef<const char>(BlockBegining + offset, sizeof(T));
        }

        bool Set(ui32 index, const TArrayRef<const char>& data) override {
            CHECK_WITH_LOG(data.size() == sizeof(T));
            VERIFY_WITH_LOG(!!BlockBegining, "No data was set");
            ui32 offset = index * sizeof(T);
            CHECK_WITH_LOG(offset + data.size() <= Size);
            memcpy(BlockBegining + offset, data.data(), data.size());
            return true;
        }

        ui32 GetDataCount() const override {
            return Size / sizeof(T);
        }
    };

    class TAnnDataAccessor : public IDataBlockAccessor, public IStreamIdRemapper {
    public:
        TAnnDataAccessor(const NRTYFactors::TAnnFactorsList& streamsInfo)
            : IDataBlockAccessor(streamsInfo.GetFactorsInfo()->GetSumWidthBytes())
            , StreamsInfo(streamsInfo)
        {}

        virtual TArrayRef<const char> Get(ui32 index) const override {
            VERIFY_WITH_LOG(!!BlockBegining, "No data was set");
            ui32 offset = StreamsInfo.GetFactorsInfo()->GetOffsetInBytes(index);
            CHECK_WITH_LOG(offset < Size);
            return TArrayRef<const char>(BlockBegining + offset, StreamsInfo.GetFactorsInfo()->GetFactor(index).Width / 8);
        }

        virtual bool Set(ui32 index, const TArrayRef<const char>& data) override {
            if (data.size() * 8 != StreamsInfo.GetFactorsInfo()->GetFactor(index).Width) {
                return false;
            }
            VERIFY_WITH_LOG(!!BlockBegining, "No data was set");
            ui32 offset = StreamsInfo.GetFactorsInfo()->GetOffsetInBytes(index);
            CHECK_WITH_LOG(offset + data.size() <= Size);
            memcpy(BlockBegining + offset, data.data(), data.size());
            return true;
        }

        virtual ui32 GetDataCount() const override {
            return StreamsInfo.GetFactorsInfo()->GetStaticFactorsCount();
        }

        ui32 GetGlobalStreamIndex(ui32 streamId) const override {
            return StreamsInfo.GetFactorsInfo()->GetFactor(streamId).IndexGlobal;
        }

    private:
        const NRTYFactors::TAnnFactorsList& StreamsInfo;
    };
}
