void CMultiWordCreator::CollectArticleInfo(const SArtPointer& artP, EDicType dicType,
                                           yvector<TGztArticle>& gztArticles,
                                           yvector<SDictIndex>& auxArticles,
                                           bool hasTextKeys) const
{
    hasTextKeys = false;

    const CDictsHolder& dicts = *GlobalDictsHolder;
    const TGazetteer& gzt = *dicts.Gazetteer();
    const CIndexedDictionary& auxDict = dicts.GetDict(dicType);

    YASSERT(artP.IsValid());

    if (artP.HasStrType()) {
        NGzt::TArticlePtr art;
        if (gzt.ArticlePool().FindCustomArticleByName(artP.GetStrType(), art))
            gztArticles.push_back(TGztArticle(art));
        else {
            int iArt = auxDict.get_article_index(artP.GetStrType());
            if (iArt != -1)
                auxArticles.push_back(SDictIndex(dicType, iArt));
        }
    } else if (artP.GetKWType().GetDescriptor() == TGztArticle::AuxDicArticleDescriptor()) {
        // do not search gzt articles by TAuxDictArticle kw-type
    } else {
        yhash<TKeyWordType, SKWTypeInfo>::const_iterator kwtype_info = auxDict.m_KWType2Articles.find(artP.GetKWType());
        if (kwtype_info == auxDict.m_KWType2Articles.end() || kwtype_info->second.m_bOnlyTextContent)
            hasTextKeys = true;
        else
            for (size_t i = 0; i < kwtype_info->second.m_Articles.size(); ++i)
                auxArticles.push_back(SDictIndex(dicType, kwtype_info->second.m_Articles[i]));

        const yset<ui32>* custom_offsets = gzt.ArticlePool().FindCustomArticleOffsetsByType(artP.GetKWType().GetDescriptor());
        if (custom_offsets != NULL)
            for (yset<ui32>::const_iterator it = custom_offsets->begin(); it != custom_offsets->end(); ++it)
                gztArticles.push_back(TGztArticle(*it, gzt.ArticlePool()));
    }

    if (!hasTextKeys)
        for (size_t i = 0; i < gztArticles.size(); ++i)
            if (gztArticles[i].HasNonCustomKey()) {
                hasTextKeys = true;
                break;
            }
}
void CAnalyticFormBuilder::ChangeGrammemsAsAnalyticForm(CHomonym& H, const CHomonym& VerbHomonym)
{
    THomonymGrammems old_grammems;
    H.Grammems.Swap(old_grammems);

    for (THomonymGrammems::TFormIter old = old_grammems.IterForms(); old.Ok(); ++old)
        for (THomonymGrammems::TFormIter verb = VerbHomonym.Grammems.IterForms(); verb.Ok(); ++verb) {
            Stroka strPos;

            // auxiliary verb grammems
            const TGramBitSet& VerbGrammems = *verb;
            // meaningful part grammems
            TGramBitSet MainGrammems = *old;

            // final grammems to set
            TGramBitSet ResultedGrammems;

            if (MainGrammems.Has(gInfinitive)) {
                ResultedGrammems = MainGrammems & ~TMorph::AllPOS();
                if (VerbGrammems.Has(gImperative)) {
                    // analytical form for imperatives in singular number does not exist
                    if (VerbGrammems.Has(gSingular))
                        continue;
                    ResultedGrammems.Set(gImperative); // "будем же жить!"
                } else
                    ResultedGrammems |= VerbGrammems & NSpike::AllTimes; // "я стал пилить" или "стану писать"

                ResultedGrammems |= VerbGrammems & NSpike::AllPersons;
                ResultedGrammems |= VerbGrammems & NSpike::AllNumbers;
                ResultedGrammems |= VerbGrammems & NSpike::AllGenders;

                //copy all POS grammems from verb to main
                ResultedGrammems |= VerbGrammems & TMorph::AllPOS();

                H.PutAuxArticle(SDictIndex(TEMPLATE_DICT, VerbHomonym.GetAuxArticleIndex(TEMPLATE_DICT)));
                strPos = "Г";
            } else if (TMorph::IsShortParticiple(MainGrammems)) {
                // "*будем же взяты!"
                if (VerbGrammems.Has(gImperative))
                    continue;

                ResultedGrammems = MainGrammems & ~TMorph::AllPOS();
                // remove any time grammems from participle
                ResultedGrammems &= ~NSpike::AllTimes;

                ResultedGrammems |= VerbGrammems & NSpike::AllPersons;
                ResultedGrammems |= VerbGrammems & NSpike::AllTimes;

                if (VerbGrammems.Has(gImperative))  // ??? the same check second time, always false?
                    ResultedGrammems.Set(gImperative);

                strPos = "ПРИЧАСТИЕ";
                ResultedGrammems |= TGramBitSet(gParticiple, gShort);
            } else if (TMorph::IsShortAdjective(MainGrammems)) {
                if (VerbGrammems.Has(gImperative))
                    continue; // будем cчитать, что "будем же красивы!" - это плохо!
                              // на самом деле, просто не хочется вводить  ее кучу кодов.

                ResultedGrammems =  VerbGrammems;
                ResultedGrammems |= MainGrammems & (NSpike::AllNumbers | NSpike::AllGenders | TGramBitSet(gAnimated, gInanimated));
                ResultedGrammems &= ~TMorph::AllPOS();

                if (ResultedGrammems.Has(gActive))
                    ResultedGrammems &= ~TGramBitSet(gActive);

                ResultedGrammems |= TGramBitSet(gAdjective, gShort);
                strPos = "П";
            } else if (MainGrammems.Has(gPraedic))     // "мне было больно"
            {
                ResultedGrammems = VerbGrammems;
                ResultedGrammems |= NSpike::AllCases & MainGrammems;    //copied from PronounPredk code (commented below) - preserve cases if any
                ResultedGrammems &= ~TMorph::AllPOS();

                if (ResultedGrammems.Has(gActive))
                    ResultedGrammems.Reset(gActive);

                strPos = "ПРЕДК";
                ResultedGrammems |= MainGrammems & TMorph::AllPOS();
            } else if (MainGrammems.Has(gComparative))       // он был больше тебя
            {
                ResultedGrammems = (VerbGrammems & ~TMorph::AllPOS()) | TGramBitSet(gComparative);
                if (ResultedGrammems.Has(gActive))
                    ResultedGrammems.Reset(gActive);

                strPos = "П";
                ResultedGrammems |= MainGrammems & TMorph::AllPOS();
            } else if (TMorph::IsFullAdjective(MainGrammems))
                // resolve disambiguity of homonyms, because analytical forms with full adjectives do not exist.
                continue;

            // "стал писать" "стану писать" "стать писать" - совершенный вид
            if (VerbHomonym.Lemma == kStat)
                ResultedGrammems.Reset(gImperfect).Set(gPerfect);

            // if the auxiliary verb was an infinitive then it is all an infinitive
            //  "быть  лучше" или "должно быть принесено"
            if (VerbHomonym.HasGrammem(gInfinitive)) {
                ResultedGrammems &= ~TMorph::AllPOS();
                ResultedGrammems.Set(gInfinitive);
                strPos = "ИНФИНИТИВ";
            } else if (VerbHomonym.HasGrammem(gGerund))     //  "будучи лишней"
            {
                ResultedGrammems &= ~TMorph::AllPOS();
                ResultedGrammems.Set(gGerund);

                strPos = "ДЕЕПРИЧАСТИЕ";
            }

            if (strPos.empty())
                continue;

            /* do some corrections (code taken from RusGramTab.ProcessPOSAndGrammems) */
            if (ResultedGrammems.HasAll(NSpike::AllCases | TGramBitSet(gAdjPronoun)))
                ResultedGrammems |= NSpike::AllGenders | NSpike::AllNumbers;

            if (ResultedGrammems.Has(gMasFem))
                ResultedGrammems |= TGramBitSet(gMasculine, gFeminine);

            if (!ResultedGrammems.Has(gPraedic) && ResultedGrammems.HasAll(NSpike::AllCases) && !ResultedGrammems.Has(gSingular))
                ResultedGrammems |= TGramBitSet(gSingular, gPlural);

            H.Grammems.AddForm(ResultedGrammems);
        }
}