text: #pragma once
  
  #include <util/generic/vector.h>
  #include <util/generic/stroka.h>
  #include <util/generic/ptr.h>
  #include <util/generic/cast.h>
  #include <util/system/mutex.h>
  #include <util/system/rwlock.h>
  
  #include <kernel/gazetteer/gazetteer.h>
  
  #include <FactExtract/Parser/afdocparser/common/graminfo.h>
  #include <FactExtract/Parser/afdocparser/common/facttypeholder.h>
  #include <FactExtract/Parser/afdocparser/rus/morph.h>
  #include <FactExtract/Parser/afglrparserlib/simplegrammar.h>
  #include <FactExtract/Parser/auxdictlib/articles_parser.h>
  #include <FactExtract/Parser/auxdictlib/dictindex.h>
  
  
  class CHomonym;
  class CWord;
  class CWordVector;
  
  class TBuiltinKWTypes;
  class TGztArticle;
  
  #ifndef TOMITA_EXTERNAL
  class TTagger;
  #endif
  
  
  class CDictsHolder: public CGramInfo
  {
  private:
       // can only be created as singleton
      DECLARE_SINGLETON_FRIEND(CDictsHolder)
      CDictsHolder();
  
  public:
  
    virtual void Init(const Stroka& strDicPath, const Stroka& strBinPath = "");
    void InitFragmDics();
    void InitGazetteerTitleIndex();
  
    virtual void InitNames(const Stroka& strNameFile, ECharset encoding);
    virtual void InitNamesFromProtobuf();
    virtual TSurnamePredictor* LoadSurnamePrediction() const;
    virtual yset<Wtroka> LoadRusExtension() const;
    virtual TMapAbbrev LoadRusAbbrev() const;
  
    virtual ~CDictsHolder();
  
    inline const TGazetteer* Gazetteer() const {
        return m_Gazetteer.Get();
    }
  
    inline const TBuiltinKWTypes& BuiltinKWTypes() const {
        const TBuiltinKWTypes* ptr = m_BuiltinKWTypes.Get();
        YASSERT(ptr != NULL);
        return *ptr;
    }
  
    TKeyWordType FindKWType(const Stroka& kwtypeName) const {
        return m_Gazetteer->ProtoPool().FindMessageTypeByName(kwtypeName);
    }
  
    static bool IsTitleMatch(const TWtringBuf& artTitle, const TWtringBuf& searchTitle, bool exactMatch = false);
    static bool IsArticleMatch(const TGztArticle& art, const SArtPointer& searchArt, bool exactMatch = false);
    static bool IsArticleMatch(const article_t& art, const SArtPointer& searchArt, bool exactMatch = false);
  
    bool GetGztArticleByTitle(const Wtroka& title, TGztArticle& article) const;
    bool GetGztArticleByTitlePrefix(const Wtroka& titlePrefix, TGztArticle& article) const;
  
    //for CHomonym
  
    // returns true if @h has assigned article which art-pointer is contained in @artPointers
    bool HasArtPointer(const CHomonym& h, EDicType dicType, const yset<SArtPointer>& artPointers) const;
  
    // match article by kwtype, or name or name prefix (for article folders)
    bool MatchArticlePtr(const CHomonym& h, EDicType dic, const SArtPointer& art, bool exactMatch = false) const;
    // Return first gzt-article, matched by MatchArticlePtr method
    bool GetMatchingArticle(const CHomonym& h, const SArtPointer& art, TGztArticle& article, bool exactMatch = false) const;
  
    const article_t* GetAuxArticle(const CHomonym& h, EDicType dicType) const;
    virtual Stroka GetStrKWType(const CHomonym& h, ECharset encoding)const;
  
    TKeyWordType GetKWType(const CHomonym& h, EDicType dic) const;
    Wtroka GetArticleTitle(const CHomonym& h, EDicType dic) const;
  
    virtual or_valencie_list_t GetSubjValVars(const CHomonym& h) const;
  
    bool IsSimConjWithCorr(const CHomonym& h) const;
    Wtroka GetUnquotedDictionaryLemma(const CHomonym& h, EDicType dic) const;
  
    virtual bool HasArticle(const CHomonym& h, const SArtPointer& artP, EDicType) const;
  
    inline bool HasKWType(const CHomonym& h, TKeyWordType kwType) const {
        return HasArticle(h, SArtPointer(kwType), KW_DICT);
    }
  
    //for CWord
    virtual bool  HasArticle(const CWord& w, yset<TKeyWordType>&  kw_types) const;
  
    virtual bool  HasArticle(const CWord& w, const SArtPointer& artP) const;
    virtual int   HasArticle_i(const CWord& w, const SArtPointer& artP) const;
  
    virtual TKeyWordType GetAuxKWType(const SDictIndex& di) const;
    virtual Wtroka GetAuxArticleTitle(const SDictIndex& di) const;
  
    const article_t* GetAuxArticle (const SDictIndex& DictIndex) const;
    const article_t* GetAuxArticle(const Wtroka& strTitle, EDicType dicType) const;
    int GetAuxArticleIndex(const Wtroka& strTitle, EDicType dicType) const;
    const article_t* GetEmptyAuxArticle() const;
  
    const CIndexedDictionary& GetDict(EDicType DicType) const;
  
    virtual bool  HasSimConjNotWithCommaObligatory(const CWord& w) const;
  
    const CWorkGrammar& GetGrammarOrRegister(const Stroka& path) const;
  
  #ifndef TOMITA_EXTERNAL
    const TTagger& GetTaggerOrRegister(const Stroka& path, const TGztArticle& taggerArticle) const;
  #endif
  
    inline CContentsCluster* FindCluster(const Wtroka& word, EDicType DicType, ECompType CompType) const {
        YASSERT(DicType < DICTYPE_COUNT);
        return m_Dicts[DicType].m_Contents.FindCluster(word, CompType);
    }
  
    long FindTemplateArticle(const CHomonym& homonym) const;      //grammems here should include both POS and flex grammems
  
    const CFilterStore& GetFilter(TKeyWordType type) const;
  
    size_t GetLemmaCorpusFreq(Stroka Lemma) const;
  
    const TFactTypeHolder& FactTypes() const {
        return *m_FactTypes;
    }
  
    const fact_type_t& RequireFactType(const TStringBuf& factTypeName) const {
        const fact_type_t* ft = m_FactTypes->Find(factTypeName);
        if (EXPECT_FALSE(ft == NULL))
            ythrow yexception() << "Unknown fact type \"" << factTypeName << "\" is requested.";
        return *ft;
    }
  
    const NGzt::TArticlePool::TTitleMap* GetGztArticleIndex() const;
  
  public: // data
    CWorkGrammar  m_SynAnGrammar;
  
  private:
    bool InitSynAnGrammar(const Stroka& dicsPath);
    void InitLemmaFreq();
  
    void InitAuxKwDict();
    void InitGazetteer();
    void InitGazetteerTitleIndexImpl();
    void InitFactTypes();
    void InitRoot(const Stroka& strDicPath, const Stroka& strBinPath = "");
  
    void InitAuxDic(const Stroka& strDicName, const Stroka& text, SDefaultFieldValues& DefaultFieldValues, EDicType dic, bool bInitGrammemsTemplate = false);
    bool ReadDict(dictionary_t& dict, SDefaultFieldValues& DefaultFieldValues, const Stroka& path, const Stroka &text = "");
  
    const SArticleLemmaInfo& GetLemmaInfo(const CHomonym& h, EDicType dic, Wtroka& lemma_text, SArticleLemmaInfo& lemma_info_scratch) const;
  
    //для всех грамматик для всех терминалов записанных как леммы делаем искусственные статьи
    void MakeArtificialArticlesForLemmasFromAllGrammars();
    void MakeArtificialArticlesForLemmasFromGrammar(CWorkGrammar& grammar);
  
    void AddArtIDToKWTypes(CWorkGrammar& grammar);
  
    const CWorkGrammar* GetGrammarOrRegisterInt(const Stroka& path) const;
  
  private:
      Stroka DicPath;
      Stroka DicFdoPath;
      Stroka BinPath;
      Stroka RootFile;
      bool PathCompatibilityMode; // "true" means looking for predefined "fdo" folder
  
    CIndexedDictionary m_Dicts[DICTYPE_COUNT];
  
    TRWMutex GrammarLock, TaggerLock;
    typedef ymap<Stroka, CWorkGrammar*> TGrammarIndex;
    mutable TGrammarIndex RegisteredGrammars;   // access to this member is protected with GrammarLock
  
  #ifndef TOMITA_EXTERNAL
    typedef ymap<Stroka, TTagger*> TTaggerIndex;
    mutable TTaggerIndex RegisteredTaggers;   // access to this member is protected with TaggerLock
  #endif
  
    const CWorkGrammar EmptyGrammar;
  
    THolder<NGzt::TArticlePool::TTitleMap> GztArticleIndex;
    ymap<TKeyWordType,CFilterStore> m_Filters; //фильтры для ключевых слов для ситуаций
  
    bool m_bFramDictsLoaded;
    ymap<Stroka, size_t> m_LemmaFreq;
  
    THolder<TGazetteer> m_Gazetteer;
    yhash<TKeyWordType, yset<TGztArticle> > m_CustomKWTypes;
  
    THolder<TBuiltinKWTypes> m_BuiltinKWTypes;
    THolder<TFactTypeHolder> m_FactTypes;
  
    DECLARE_NOCOPY(CDictsHolder)
  };
  
  inline CDictsHolder* GetMutableGlobalDictsHolder() {
      return CheckedCast<CDictsHolder*>(TMorph::GlobalMutableGramInfo());
  }
  
  inline const CDictsHolder* GetGlobalDictsHolder() {
      return CheckedCast<const CDictsHolder*>(GetGlobalGramInfo());
  }
  
  #define GlobalDictsHolder (GetGlobalDictsHolder())
  
  
  