Пример #1
0
        public virtual void AddEntriesFor(int bookNumber, Block block)
        {
            bool added = false;

            foreach (var verse in block.AllVerses)
            {
                if (!ControlCharacterVerseData.Singleton.GetCharacters(bookNumber, block.ChapterNumber, verse, m_versification, true, true)
                    .Any(c => c.Character == block.CharacterId && c.Delivery == (block.Delivery ?? Empty)))
                {
                    foreach (var v in verse.AllVerseNumbers)
                    {
                        var verseRef = new VerseRef(bookNumber, block.ChapterNumber, v, m_versification);
                        verseRef.ChangeVersification(ScrVers.English);
                        added |= base.AddCharacterVerse(new CharacterVerse(verseRef.BBBCCCVVV, block.CharacterId, block.Delivery ?? Empty, Empty, true));
                    }
                }
            }

            if (added)
            {
                Analytics.Track("AddCharacter", new Dictionary <string, string>
                {
                    { "verseReference", block.GetReferenceString(BCVRef.NumberToBookCode(bookNumber)) },
                    { "characterId", block.CharacterId },
                    { "delivery", block.Delivery }
                });
            }
        }
Пример #2
0
        public static bool ChangeToEnglishVersification(ref VerseRef startRef, ref int endVerse, out int endChapter)
        {
            if (endVerse < startRef.VerseNum)
            {
                throw new ArgumentOutOfRangeException(nameof(endVerse), "Range must be in a single chapter and end verse must be greater than start verse. " +
                                                      $"Details: {nameof(startRef)} = {startRef}; {nameof(endVerse)} = {endVerse}");
            }

            bool     endAndStartAreSame = endVerse == startRef.VerseNum;
            VerseRef endRef             = endAndStartAreSame ? startRef : new VerseRef(startRef)
            {
                VerseNum = endVerse
            };

            startRef.ChangeVersification(ScrVers.English);
            if (startRef.VerseNum == 0)             // Currently, we don't support overriding verse 0 (Hebrew subtitle in Psalms) -- this allows us to define overrides with chapter ranges.
            {
                endChapter = -1;
                return(false);
            }

            if (endAndStartAreSame)             // Calling change versification is kind of expensive, so this is a helpful optimization
            {
                endRef = startRef;
            }
            else
            {
                endRef.ChangeVersification(ScrVers.English);
            }
            endVerse   = endRef.VerseNum;
            endChapter = endRef.ChapterNum;
            return(true);
        }
Пример #3
0
 /// <summary>
 /// Sends a "Santa Fe" focus message which can be used by other applications (such as Paratext)
 /// to navigate to the same Scripture reference
 /// </summary>
 /// <param name="currRef"></param>
 public static void SendScrReference(this VerseRef currRef)
 {
     if (currRef != null && currRef.Valid)
     {
         currRef.ChangeVersification(ScrVers.English);
         SantaFeFocusMessageHandler.SendFocusMessage(currRef.ToString());
     }
 }
Пример #4
0
        /// <summary>
        /// This method is preferred over the string bookId counterpart for performance reasons (so we don't have to look up the book number)
        /// </summary>
        public IEnumerable <CharacterVerse> GetCharacters(int bookId, int chapter, int initialStartVerse, int initialEndVerse = 0, int finalVerse = 0, ScrVers versification = null)
        {
            if (versification == null)
            {
                versification = ScrVers.English;
            }

            IEnumerable <CharacterVerse> result;

            if (initialEndVerse == 0 || initialStartVerse == initialEndVerse)
            {
                var verseRef = new VerseRef(bookId, chapter, initialStartVerse, versification);
                verseRef.ChangeVersification(ScrVers.English);
                result = m_lookup[verseRef.BBBCCCVVV];
            }
            else
            {
                int start = new BCVRef(bookId, chapter, initialStartVerse).BBCCCVVV;
                int end   = new BCVRef(bookId, chapter, initialEndVerse).BBCCCVVV;
                result = Enumerable.Empty <CharacterVerse>();
                for (int i = start; i <= end; i++)
                {
                    result = result.Union(m_lookup[i]);
                }
            }
            if (finalVerse == 0 || result.Count() == 1)
            {
                return(result);
            }

            var nextVerse = Math.Max(initialStartVerse, initialEndVerse) + 1;

            while (nextVerse <= finalVerse)
            {
                var verseRef = new VerseRef(bookId, chapter, nextVerse, versification);
                verseRef.ChangeVersification(ScrVers.English);
                IEnumerable <CharacterVerse> nextResult = m_lookup[verseRef.BBBCCCVVV];
                if (!nextResult.Any())
                {
                    nextVerse++;
                    continue;
                }
                if (!result.Any())
                {
                    result = nextResult;
                    nextVerse++;
                    continue;
                }
                var intersection = nextResult.Intersect(result, m_characterDeliveryEqualityComparer);
                if (intersection.Count() == 1)
                {
                    result = intersection;
                    break;
                }
                nextVerse++;
            }
            return(result);
        }
        public VerseRef GetBlockVerseRef(Block block = null, ScrVers targetVersification = null)
        {
            block = block ?? m_navigator.CurrentBlock;
            var verseRef = new VerseRef(BCVRef.BookToNumber(CurrentBookId), block.ChapterNumber, block.InitialStartVerseNumber, Versification);

            if (targetVersification != null)
            {
                verseRef.ChangeVersification(targetVersification);
            }
            return(verseRef);
        }
Пример #6
0
        /// <summary>
        /// Gets all project-specific character/delivery pairs for the given verse or bridge.
        /// </summary>
        public override HashSet <CharacterSpeakingMode> GetCharacters(int bookId, int chapter, IVerse verseOrBridge,
                                                                      ScrVers versification = null, bool includeAlternatesAndRareQuotes = false, bool includeNarratorOverrides = false)
        {
            Debug.Assert(!includeAlternatesAndRareQuotes);
            Debug.Assert(!includeNarratorOverrides);
            Debug.Assert(versification == null || versification == m_versification);
            var result = new HashSet <CharacterSpeakingMode>(m_characterDeliveryEqualityComparer);

            foreach (var v in verseOrBridge.AllVerseNumbers)
            {
                var verseRef = new VerseRef(bookId, chapter, v, versification ?? m_versification);
                verseRef.ChangeVersification(ScrVers.English);
                result.AddRange(GetSpeakingModesForRef(verseRef));
            }
            return(result);
        }
        public void GetCharacters_NonEnglishVersification()
        {
            // Prove the test is valid
            var character = ControlCharacterVerseData.Singleton.GetCharacters(1, 32, 6).Single();

            Assert.AreEqual("messengers of Jacob", character.Character);
            var verseRef = new VerseRef(1, 32, 6, ScrVers.English);

            verseRef.ChangeVersification(m_testVersification);
            Assert.AreEqual(1, verseRef.BookNum);
            Assert.AreEqual(32, verseRef.ChapterNum);
            Assert.AreEqual(7, verseRef.VerseNum);

            // Run the test
            character = ControlCharacterVerseData.Singleton.GetCharacters(verseRef.BookNum, verseRef.ChapterNum, verseRef.VerseNum, versification: m_testVersification).Single();
            Assert.AreEqual("messengers of Jacob", character.Character);
        }
Пример #8
0
        public List <Term> TermsInRange(VerseRef firstReference, VerseRef lastReference)
        {
            VerseRef first = firstReference.Clone();
            VerseRef last  = lastReference.Clone();

            first.ChangeVersification(ScrVers.Original);
            last.ChangeVersification(ScrVers.Original);

            IEnumerable <Term> terms2;

            /*
             * if (first.Book == last.Book && first.Chapter == last.Chapter)
             *      terms2 = TermsInChapter(first);
             * else
             */
            terms2 = terms;

            int firstBCV = int.Parse(first.BBBCCCVVV());
            int lastBCV  = int.Parse(last.BBBCCCVVV());

            return(terms2.Where(term => term.HasReferencesInRange(firstBCV, lastBCV)).ToList());
        }
Пример #9
0
        private double PercentageOfExpectedQuotesFound(System.Collections.Generic.IReadOnlyList <BookScript> books)
        {
            var totalExpectedQuotesInIncludedChapters = 0;
            var totalVersesWithExpectedQuotes         = 0;

            var expectedQuotes = ControlCharacterVerseData.Singleton.ExpectedQuotes;

            foreach (var book in expectedQuotes.Keys)
            {
                var bookScript = books.FirstOrDefault(b => BCVRef.BookToNumber(b.BookId) == book);
                if (bookScript == null)
                {
                    continue;
                }
                foreach (var chapter in expectedQuotes[book])
                {
                    var chapterCounted = false;
                    foreach (var verseWithExpectedQuote in chapter.Value)
                    {
                        var referenceForExpectedQuote = new VerseRef(book, chapter.Key, verseWithExpectedQuote, ScrVers.English);
                        referenceForExpectedQuote.ChangeVersification(m_project.Versification);
                        var blocks =
                            bookScript.GetBlocksForVerse(referenceForExpectedQuote.ChapterNum, referenceForExpectedQuote.VerseNum).ToList();
                        if (!chapterCounted && blocks.Any())
                        {
                            totalExpectedQuotesInIncludedChapters += chapter.Value.Count;
                            chapterCounted = true;
                        }
                        if (blocks.Any(b => b.IsQuote))
                        {
                            totalVersesWithExpectedQuotes++;
                        }
                    }
                }
            }

            return(totalVersesWithExpectedQuotes * 100.0 / totalExpectedQuotesInIncludedChapters);
        }
Пример #10
0
        /// <summary>
        /// Gets a single character/delivery object that represents the one known character expected to be the
        /// exclusive (implicit) speaker over the entire reference range represented by the given parameters.
        /// If there are conflicting implicit characters or an implicit character covers only part of the range,
        /// the returned object will be a "Needs Review" character.
        /// </summary>
        public virtual ICharacterDeliveryInfo GetImplicitCharacter(int bookId, int chapter, int startVerse, int endVerse = 0, ScrVers versification = null)
        {
            if (versification == null)
            {
                versification = ScrVers.English;
            }

            var verseRef = new VerseRef(bookId, chapter, startVerse, versification);

            verseRef.ChangeVersification(ScrVers.English);
            var implicitCv = m_lookupByRef[verseRef.BBBCCCVVV].SingleOrDefault(cv => cv.IsImplicit);

            if (endVerse == 0 || startVerse == endVerse || implicitCv == null)
            {
                return(implicitCv);
            }

            var initialEndRef = new VerseRef(bookId, chapter, endVerse, versification);

            initialEndRef.ChangeVersification(ScrVers.English);
            do
            {
                var cvNextVerse = m_lookupByRef[verseRef.BBBCCCVVV].SingleOrDefault(cv => cv.IsImplicit);
                // Unless all verses in the range have the same implicit character, we cannot say that there is an
                // implicit character for this range. Note that there is the slight possibility that the delivery may vary
                // from one verse to the next, but it doesn't seem worth it to fail to find the implicit character just
                // because of that. Especially since the delivery info is only of minor usefulness.
                if (cvNextVerse?.Character != implicitCv.Character)
                {
                    return(NeedsReviewCharacter.Singleton);
                }
                verseRef.NextVerse();
                // ReSharper disable once LoopVariableIsNeverChangedInsideLoop - NextVerse changes verseRef
            } while (verseRef <= initialEndRef);
            return(implicitCv);
        }
        /// <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);
        }
Пример #12
0
        public IEnumerable <CharacterVerse> GetCharacters(int bookId, int chapter, int initialStartVerse, int initialEndVerse = 0, int finalVerse = 0, ScrVers versification = null)
        {
            if (versification == null)
            {
                versification = ScrVers.English;
            }

            IEnumerable <CharacterVerse> result;

            if (initialEndVerse == 0 || initialStartVerse == initialEndVerse)
            {
                var verseRef = new VerseRef(bookId, chapter, initialStartVerse, versification);
                verseRef.ChangeVersification(ScrVers.English);
                result = m_lookup[verseRef.BBBCCCVVV];
            }
            else
            {
                // REVIEW: Don't we need to call ChangeVersification here?
                int start = new BCVRef(bookId, chapter, initialStartVerse).BBCCCVVV;
                int end   = new BCVRef(bookId, chapter, initialEndVerse).BBCCCVVV;
                result = Enumerable.Empty <CharacterVerse>();
                for (int i = start; i <= end; i++)
                {
                    result = result.Union(m_lookup[i]);
                }
            }
            if (finalVerse == 0)             // Because of the possibility of interruptions, we can't quit early when we're down to 1 character/delivery // || result.Count() == 1)
            {
                return(result);
            }

            // This is a list (because that makes it easy to do a Union), but it should only ever have exactly one item in it.
            var interruption = result.Where(c => c.QuoteType == QuoteType.Interruption).ToList();

            var nextVerse = Math.Max(initialStartVerse, initialEndVerse) + 1;

            while (nextVerse <= finalVerse)
            {
                var verseRef = new VerseRef(bookId, chapter, nextVerse, versification);
                verseRef.ChangeVersification(ScrVers.English);
                IEnumerable <CharacterVerse> nextResult = m_lookup[verseRef.BBBCCCVVV];
                if (nextResult.Any())
                {
                    if (!interruption.Any())
                    {
                        interruption = nextResult.Where(c => c.QuoteType == QuoteType.Interruption).ToList();
                    }
                }
                else
                {
                    nextVerse++;
                    continue;
                }
                if (!result.Any())
                {
                    result = nextResult;
                    nextVerse++;
                    continue;
                }
                var intersection = nextResult.Intersect(result, m_characterDeliveryEqualityComparer);
                if (intersection.Count() == 1)
                {
                    result = intersection;
                    break;
                }
                nextVerse++;
            }
            return(result.Union(interruption));
        }
Пример #13
0
        /// <summary>
        /// Split blocks in the given book to match verse split locations
        /// </summary>
        /// <returns>A value indicating whether any splits were made</returns>
        private static bool MakesSplits(PortionScript blocksToSplit, int bookNum, ScrVers versification,
                                        List <VerseSplitLocation> verseSplitLocations, string descriptionOfProjectBeingSplit,
                                        string descriptionOfProjectUsedToDetermineSplitLocations, bool preventSplittingBlocksAlreadyMatchedToRefText = false)
        {
            if (!verseSplitLocations.Any())
            {
                return(false);
            }
            bool     splitsMade        = false;
            var      iSplit            = 0;
            VerseRef verseToSplitAfter = verseSplitLocations[iSplit];
            var      blocks            = blocksToSplit.GetScriptBlocks();

            for (int index = 0; index < blocks.Count; index++)
            {
                var block          = blocks[index];
                var initStartVerse = new VerseRef(bookNum, block.ChapterNumber, block.InitialStartVerseNumber,
                                                  versification);
                VerseRef initEndVerse;
                if (block.InitialEndVerseNumber != 0)
                {
                    initEndVerse = new VerseRef(bookNum, block.ChapterNumber, block.InitialEndVerseNumber,
                                                versification);
                }
                else
                {
                    initEndVerse = initStartVerse;
                }

                while (initEndVerse > verseToSplitAfter)
                {
                    if (iSplit == verseSplitLocations.Count - 1)
                    {
                        return(splitsMade);
                    }
                    verseToSplitAfter = verseSplitLocations[++iSplit];
                }

                var lastVerse = new VerseRef(bookNum, block.ChapterNumber, block.LastVerseNum, versification);
                if (lastVerse < verseToSplitAfter)
                {
                    continue;
                }

                if (initEndVerse.CompareTo(lastVerse) != 0 && lastVerse >= verseSplitLocations[iSplit].Before)
                {
                    bool invalidSplitLocation = false;
                    verseToSplitAfter.ChangeVersification(versification);
                    if (preventSplittingBlocksAlreadyMatchedToRefText && block.MatchesReferenceText)
                    {
                        invalidSplitLocation = blocksToSplit.GetVerseStringToUseForSplittingBlock(block, verseToSplitAfter.VerseNum) == null;
                    }
                    else if (blocksToSplit.TrySplitBlockAtEndOfVerse(block, verseToSplitAfter.VerseNum))
                    {
                        splitsMade = true;
                    }
                    else
                    {
                        invalidSplitLocation = true;
                    }

                    if (invalidSplitLocation)
                    {
#if DEBUG
                        if (!BlockContainsVerseEndInMiddleOfVerseBridge(block, verseToSplitAfter.VerseNum))
                        {
                            ErrorReport.NotifyUserOfProblem(
                                "Attempt to split {0} block to match breaks in the {1} text failed. Book: {2}; Chapter: {3}; Verse: {4}; Block: {5}",
                                descriptionOfProjectBeingSplit, descriptionOfProjectUsedToDetermineSplitLocations,
                                blocksToSplit.Id, block.ChapterNumber, verseToSplitAfter.VerseNum, block.GetText(true));
                        }
#endif
                        if (iSplit == verseSplitLocations.Count - 1)
                        {
                            break;
                        }
                        verseToSplitAfter = verseSplitLocations[++iSplit];
                        index--;
                    }
                }
            }
            return(splitsMade);
        }
Пример #14
0
        private void HandleAnalysisCompleted(object sender, EventArgs e)
        {
            int totalExpectedQuotesInIncludedChapters = 0;
            int totalVersesWithExpectedQuotes         = 0;

            var expectedQuotes = ControlCharacterVerseData.Singleton.ExpectedQuotes;

            foreach (var book in expectedQuotes.Keys)
            {
                var bookScript = m_project.Books.FirstOrDefault(b => BCVRef.BookToNumber(b.BookId) == book);
                if (bookScript == null)
                {
                    continue;
                }
                foreach (var chapter in expectedQuotes[book])
                {
                    bool chapterCounted = false;
                    foreach (var verseWithExpectedQuote in chapter.Value)
                    {
                        var referenceForExpectedQuote = new VerseRef(book, chapter.Key, verseWithExpectedQuote, ScrVers.English);
                        referenceForExpectedQuote.ChangeVersification(m_project.Versification);
                        var blocks = bookScript.GetBlocksForVerse(referenceForExpectedQuote.ChapterNum, referenceForExpectedQuote.VerseNum).ToList();
                        if (!chapterCounted && blocks.Any())
                        {
                            totalExpectedQuotesInIncludedChapters += chapter.Value.Count;
                            chapterCounted = true;
                        }
                        if (blocks.Any(b => b.IsQuote))
                        {
                            totalVersesWithExpectedQuotes++;
                        }
                    }
                }
            }

            double percentageOfExpectedQuotesFound = totalVersesWithExpectedQuotes * 100.0 / totalExpectedQuotesInIncludedChapters;

            if (percentageOfExpectedQuotesFound < Properties.Settings.Default.TargetPercentageOfQuotesFound)
            {
                using (var dlg = new PercentageOfExpectedQuotesFoundTooLowDlg(Text, percentageOfExpectedQuotesFound))
                {
                    dlg.ShowDialog();
                    if (dlg.UserWantsToReview)
                    {
                        if (!m_toolStripComboBoxFilter.Items.Contains(m_versesWithMissingExpectedQuotesFilterItem))
                        {
                            m_toolStripComboBoxFilter.Items.Insert(1, m_versesWithMissingExpectedQuotesFilterItem);
                        }
                        m_toolStripComboBoxFilter.SelectedItem = m_versesWithMissingExpectedQuotesFilterItem;
                        return;
                    }
                }
            }
            else if (m_project.ProjectAnalysis.PercentUnknown > Properties.Settings.Default.MaxAcceptablePercentageOfUnknownQuotes)
            {
                using (var dlg = new TooManyUnexpectedQuotesFoundDlg(Text, m_project.ProjectAnalysis.PercentUnknown))
                {
                    dlg.ShowDialog();
                    if (dlg.UserWantsToReview)
                    {
                        if (!m_toolStripComboBoxFilter.Items.Contains(m_allQuotesFilterItem))
                        {
                            m_toolStripComboBoxFilter.Items.Insert(m_toolStripComboBoxFilter.Items.Count - 1, m_allQuotesFilterItem);
                        }
                        m_toolStripComboBoxFilter.SelectedItem = m_allQuotesFilterItem;
                        return;
                    }
                }
            }

            DialogResult = DialogResult.OK;
            Close();
        }