#pragma once
#include "factor.h"
#include "factors_abstract.h"
#include "factors_description.h"
#include <util/generic/ptr.h>
#include <util/generic/hash.h>
#include <util/generic/string.h>

namespace NRTYFactors {

    class TFactorsListByFunction {
    private:
        TFactorsList FactorsList;
        THolder<IRTYStaticFactors> StatFactorsInfo;
        TString FunctionName;
    public:

        typedef TAtomicSharedPtr<TFactorsListByFunction> TPtr;

        TFactorsListByFunction(const TString& fName)
            : FunctionName(fName)
         {}

        bool CheckFactorName(const TString& name, ui32& index) {
            for (ui32 i = 0; i < FactorsList.size(); ++i) {
                if (FactorsList[i].Name == name) {
                    index = i;
                    return true;
                }
            }
            return false;
        }

        TFactorsList& GetFactorsList() {
            return FactorsList;
        }

        const IRTYStaticFactors* GetFactorsInfo() const {
            VERIFY_WITH_LOG(!!StatFactorsInfo, "Incorrect TQSFactorsList usage");
            return StatFactorsInfo.Get();
        }

        void BuildStatFactorsInfo() {
            StatFactorsInfo.Reset(new TSimpleStaticFactorsDescription(FactorsList));
        }

        const TString& GetFunctionName() const {
            return FunctionName;
        }
    };

    typedef TFactorsListByFunction TQSFactorsList;
    typedef TFactorsListByFunction TCSFactorsList;
    typedef TFactorsListByFunction TAnnFactorsList;
    typedef TFactorsList TGeoLayersList;

    typedef THashMap<TString, TQSFactorsList::TPtr> TQSFactorsHashList;
    typedef THashMap<TString, TCSFactorsList::TPtr> TCSFactorsHashList;
    typedef THashMap<TString, TAnnFactorsList::TPtr> TAnnFactorsHashList;

    template <class TFactorsHashList, class TFactorsData>
    class TFactorsHashListWriter: public IFactorsInfoWriter {
    private:
        TFactorsHashList& List;
        TString Prefix;
    public:
        TFactorsHashListWriter(TFactorsHashList& list, const TString& prefix): List(list) {
            Prefix = prefix;
        }

        void Clear() {
            List.clear();
        }

        virtual void Finish() {
            for (typename TFactorsHashList::iterator i = List.begin(), e = List.end(); i != e; ++i) {
                i->second->BuildStatFactorsInfo();
            }
        }

        void Write(const TString& sectionName, const TFactor& factor) {
            VERIFY_WITH_LOG(sectionName.size() > Prefix.size() && sectionName.StartsWith(Prefix), "Incorrect writer usage for %s", sectionName.data());
            TString qsName = sectionName.substr(Prefix.size());
            if (List.find(qsName) == List.end())
                List[qsName] = new TFactorsData(qsName);
            List[qsName]->GetFactorsList().push_back(factor);
        }
    };

    class TRTYBlocksFactorsInfo {
    private:
        bool MainFlag;
        TVector<bool> BlocksFlags;
        bool Initialized;
    public:

        TRTYBlocksFactorsInfo() {
            Initialized = false;
            MainFlag = false;
        }

        void Init(ui32 size) {
            Initialized = true;
            BlocksFlags.resize(size, false);
        }

        bool IsUsed() const {
            return MainFlag;
        }

        bool IsUsed(ui32 blockNum) const {
            Y_ASSERT(BlocksFlags.size() > blockNum);
            return BlocksFlags[blockNum];
        }

        void Set(ui32 index) {
            VERIFY_WITH_LOG(Initialized, "Incorrect TRTYBlocksFactorsInfo usage");
            VERIFY_WITH_LOG(BlocksFlags.size() > index, "Incorrect block index %u", index);
            MainFlag = true;
            BlocksFlags[index] = true;
        }
    };


};
