public override ISet <ICharacterDeliveryInfo> GetUniqueCharacterDeliveryInfo(string bookCode) { var set = base.GetUniqueCharacterDeliveryInfo(bookCode); set.AddRange(NarratorOverrides.GetNarratorOverridesForBook(bookCode).Select(o => o.Character) .Distinct().Select(c => new NarratorOverrideCharacter(c))); return(set); }
/// <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); }