/// <summary>
        /// Gets all characters completely covered by the given range of verses. If there are multiple verses, only
        /// characters known to speak in ALL the verses will be included in the returned set, with the exception of
        /// Interruptions, which will be included if they occur in any verse. Returned items will include the accompanying
        /// deliveries if the deliveries are consistent across all verses.
        /// </summary>
        public override HashSet <CharacterSpeakingMode> GetCharacters(int bookId, int chapter, IReadOnlyCollection <IVerse> verses,
                                                                      ScrVers versification = null, bool includeAlternatesAndRareQuotes = false, bool includeNarratorOverrides = false)
        {
            if (versification == null)
            {
                versification = ScrVers.English;
            }

            List <string>                   overrideCharacters = null;
            CharacterSpeakingMode           interruption       = null;
            HashSet <CharacterSpeakingMode> result             = null;

            foreach (var verse in verses)
            {
                var entriesForCurrentVerseBridge = new HashSet <CharacterSpeakingMode>();
                foreach (var v in verse.AllVerseNumbers)
                {
                    var verseRef = new VerseRef(bookId, chapter, v, versification);

                    if (includeNarratorOverrides)
                    {
                        overrideCharacters = NarratorOverrides.GetCharacterOverrideDetailsForRefRange(verseRef,
                                                                                                      verses.Last().EndVerse)?.Select(o => o.Character).ToList();
                        if (overrideCharacters != null && !overrideCharacters.Any())
                        {
                            overrideCharacters = null;
                        }
                        includeNarratorOverrides = false;                         // Don't need to get them again
                    }

                    verseRef.ChangeVersification(ScrVers.English);
                    foreach (var cv in GetSpeakingModesForRef(verseRef))
                    {
                        if (cv.QuoteType == QuoteType.Interruption)
                        {
                            if (interruption == null)
                            {
                                interruption = cv;
                            }
                            continue;
                        }
                        var match = entriesForCurrentVerseBridge.FirstOrDefault(e => m_characterDeliveryEqualityComparer.Equals(e, cv));
                        if (match == null)
                        {
                            entriesForCurrentVerseBridge.Add(cv);
                        }
                        else if (!cv.IsUnusual && match.IsUnusual && !includeAlternatesAndRareQuotes)
                        {
                            // We prefer a regular quote type because in the end we will eliminate Alternate and Rare quotes.
                            // Since we have found a subsequent verse with the unusual character as a "regular" quote type,
                            // we want to replace the unusual entry with the preferred one.
                            entriesForCurrentVerseBridge.Remove(match);
                            entriesForCurrentVerseBridge.Add(cv);
                        }
                    }
                }

                if (result == null)
                {
                    result = entriesForCurrentVerseBridge;
                }
                else
                {
                    PerformPreferentialIntersection(ref result, entriesForCurrentVerseBridge);
                }
            }

            if (result == null)
            {
                throw new ArgumentException("Empty enumeration passed to GetCharacters.", nameof(verses));
            }

            if (interruption != null)
            {
                result.Add(interruption);
            }

            if (!includeAlternatesAndRareQuotes)
            {
                result.RemoveWhere(cv => cv.QuoteType == QuoteType.Alternate || cv.QuoteType == QuoteType.Rare);
            }

            if (overrideCharacters != null)
            {
                foreach (var character in overrideCharacters.Where(c => !result.Any(r => r.Character == c && r.Delivery == Empty)))
                {
                    result.Add(new CharacterSpeakingMode(character, Empty, null, false, QuoteType.Potential));
                }
            }

            return(result);
        }
Exemple #2
0
 // Note QuoteType *cannot* be included in equality determination (nor do we want it to be) because it is not readonly.
 protected bool Equals(CharacterSpeakingMode other)
 {
     return(Equals(Character, other.Character) &&
            Equals(Delivery, other.Delivery) &&
            Equals(Alias, other.Alias));
 }