private void findSP(List<int> allResultIds, PartOfSpeech PartOfSpeech, ObjectType type, List<int> excludeIds)
        {
            // из всех текущих id выбираем такие, которые являются заданным типом СЧР
            List<int> idsToAnalyze = new List<int>();
            foreach (var resultId in allResultIds)
            {
                if (_sentence.WordList.Exists(x => x.Id == resultId && x.PartOfSpeech.Value == PartOfSpeech.Value))
                    idsToAnalyze.Add(resultId);
            }

            foreach (var wordId in idsToAnalyze)
            {
                //ищем дочернее слово для СЧР
                List<SentenceWord> childWords = _sentence.WordList.FindAll(x => x.DOM == wordId && !excludeIds.Contains(x.Id));

                foreach (var childWord in childWords)
                {
                    // найдем в текущих результатах такой элемент, id которого либо равен исследуемому, либо в его ServiceParts присутствует исследуемый id - чтобы знать куда добавлять инфу
                    var resultItem = Result.Items.Find(x => x.Id == wordId);
                    if (resultItem == null)
                    {
                        foreach (var i in Result.Items)
                        {
                            if (i.ServiceParts.Concat(i.AddedWordsCase1).Concat(i.AddedWordsCase2).ToList().Exists(x => x.Id == wordId))
                                resultItem = i;
                        }
                    }

                    if (resultItem != null)
                    {
                        // если дочернего слова нет в списке предварительных элеметнов, то добавляем его вместо текущего элемента, присоединяя к нему СЧР с заданным типом СЧР
                        if (!allResultIds.Exists(x => x == childWord.Id))
                        {
                            Stage3ResultElement itemToAdd = new Stage3ResultElement();
                            itemToAdd.IsRestoredFromServicePart = true;
                            itemToAdd.CopyFromSourceWord(childWord);
                            itemToAdd.ObjectType = type;
                            List<SentenceWord> itemAddWords = itemToAdd.ServiceParts.Concat(itemToAdd.AddedWordsCase1).Concat(itemToAdd.AddedWordsCase2).ToList();
                            if (itemAddWords.Find(x => x.Id == wordId) == null)
                                itemToAdd.AddedWordsCase2.Add(_sentence.WordList.Find(x => x.Id == wordId));

                            itemAddWords = itemToAdd.ServiceParts.Concat(itemToAdd.AddedWordsCase1).Concat(itemToAdd.AddedWordsCase2).ToList();
                            if (itemAddWords.Find(x => x.Id == wordId) == null)
                                itemToAdd.AddedWordsCase2.Add(_sentence.WordList.Find(x => x.Id == resultItem.Id));

                            Result.Items.Remove(resultItem);

                            Result.Items.Add(itemToAdd);
                        }
                        // а если такое слово есть, то берем его и объединяем с СЧР, с заданным типом
                        else
                        {
                            List<SentenceWord> resultAddWords = resultItem.ServiceParts.Concat(resultItem.AddedWordsCase1).Concat(resultItem.AddedWordsCase2).ToList();

                            if (resultAddWords.Find(x => x.Id == wordId) == null && resultItem.Id != wordId)
                                resultItem.AddedWordsCase2.Add(_sentence.WordList.Find(x => x.Id == wordId));
                            Result.Items.RemoveAll(x => x.Id == wordId);
                        }
                    }
                    else
                        Debug.WriteLine("IPPI MainParts 583: resultItem == null, sentence " + allResultIds.ToString());

                    allResultIds = getAllMainPartsIds(type);
                }
            }
        }
        public override void ProcessSentence(Sentence sentence)
        {
            _sentence = sentence;
            Debug.Assert(_stage2Result != null);

            // подлежащие
            foreach (var subjectStage2 in _stage2Result.Items.FindAll(x => x.ObjectType == ObjectType.Subject))
            {
                Stage3ResultElement item = new Stage3ResultElement();
                item.CopyFromSourceWord(subjectStage2);
                Result.Items.Add(item);
            }

            // получили некое начальное множество слов-подлежащих. Начинаем процедуру поиска дополнительных слов
            bool allDoneForSubjects = false;

            int lastIterationMainPartsCount, currentIterationMainPartsCount;
            while (!allDoneForSubjects)
            {
                currentIterationMainPartsCount = 0;
                lastIterationMainPartsCount = getAllMainPartsIds(ObjectType.Subject).Count;

                //ищем предлоги и доп слова в имеющейся выборке
                findSP(getAllMainPartsIds(ObjectType.Subject), PartOfSpeech.Preposition, ObjectType.Subject, getAllMainPartsIds(ObjectType.Predicate));
                findAdditionalMainPartWords(ObjectType.Subject);
                findAdditionalSubjects();

                currentIterationMainPartsCount = getAllMainPartsIds(ObjectType.Subject).Count;
                allDoneForSubjects = currentIterationMainPartsCount == lastIterationMainPartsCount;
            }

            // сказуемые
            foreach (var predicateStage2 in _stage2Result.Items.FindAll(x => x.ObjectType == ObjectType.Predicate))
            {
                Stage3ResultElement item = new Stage3ResultElement();
                item.CopyFromSourceWord(predicateStage2);
                Result.Items.Add(item);
            }

            // получили некое начальное множество слов-сказуемых. Начинаем процедуру поиска дополнительных слов
            bool allDone = false;
            while (!allDone)
            {
                currentIterationMainPartsCount = 0;
                lastIterationMainPartsCount = getAllMainPartsIds(ObjectType.Predicate).Count;

                //ищем сочинительные союзы, вспомогательные глаголы и доп слова в имеющейся выборке
                findAdditionalMainPartWords(ObjectType.Predicate);
                findAdditionalPredicates();
                findSP(getAllMainPartsIds(ObjectType.Predicate), PartOfSpeech.VerbHelperFuture, ObjectType.Predicate, getAllMainPartsIds(ObjectType.Subject));
                findSP(getAllMainPartsIds(ObjectType.Predicate), PartOfSpeech.VerbHelperPassive, ObjectType.Predicate, getAllMainPartsIds(ObjectType.Subject));
                findSP(getAllMainPartsIds(ObjectType.Predicate), PartOfSpeech.CoordinatingConjunction, ObjectType.Predicate, getAllMainPartsIds(ObjectType.Subject));

                currentIterationMainPartsCount = getAllMainPartsIds(ObjectType.Predicate).Count;
                allDone = currentIterationMainPartsCount == lastIterationMainPartsCount;
            }

            // удаляем союзы
            Result.Items.RemoveAll(x => x.IsConjuction);
        }
        private void findAdditionalMainPartWords(ObjectType Type)
        {
            bool allDone = false;

            while (!allDone)
            {
                List<SentenceWord> foundAdditionalItems = new List<SentenceWord>();
                foreach (var currentItem in Result.Items.FindAll(x => x.ObjectType == Type))
                {
                    foundAdditionalItems.AddRange(_sentence.WordList.FindAll(x => (x.DOM == currentItem.Id ||
                        currentItem.ServiceParts.Concat(currentItem.AddedWordsCase1).Concat(currentItem.AddedWordsCase2).ToList().FindAll(y => y.Id == x.DOM).Count > 0)
                        && (x.Link.Value == LinkType.Sochin.Value
                        || x.Link.Value == LinkType.SochSouz.Value)));
                }
                allDone = true;

                foreach (var addItem in foundAdditionalItems)
                {
                    Stage3ResultElement item = new Stage3ResultElement();
                    item.CopyFromSourceWord(addItem);
                    item.ObjectType = Type;
                    item.ObjectKind = ObjectKind.Additional;
                    if (!Result.Items.Exists(x => x.Id == addItem.Id))
                    {
                        Result.Items.Add(item);
                        allDone = false;
                    }
                }
            }
        }
 public void CopyFromSourceWord(Stage3ResultElement sourceWord)
 {
     base.CopyFromSourceWord(sourceWord);
     AddedWordsCase1 = sourceWord.AddedWordsCase1;
     AddedWordsCase2 = sourceWord.AddedWordsCase2;
 }