示例#1
0
 private static void FindAllScriptureBlocksThroughVerse(IReadOnlyList <Block> blockList, VerseRef endVerse, ref int i, ScrVers versification)
 {
     for (; ;)
     {
         var nextScriptureBlock = blockList.Skip(i + 1).FirstOrDefault(b => !CharacterVerseData.IsCharacterExtraBiblical(b.CharacterId));
         if (nextScriptureBlock == null)
         {
             break;
         }
         var nextVerseRef = new VerseRef(endVerse.BookNum, nextScriptureBlock.ChapterNumber, nextScriptureBlock.InitialStartVerseNumber, versification);
         if (nextVerseRef > endVerse)
         {
             break;
         }
         i++;
     }
 }
        public void Constructor_CharactersRemovedFromProjectLeavingGroupsThatWouldHaveNoCharacters_CharacterGroupsToRemoveNotEmpty()
        {
            // By jacking up the number of actors really high, we guarantee that most characters will end up in a group by themselves,
            // thus more-or-less ensuring that some groups will no longer contain any characters in use after excluding Mark from the
            // project.
            m_testProject.VoiceActorList.Actors = CharacterGroupGeneratorTests.GetVoiceActors(99, 22, 7);
            GenerateGroups();
            m_testProject.AvailableBooks.Single(b => b.Code == "MRK").IncludeInScript = false;
            var adjuster = new CharacterGroupsAdjuster(m_testProject);

            Assert.AreEqual(0, adjuster.CharactersNotCoveredByAnyGroup.Count());
            Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains(CharacterVerseData.GetStandardCharacterId("MRK", CharacterVerseData.StandardCharacter.Narrator)));
            Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains(CharacterVerseData.GetStandardCharacterId("MRK", CharacterVerseData.StandardCharacter.ExtraBiblical)));
            Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains(CharacterVerseData.GetStandardCharacterId("MRK", CharacterVerseData.StandardCharacter.BookOrChapter)));
            Assert.IsTrue(adjuster.CharacterGroupsToRemove.Any());
            Assert.IsTrue(adjuster.GroupsAreNotInSynchWithData);
        }
示例#3
0
        public void Constructor_BooksWithDifferentAuthors_NoStatsCombined()
        {
            var keyStrokesByBook = new Dictionary <string, int>();

            keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JER", CharacterVerseData.StandardCharacter.Narrator)] = 52000;
            keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EZK", CharacterVerseData.StandardCharacter.Narrator)] = 48000;
            keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("HOS", CharacterVerseData.StandardCharacter.Narrator)] = 12000;
            keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.Narrator)] = 1000;
            var includedBooks = new List <string> {
                "JER", "EZK", "HOS", "JUD"
            };

            Assert.AreEqual(52000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("JER"), includedBooks, keyStrokesByBook).KeyStrokeCount);
            Assert.AreEqual(48000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("EZK"), includedBooks, keyStrokesByBook).KeyStrokeCount);
            Assert.AreEqual(12000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("HOS"), includedBooks, keyStrokesByBook).KeyStrokeCount);
            Assert.AreEqual(1000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("JUD"), includedBooks, keyStrokesByBook).KeyStrokeCount);
        }
示例#4
0
        public BlockMatchup(BookScript vernacularBook, int iBlock, Action <PortionScript> splitBlocks,
                            Func <VerseRef, bool> isOkayToBreakAtVerse, IReferenceLanguageInfo heSaidProvider)
        {
            m_vernacularBook = vernacularBook;
            int bookNum = BCVRef.BookToNumber(m_vernacularBook.BookId);

            m_referenceLanguageInfo = heSaidProvider;
            var blocks = m_vernacularBook.GetScriptBlocks();
            var originalAnchorBlock           = blocks[iBlock];
            var blocksForVersesCoveredByBlock =
                vernacularBook.GetBlocksForVerse(originalAnchorBlock.ChapterNumber, originalAnchorBlock.InitialStartVerseNumber).ToList();

            m_iStartBlock = iBlock - blocksForVersesCoveredByBlock.IndexOf(originalAnchorBlock);
            while (!blocksForVersesCoveredByBlock.First().StartsAtVerseStart&& blocksForVersesCoveredByBlock.First().InitialStartVerseNumber < originalAnchorBlock.InitialStartVerseNumber)
            {
                var prepend = vernacularBook.GetBlocksForVerse(originalAnchorBlock.ChapterNumber, blocksForVersesCoveredByBlock.First().InitialStartVerseNumber).ToList();
                prepend.RemoveAt(prepend.Count - 1);
                m_iStartBlock -= prepend.Count;
                blocksForVersesCoveredByBlock.InsertRange(0, prepend);
            }
            int iLastBlock = m_iStartBlock + blocksForVersesCoveredByBlock.Count - 1;
            int i          = iLastBlock;

            AdvanceToCleanVerseBreak(blocks, verseNum =>
            {
                return(isOkayToBreakAtVerse(new VerseRef(bookNum, originalAnchorBlock.ChapterNumber, verseNum)));
            }, ref i);
            if (i > iLastBlock)
            {
                blocksForVersesCoveredByBlock.AddRange(blocks.Skip(iLastBlock + 1).Take(i - iLastBlock));
            }
            while (CharacterVerseData.IsCharacterOfType(blocksForVersesCoveredByBlock.Last().CharacterId, CharacterVerseData.StandardCharacter.ExtraBiblical))
            {
                blocksForVersesCoveredByBlock.RemoveAt(blocksForVersesCoveredByBlock.Count - 1);
            }

            m_portion             = new PortionScript(vernacularBook.BookId, blocksForVersesCoveredByBlock.Select(b => b.Clone()));
            CorrelatedAnchorBlock = m_portion.GetScriptBlocks()[iBlock - m_iStartBlock];
            if (splitBlocks != null)
            {
                int origCount = m_portion.GetScriptBlocks().Count;
                splitBlocks(m_portion);
                m_numberOfBlocksAddedBySplitting = m_portion.GetScriptBlocks().Count - origCount;
            }
        }
示例#5
0
        public string CharacterSelect(int splitId, IEnumerable <AssignCharacterViewModel.Character> characters = null)
        {
            if ((characters == null) && !string.IsNullOrEmpty(s_characterSelect))
            {
                return(string.Format(s_characterSelect, splitId));
            }

            const string optionTemplate = "<option value=\"{0}\">{1}</option>";
            var          sb             = new StringBuilder("<select class=\"select-character\" data-splitid=\"{0}\"><option value=\"\"></option>");

            if (characters != null)
            {
                foreach (var character in characters)
                {
                    if (CharacterVerseData.IsCharacterStandard(character.CharacterId))
                    {
                    }
                    if (character.IsNarrator)
                    {
                        sb.AppendFormat(optionTemplate,
                                        CharacterVerseData.GetStandardCharacterId(BookCode, CharacterVerseData.StandardCharacter.Narrator),
                                        character.LocalizedDisplay);
                    }
                    else
                    {
                        var stdCharacterType = CharacterVerseData.GetStandardCharacterType(character.CharacterId);
                        if (stdCharacterType == CharacterVerseData.StandardCharacter.NonStandard)
                        {
                            sb.AppendFormat(optionTemplate, character.CharacterId, character.LocalizedDisplay);
                        }
                        else
                        {
                            sb.AppendFormat(optionTemplate,
                                            CharacterVerseData.GetStandardCharacterId(BookCode, stdCharacterType),
                                            character.LocalizedDisplay);
                        }
                    }
                }
            }

            sb.Append("</select>");
            s_characterSelect = sb.ToString();

            return(string.Format(s_characterSelect, splitId));
        }
示例#6
0
        public virtual Color GetForeColorByCharacterId(string characterId)
        {
            if (string.IsNullOrWhiteSpace(characterId))
            {
                return(SpeechNonCharacter);
            }

            if (characterId == "Jesus")
            {
                return(SpeechJesus);
            }

            if (!CharacterVerseData.IsCharacterStandard(characterId))
            {
                return(SpeechCharacter);
            }

            return(SpeechNonCharacter);
        }
        public void Constructor_CharactersRemovedFromProjectButNotEnoughToResultInAnEmptyGroup_AdditionsButNoDeletions()
        {
            // By keeping the number of actors really low, we guarantee that groups will have lots of characters,
            // thus more-or-less ensuring that no groups will consist only of characters no longer in use after excluding Mark from the
            // project.
            m_testProject.VoiceActorList.Actors = CharacterGroupGeneratorTests.GetVoiceActors(7, 1, 1);
            GenerateGroups();
            m_testProject.AvailableBooks.Single(b => b.Code == "MRK").IncludeInScript = false;
            var adjuster = new CharacterGroupsAdjuster(m_testProject);

            Assert.AreEqual(0, adjuster.CharactersNotCoveredByAnyGroup.Count());
            Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains(CharacterVerseData.GetStandardCharacterId("MRK", CharacterVerseData.StandardCharacter.Narrator)));
            Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains(CharacterVerseData.GetStandardCharacterId("MRK", CharacterVerseData.StandardCharacter.ExtraBiblical)));
            Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains(CharacterVerseData.GetStandardCharacterId("MRK", CharacterVerseData.StandardCharacter.BookOrChapter)));
            Assert.AreEqual(0, adjuster.CharacterGroupsToRemove.Count());
            Assert.IsFalse(adjuster.NewBooksHaveBeenIncluded);
            Assert.IsTrue(adjuster.BooksHaveBeenExcluded);
            Assert.IsTrue(adjuster.FullRegenerateRecommended);
            Assert.IsTrue(adjuster.GroupsAreNotInSynchWithData);
        }
        public void Constructor_CharactersAddedToProject_AdditionsButNoDeletions()
        {
            m_testProject.VoiceActorList.Actors = CharacterGroupGeneratorTests.GetVoiceActors(9, 2, 1);
            GenerateGroups();
            m_testProject.AvailableBooks.Single(b => b.Code == "ACT").IncludeInScript = true;
            var adjuster = new CharacterGroupsAdjuster(m_testProject);

            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.Narrator)));
            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.ExtraBiblical)));
            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.BookOrChapter)));
            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains("Gamaliel"));
            Assert.IsFalse(adjuster.CharactersNotCoveredByAnyGroup.Contains("Jesus"));
            Assert.IsFalse(adjuster.CharactersNotCoveredByAnyGroup.Contains("Peter (Simon)"));
            Assert.AreEqual(0, adjuster.CharactersNoLongerInUse.Count());
            Assert.AreEqual(0, adjuster.CharacterGroupsToRemove.Count());
            Assert.IsTrue(adjuster.NewBooksHaveBeenIncluded);
            Assert.IsFalse(adjuster.BooksHaveBeenExcluded);
            Assert.IsTrue(adjuster.FullRegenerateRecommended);
            Assert.IsTrue(adjuster.GroupsAreNotInSynchWithData);
        }
        public void Constructor_CharactersAddedToProject_AdditionsButNoDeletions()
        {
            SetVoiceActors(9, 2, 1);
            GenerateGroups();
            m_testProject.AvailableBooks.Single(b => b.Code == "ACT").IncludeInScript = true;
            m_testProject.ClearCharacterStatistics();             // This simulates behavior in UI when the project is saved after displaying ScriptureRangeSelectionDlg
            var adjuster = new CharacterGroupsAdjuster(m_testProject);

            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.Narrator)));
            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.ExtraBiblical)));
            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.BookOrChapter)));
            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains("Gamaliel"));
            Assert.IsFalse(adjuster.CharactersNotCoveredByAnyGroup.Contains("Jesus"));
            Assert.IsFalse(adjuster.CharactersNotCoveredByAnyGroup.Contains("Peter (Simon)"));
            Assert.AreEqual(0, adjuster.CharactersNoLongerInUse.Count());
            Assert.AreEqual(0, adjuster.CharacterGroupsToRemove.Count());
            Assert.IsTrue(adjuster.NewBooksHaveBeenIncluded);
            Assert.IsFalse(adjuster.BooksHaveBeenExcluded);
            Assert.IsTrue(adjuster.FullRegenerateRecommended);
            Assert.IsTrue(adjuster.GroupsAreNotInSynchWithData);
        }
示例#10
0
        public void DataIntegrity_AllNonNarratorCharacterDetailsHaveCharacterIdOrDefaultCharacter()
        {
            var characterIds = new List <string>(ControlCharacterVerseData.Singleton.GetAllQuoteInfo().Select(d => d.Character)
                                                 .SelectMany(characters => characters.Split('/')));

            var           defaultCharacters = ControlCharacterVerseData.Singleton.GetAllQuoteInfo().Select(d => d.DefaultCharacter).ToList();
            ISet <string> missingCharacters = new SortedSet <string>();

            foreach (string character in CharacterDetailData.Singleton.GetAll().Select(d => d.CharacterId))
            {
                if (!CharacterVerseData.IsCharacterStandard(character) &&
                    (!(characterIds.Contains(character) || defaultCharacters.Contains(character))))
                {
                    missingCharacters.Add(character);
                }
            }
            Assert.False(missingCharacters.Any(),
                         "Characters in Character-Detail data but not in Character-Verse data:" +
                         Environment.NewLine +
                         missingCharacters.OnePerLineWithIndent());
        }
示例#11
0
        /// <summary>Gets extra-biblical characters that are voiced by the same actor who is not the narrator</summary>
        /// <param name="book"></param>
        /// <param name="dramatizationPreferences"></param>
        /// <param name="bookData"></param>
        private static void GetOtherCharactersToTreatAsOne(BookScript book, ProjectDramatizationPreferences dramatizationPreferences,
                                                           Dictionary <CharacterVerseData.StandardCharacter, HashSet <string> > bookData)
        {
            var bookTitleChapterId = CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.BookOrChapter);
            var sectionHeadId      = CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.ExtraBiblical);
            var bookIntroductionId = CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.Intro);

            if ((dramatizationPreferences.BookTitleAndChapterDramatization & ExtraBiblicalMaterialSpeakerOption.NotNarratorOrOmitted) != 0)
            {
                if (dramatizationPreferences.BookTitleAndChapterDramatization == dramatizationPreferences.SectionHeadDramatization)
                {
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.BookOrChapter, bookTitleChapterId);
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.BookOrChapter, sectionHeadId);

                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.ExtraBiblical, bookTitleChapterId);
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.ExtraBiblical, sectionHeadId);
                }

                if (dramatizationPreferences.BookTitleAndChapterDramatization == dramatizationPreferences.BookIntroductionsDramatization)
                {
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.BookOrChapter, bookTitleChapterId);
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.BookOrChapter, bookIntroductionId);

                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.Intro, bookTitleChapterId);
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.Intro, bookIntroductionId);
                }
            }

            if ((dramatizationPreferences.SectionHeadDramatization & ExtraBiblicalMaterialSpeakerOption.NotNarratorOrOmitted) != 0)
            {
                if (dramatizationPreferences.SectionHeadDramatization == dramatizationPreferences.BookIntroductionsDramatization)
                {
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.ExtraBiblical, sectionHeadId);
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.ExtraBiblical, bookIntroductionId);

                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.Intro, sectionHeadId);
                    AddOrNew(bookData, CharacterVerseData.StandardCharacter.Intro, bookIntroductionId);
                }
            }
        }
        public void MakeMinimalAdjustments_FewDeletionsAndFewGroups_CharactersRemovedFromExistingCharacterGroups()
        {
            m_testProject.AvailableBooks.Single(b => b.Code == "JUD").IncludeInScript = true;
            m_testProject.VoiceActorList.Actors = CharacterGroupGeneratorTests.GetVoiceActors(20, 2, 1);
            GenerateGroups();
            m_testProject.AvailableBooks.Single(b => b.Code == "JUD").IncludeInScript = false;
            var adjuster           = new CharacterGroupsAdjuster(m_testProject);
            var charactersNotInUse = adjuster.CharactersNoLongerInUse.ToList();

            Assert.IsTrue(charactersNotInUse.Count > 0);
            Assert.IsTrue(charactersNotInUse.Contains(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.Narrator)));
            Assert.IsTrue(charactersNotInUse.Contains(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.ExtraBiblical)));
            Assert.IsTrue(charactersNotInUse.Contains(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.BookOrChapter)));
            var originalCountOfGroups = m_testProject.CharacterGroupList.CharacterGroups.Count;

            adjuster.MakeMinimalAdjustments();
            Assert.IsFalse(adjuster.GroupsAreNotInSynchWithData);
            Assert.AreEqual(0, adjuster.CharactersNoLongerInUse.Count());
            Assert.AreEqual(0, adjuster.CharactersNotCoveredByAnyGroup.Count());
            Assert.AreEqual(originalCountOfGroups, m_testProject.CharacterGroupList.CharacterGroups.Count);
            Assert.IsFalse(m_testProject.CharacterGroupList.CharacterGroups.Any(g => g.CharacterIds.Any(c => charactersNotInUse.Contains(c))));
        }
        public void Constructor_FiveCharactersAddedRemovedOrRenamed_FullRegenerateRecommended()
        {
            SetVoiceActors(9, 2, 1);
            m_testProject.AvailableBooks.Single(b => b.Code == "LUK").IncludeInScript = false;
            m_testProject.ClearCharacterStatistics();             // This simulates behavior in UI when the project is saved after displaying ScriptureRangeSelectionDlg
            GenerateGroups();

            try
            {
                RenameCharacter(41, 1, 27, "men in Capernaum synagogue", "dudes in the Capernaum teaching center");
                RenameCharacter(41, 2, 12, "everyone who saw healing of paralytic", "witnesses of paralytic's healing");
                SetBlockCharacterToNarrator("MRK", 9, 26, "many in crowd");
                SetBlockCharacterToNarrator("MRK", 5, 35, "men from Jairus' house");
                RenameCharacter(41, 7, 1,
                                CharacterVerseData.GetStandardCharacterId("MRK", CharacterVerseData.StandardCharacter.Narrator),
                                "Mephibosheth");

                var adjuster = new CharacterGroupsAdjuster(m_testProject);
                Assert.AreEqual(3, adjuster.CharactersNotCoveredByAnyGroup.Count());
                Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains("dudes in the Capernaum teaching center"));
                Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains("witnesses of paralytic's healing"));
                Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains("Mephibosheth"));
                Assert.AreEqual(4, adjuster.CharactersNoLongerInUse.Count());
                Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains("men in Capernaum synagogue"));
                Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains("everyone who saw healing of paralytic"));
                Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains("many in crowd"));
                Assert.IsTrue(adjuster.CharactersNoLongerInUse.Contains("men from Jairus' house"));
                Assert.AreEqual(0, adjuster.CharacterGroupsToRemove.Count());
                Assert.IsFalse(adjuster.NewBooksHaveBeenIncluded);
                Assert.IsFalse(adjuster.BooksHaveBeenExcluded);
                Assert.IsTrue(adjuster.FullRegenerateRecommended);
                Assert.IsTrue(adjuster.GroupsAreNotInSynchWithData);
            }
            finally
            {
                CreateTestProject();
            }
        }
        public void DistributeBooksAmongNarratorGroups_FourAuthorsOfFourBooksAmongThreeNarrators_TwoAuthorsWithShortestBooksCombined()
        {
            var keyStrokesByBook = new Dictionary <string, int>();

            keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JER", CharacterVerseData.StandardCharacter.Narrator)] = 52000;
            keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EZK", CharacterVerseData.StandardCharacter.Narrator)] = 48000;
            keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("HOS", CharacterVerseData.StandardCharacter.Narrator)] = 12000;
            keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.Narrator)] = 1000;
            var authorStats = new List <AuthorStats>();
            var jeremiah    = new BiblicalAuthors.Author {
                Name = "Jeremiah"
            };
            var ezekiel = new BiblicalAuthors.Author {
                Name = "Ezekiel"
            };
            var hosea = new BiblicalAuthors.Author {
                Name = "Hosea"
            };
            var jude = new BiblicalAuthors.Author {
                Name = "Jude"
            };

            authorStats.Add(new AuthorStats(jeremiah, keyStrokesByBook, "JER"));
            authorStats.Add(new AuthorStats(ezekiel, keyStrokesByBook, "EZK"));
            authorStats.Add(new AuthorStats(hosea, keyStrokesByBook, "HOS"));
            authorStats.Add(new AuthorStats(jude, keyStrokesByBook, "JUD"));

            var narratorGroups = GetNarratorCharacterGroups(3);

            CharacterGroupGenerator.TrialGroupConfiguration.DistributeBooksAmongNarratorGroups(authorStats, narratorGroups);
            var groupForJeremiah = GetNarratorGroupForBook(narratorGroups, "JER");
            var groupForJude     = GetNarratorGroupForBook(narratorGroups, "JUD");

            Assert.AreNotEqual(groupForJeremiah, GetNarratorGroupForBook(narratorGroups, "EZK"));
            Assert.AreNotEqual(groupForJeremiah, groupForJude);
            Assert.AreEqual(groupForJude, GetNarratorGroupForBook(narratorGroups, "HOS"));
        }
        private void SetCharacterAndDelivery(Block block, Character selectedCharacter, Delivery selectedDelivery)
        {
            if (CharacterVerseData.IsCharacterUnclear(selectedCharacter.CharacterId))
            {
                throw new ArgumentException("Character cannot be confirmed as ambiguous or unknown.", nameof(selectedCharacter));
            }
            // If the user sets a non-narrator to a block we marked as narrator, we want to track it
            if (!selectedCharacter.IsNarrator && !block.IsQuote)
            {
                Analytics.Track("NarratorToQuote", new Dictionary <string, string>
                {
                    { "book", CurrentBookId },
                    { "chapter", block.ChapterNumber.ToString(CultureInfo.InvariantCulture) },
                    { "initialStartVerse", block.InitialStartVerseNumber.ToString(CultureInfo.InvariantCulture) },
                    { "lastVerse", block.LastVerseNum.ToString(CultureInfo.InvariantCulture) },
                    { "character", selectedCharacter.CharacterId }
                });
            }

            SetCharacter(block, selectedCharacter);
            block.Delivery = selectedDelivery.IsNormal ? null : selectedDelivery.Text;

            AddRecordsToProjectControlFilesIfNeeded(block);
        }
        public bool IsModified(Character newCharacter, Delivery newDelivery)
        {
            Block currentBlock = CurrentBlockInOriginal;

            if (CharacterVerseData.IsCharacterExtraBiblical(currentBlock.CharacterId))
            {
                return(false);                // Can't change these.
            }
            if (newCharacter == null)
            {
                return(!(currentBlock.CharacterIsUnclear || currentBlock.CharacterId == null));
            }
            if (newCharacter.IsNarrator)
            {
                if (!currentBlock.CharacterIs(CurrentBookId, CharacterVerseData.StandardCharacter.Narrator))
                {
                    return(true);
                }
            }
            else if (newCharacter.CharacterId != currentBlock.CharacterId)
            {
                return(true);
            }

            if (newDelivery == null)
            {
                return(true);
            }

            if (newDelivery.IsNormal)
            {
                return(!string.IsNullOrEmpty(currentBlock.Delivery));
            }

            return(newDelivery.Text != currentBlock.Delivery);
        }
        private void AddRecordToProjectCharacterVerseData(Block block, Character character, Delivery delivery)
        {
            CharacterDetail detail;

            if (m_pendingCharacterDetails.TryGetValue(character.CharacterId, out detail))
            {
                m_project.AddProjectCharacterDetail(detail);
                m_project.SaveProjectCharacterDetailData();
                m_pendingCharacterDetails.Remove(detail.CharacterId);
            }

            var cv = new CharacterVerse(
                new BCVRef(GetBlockVerseRef(block, ScrVers.English).BBBCCCVVV),
                character.IsNarrator
                                                ? CharacterVerseData.GetStandardCharacterId(CurrentBookId, CharacterVerseData.StandardCharacter.Narrator)
                                                : character.CharacterId,
                delivery.IsNormal ? null : delivery.Text,
                character.Alias,
                character.ProjectSpecific || delivery.ProjectSpecific);

            m_projectCharacterVerseData.Add(cv);

            m_project.SaveProjectCharacterVerseData();
        }
示例#18
0
        public static void SimulateDisambiguationForAllBooks(Project testProject)
        {
            var cvData = new CombinedCharacterVerseData(testProject);

            foreach (var book in testProject.IncludedBooks)
            {
                var bookNum = BCVRef.BookToNumber(book.BookId);
                foreach (var block in book.GetScriptBlocks())
                {
                    if (block.CharacterId == CharacterVerseData.kUnknownCharacter)
                    {
                        block.SetCharacterAndCharacterIdInScript(CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.Narrator), bookNum, testProject.Versification);
                    }
                    else if (block.CharacterId == CharacterVerseData.kAmbiguousCharacter)
                    {
                        var cvEntry =
                            cvData.GetCharacters(bookNum, block.ChapterNumber, block.InitialStartVerseNumber, block.InitialEndVerseNumber,
                                                 versification: testProject.Versification).First();
                        block.SetCharacterAndCharacterIdInScript(cvEntry.Character, bookNum, testProject.Versification);
                        block.Delivery = cvEntry.Delivery;
                    }
                }
            }
        }
            private void AddToBestNarratorGroup(string characterId)
            {
                // Need tests (and code here) to handle the following scenarios:
                // 0) number of narrators > number of books -> This should never happen!
                // 1) DONE: number of narrators == number of books -> Add narrator to first empty narrator group
                // 2) TODO: number of narrators > number of authors -> break up most prolific authors into multiple narrator groups
                // 3) DONE: number of narrators == number of authors -> add narrator to group with other books by same other, if any; otherwise first empty group
                // 4) TODO: number of narrators < number of authors -> shorter books share narrators
                // 5) DONE: single narrator -> EASY: only one group!
                CharacterGroup bestNarratorGroup = null;

                if (m_narratorGroupsByAuthor != null)
                {
                    var author = BiblicalAuthors.GetAuthorOfBook(CharacterVerseData.GetBookCodeFromStandardCharacterId(characterId));
                    bestNarratorGroup = m_narratorGroupsByAuthor[author];
                }

                if (bestNarratorGroup == null)
                {
                    bestNarratorGroup = NarratorGroups.FirstOrDefault(g => !g.CharacterIds.Any());
                    bestNarratorGroup = bestNarratorGroup ?? NarratorGroups.First();
                }
                bestNarratorGroup.CharacterIds.Add(characterId);
            }
示例#20
0
        // internal for testing
        internal List <List <object> > GetExportData(string bookId = null, int voiceActorId = -1)
        {
            var result = new List <List <object> >();

            int blockNumber = 1;

            IEnumerable <BookScript> booksToInclude = bookId == null
                                ? m_booksToExport
                                : m_booksToExport.Where(b => b.BookId == bookId);

            foreach (var book in booksToInclude)
            {
                string singleVoiceNarratorOverride = null;
                if (book.SingleVoice)
                {
                    singleVoiceNarratorOverride = CharacterVerseData.GetStandardCharacterId(book.BookId,
                                                                                            CharacterVerseData.StandardCharacter.Narrator);
                }
                List <Block> pendingMismatchedReferenceBlocks = null;
                foreach (var block in book.GetScriptBlocks())
                {
                    if (block.IsChapterAnnouncement && block.ChapterNumber == 1)
                    {
                        if (Project.SkipChapterAnnouncementForFirstChapter)
                        {
                            continue;
                        }
                        if (Project.SkipChapterAnnouncementForSingleChapterBooks &&
                            Project.Versification.LastChapter(BCVRef.BookToNumber(book.BookId)) == 1)
                        {
                            continue;
                        }
                    }
                    VoiceActor.VoiceActor voiceActor = null;
                    bool includeInOutput             = true;
                    if (IncludeVoiceActors)
                    {
                        voiceActor      = Project.GetVoiceActorForCharacter(singleVoiceNarratorOverride ?? block.CharacterIdInScript) ?? GetDummyActor();
                        includeInOutput = voiceActorId == -1 || voiceActor.Id == voiceActorId;
                    }

                    if (includeInOutput)
                    {
                        if (pendingMismatchedReferenceBlocks != null && block.ReferenceBlocks.Any())
                        {
                            foreach (var refBlock in pendingMismatchedReferenceBlocks)
                            {
                                result.Add(GetExportDataForReferenceBlock(refBlock, book.BookId));
                            }
                            pendingMismatchedReferenceBlocks = null;
                        }
                        result.Add(GetExportDataForBlock(block, blockNumber++, book.BookId, voiceActor, singleVoiceNarratorOverride, IncludeVoiceActors,
                                                         Project.ReferenceText.HasSecondaryReferenceText));
                        if (!block.MatchesReferenceText && block.ReferenceBlocks.Any())
                        {
                            pendingMismatchedReferenceBlocks = block.ReferenceBlocks;
                        }
                    }
                }
                if (pendingMismatchedReferenceBlocks != null)
                {
                    foreach (var refBlock in pendingMismatchedReferenceBlocks)
                    {
                        result.Add(GetExportDataForReferenceBlock(refBlock, book.BookId));
                    }
                }
            }
            if (bookId == null && voiceActorId == -1)
            {
                AddAnnotations(result);
            }
            return(result);
        }
示例#21
0
        public bool MoveCharactersToGroup(IList <string> characterIds, CharacterGroup destGroup, bool warnUserAboutProximity = false)
        {
            CharacterGroup sourceGroup = GetSourceGroupForMove(characterIds, destGroup);

            if (sourceGroup == null)
            {
                return(false);
            }

            if (destGroup != null && warnUserAboutProximity && destGroup.CharacterIds.Count > 0)
            {
                var proximity = new Proximity(m_project);

                var testGroup       = new CharacterIdHashSet(destGroup.CharacterIds);
                var resultsBefore   = proximity.CalculateMinimumProximity(testGroup);
                int proximityBefore = resultsBefore.NumberOfBlocks;

                testGroup.AddRange(characterIds);
                var resultsAfter   = proximity.CalculateMinimumProximity(testGroup);
                int proximityAfter = resultsAfter.NumberOfBlocks;

                if (proximityBefore > proximityAfter && proximityAfter <= Proximity.kDefaultMinimumProximity)
                {
                    var firstReference = new BCVRef(BCVRef.BookToNumber(resultsAfter.FirstBook.BookId), resultsAfter.FirstBlock.ChapterNumber,
                                                    resultsAfter.FirstBlock.InitialStartVerseNumber).ToString();

                    var secondReference = new BCVRef(BCVRef.BookToNumber(resultsAfter.SecondBook.BookId), resultsAfter.SecondBlock.ChapterNumber,
                                                     resultsAfter.SecondBlock.InitialStartVerseNumber).ToString();

                    var dlgMessageFormat1 = (firstReference == secondReference) ?
                                            LocalizationManager.GetString("DialogBoxes.VoiceActorAssignmentDlg.MoveCharacterDialog.Message.Part1",
                                                                          "This move will result in a group with a minimum proximity of {0} blocks between [{1}] and [{2}] in {3}.") :
                                            LocalizationManager.GetString("DialogBoxes.VoiceActorAssignmentDlg.MoveCharacterDialog.Message.Part1",
                                                                          "This move will result in a group with a minimum proximity of {0} blocks between [{1}] in {3} and [{2}] in {4}.");
                    dlgMessageFormat1 = string.Format(dlgMessageFormat1,
                                                      resultsAfter.NumberOfBlocks,
                                                      CharacterVerseData.GetCharacterNameForUi(resultsAfter.FirstBlock.CharacterIdInScript),
                                                      CharacterVerseData.GetCharacterNameForUi(resultsAfter.SecondBlock.CharacterIdInScript),
                                                      firstReference, secondReference);
                    var dlgMessageFormat2 =
                        LocalizationManager.GetString("DialogBoxes.VoiceActorAssignmentDlg.MoveCharacterDialog.Message.Part2",
                                                      "Do you want to continue with this move?");

                    var dlgMessage = string.Format(dlgMessageFormat1 + Environment.NewLine + Environment.NewLine + dlgMessageFormat2);
                    var dlgTitle   = LocalizationManager.GetString("DialogBoxes.VoiceActorAssignmentDlg.MoveCharacterDialog.Title",
                                                                   "Confirm");

                    if (MessageBox.Show(dlgMessage, dlgTitle, MessageBoxButtons.YesNo) != DialogResult.Yes)
                    {
                        return(false);
                    }
                }
            }

            m_undoStack.Push(new MoveCharactersToGroupUndoAction(m_project, sourceGroup, destGroup, characterIds));

            m_project.CharacterGroupList.PopulateEstimatedHours(m_keyStrokesByCharacterId);
            Save();

            return(true);
        }
示例#22
0
        /// <summary>Calculate the minimum number of blocks between two character ids in given collection</summary>
        public MinimumProximity CalculateMinimumProximity(ISet <string> characterIdsToCalculate)
        {
            if (!characterIdsToCalculate.Any())
            {
                return(new MinimumProximity(Int32.MaxValue, null, null, null, null));
            }

            RelatedCharactersData relChar          = RelatedCharactersData.Singleton;
            bool          foundFirst               = false;
            int           currentBlockCount        = 0;
            int           minBlockProximity        = Int32.MaxValue;
            string        prevCharacterId          = null;
            ISet <string> prevMatchingCharacterIds = null;
            BookScript    firstBook           = null;
            Block         firstBlock          = null;
            BookScript    secondBook          = null;
            Block         secondBlock         = null;
            BookScript    prevBook            = null;
            Block         prevBlock           = null;
            bool          breakOutOfBothLoops = false;

            bool calculateAnyRelatedCharacters = characterIdsToCalculate.Any(c => relChar.HasMatchingCharacterIdsOfADifferentAge(c));

            foreach (var book in m_booksToConsider)
            {
                if (breakOutOfBothLoops)
                {
                    break;
                }

                var countVersesRatherThanBlocks = !m_referenceText.HasContentForBook(book.BookId);

                var treatAsSameCharacter = m_considerSameExtrabiblicalCharacter[book];
                if (m_narrationByAuthor)
                {
                    var author = BiblicalAuthors.GetAuthorOfBook(book.BookId);
                    if (author.CombineAuthorAndNarrator && !treatAsSameCharacter.Any(set => set.Contains(author.Name)))
                    {
                        if (!m_strictlyAdhereToNarratorPreferences || (characterIdsToCalculate.Contains(book.NarratorCharacterId) && characterIdsToCalculate.Contains(author.Name)))
                        {
                            HashSet <string> charactersToTreatAsOneWithNarrator = treatAsSameCharacter.FirstOrDefault(set => set.Contains(book.NarratorCharacterId));
                            if (charactersToTreatAsOneWithNarrator == null)
                            {
                                charactersToTreatAsOneWithNarrator = new HashSet <string>();
                                treatAsSameCharacter.Add(charactersToTreatAsOneWithNarrator);
                                charactersToTreatAsOneWithNarrator.Add(book.NarratorCharacterId);
                                charactersToTreatAsOneWithNarrator.Add(author.Name);
                            }
                            else
                            {
                                charactersToTreatAsOneWithNarrator.Add(author.Name);
                            }
                        }
                    }
                }

                // We don't want to treat book ends as being directly adjacent but not infinitely distant, either.
                currentBlockCount += kDefaultMinimumBlocks * 5 / 3;                 // The amount of padding is somewhat arbitrary.

                foreach (var block in book.Blocks)
                {
                    var characterId = block.CharacterIdInScript;

                    // The original logic here was NOT split out for the single character vs. multiple character scenarios.
                    // This made the code much more readable, but the performance was atrocious since we were creating
                    // extra hashsets and doing extra intersects. Please consider the performance implications of any
                    // changes to this code.  (I'm sure it could be optimized further, too...)

                    ISet <string> matchingCharacterIds = null;
                    if (calculateAnyRelatedCharacters &&
                        relChar.TryGetMatchingCharacterIdsOfADifferentAge(characterId, out matchingCharacterIds))
                    {
                        if (matchingCharacterIds.Count == 1)
                        {
                            matchingCharacterIds = null;
                        }
                    }
                    else
                    {
                        foreach (var set in treatAsSameCharacter)
                        {
                            if (set.Contains(characterId))
                            {
                                matchingCharacterIds = set;
                                break;
                            }
                        }
                    }

                    if (matchingCharacterIds == null)
                    {
                        if ((prevMatchingCharacterIds == null && prevCharacterId == characterId) ||
                            (prevMatchingCharacterIds != null && prevMatchingCharacterIds.Contains(characterId)))
                        {
                            currentBlockCount = 0;
                            prevBook          = book;
                            prevBlock         = block;
                        }
                        else if (characterIdsToCalculate.Contains(characterId) &&
                                 (!CharacterVerseData.IsCharacterOfType(characterId, CharacterVerseData.StandardCharacter.Narrator) ||
                                  prevCharacterId == null ||
                                  !CharacterVerseData.IsCharacterOfType(prevCharacterId, CharacterVerseData.StandardCharacter.Narrator)))
                        {
                            if (ProcessDifferentCharacter(book, block, characterId, matchingCharacterIds, ref foundFirst,
                                                          ref currentBlockCount, ref minBlockProximity,
                                                          ref firstBook, ref prevBook, ref firstBlock, ref prevBlock,
                                                          ref secondBook, ref secondBlock, ref breakOutOfBothLoops, ref prevCharacterId, ref prevMatchingCharacterIds))
                            {
                                break;
                            }
                        }
                        else
                        {
                            IncrementCount(countVersesRatherThanBlocks, block, ref currentBlockCount);
                        }
                    }
                    else if (prevMatchingCharacterIds != null && matchingCharacterIds.Intersect(prevMatchingCharacterIds).Any())
                    {
                        currentBlockCount        = 0;
                        prevBook                 = book;
                        prevBlock                = block;
                        prevMatchingCharacterIds = matchingCharacterIds;
                    }
                    else if (characterIdsToCalculate.Intersect(matchingCharacterIds).Any())
                    {
                        if (ProcessDifferentCharacter(book, block, characterId, matchingCharacterIds, ref foundFirst,
                                                      ref currentBlockCount, ref minBlockProximity,
                                                      ref firstBook, ref prevBook, ref firstBlock, ref prevBlock,
                                                      ref secondBook, ref secondBlock, ref breakOutOfBothLoops, ref prevCharacterId, ref prevMatchingCharacterIds))
                        {
                            break;
                        }
                    }
                    else
                    {
                        IncrementCount(countVersesRatherThanBlocks, block, ref currentBlockCount);
                    }
                }
            }

            return(new MinimumProximity(minBlockProximity, firstBook, secondBook, firstBlock, secondBlock));
        }
示例#23
0
        /// <summary>Populates bookData with the standard characters that should be allowed to be grouped together without causing proximity problems</summary>
        private void GetStandardCharactersToTreatAsOne(BookScript book, ProjectDramatizationPreferences dramatizationPreferences,
                                                       Dictionary <ExtraBiblicalMaterialSpeakerOption, HashSet <string> > bookData)
        {
            if (m_strictlyAdhereToNarratorPreferences)
            {
                AddOrNew(bookData, dramatizationPreferences.BookTitleAndChapterDramatization, CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.BookOrChapter));
                AddOrNew(bookData, dramatizationPreferences.SectionHeadDramatization, CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.ExtraBiblical));
                AddOrNew(bookData, dramatizationPreferences.BookIntroductionsDramatization, CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.Intro));
                bookData.Remove(ExtraBiblicalMaterialSpeakerOption.Omitted);

                // add the narrator to its group if there are others there already
                if (bookData.ContainsKey(ExtraBiblicalMaterialSpeakerOption.Narrator))
                {
                    bookData[ExtraBiblicalMaterialSpeakerOption.Narrator].Add(book.NarratorCharacterId);
                }
            }
            else
            {
                AddOrNew(bookData, ExtraBiblicalMaterialSpeakerOption.Narrator, book.NarratorCharacterId);
                if (dramatizationPreferences.BookTitleAndChapterDramatization != ExtraBiblicalMaterialSpeakerOption.Omitted)
                {
                    bookData[ExtraBiblicalMaterialSpeakerOption.Narrator].Add(CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.BookOrChapter));
                }
                if (dramatizationPreferences.SectionHeadDramatization != ExtraBiblicalMaterialSpeakerOption.Omitted)
                {
                    bookData[ExtraBiblicalMaterialSpeakerOption.Narrator].Add(CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.ExtraBiblical));
                }
                if (dramatizationPreferences.BookIntroductionsDramatization != ExtraBiblicalMaterialSpeakerOption.Omitted)
                {
                    bookData[ExtraBiblicalMaterialSpeakerOption.Narrator].Add(CharacterVerseData.GetStandardCharacterId(book.BookId, CharacterVerseData.StandardCharacter.Intro));
                }
            }
        }
示例#24
0
        public static ConcurrentDictionary <BookScript, IReadOnlyList <Block> > Unparse(IEnumerable <BookScript> books)
        {
            var blocksInBook = new ConcurrentDictionary <BookScript, IReadOnlyList <Block> >();

            Parallel.ForEach(books, book =>
            {
                var oldBlocks      = book.GetScriptBlocks();
                var newBlocks      = new List <Block>();
                Block currentBlock = null;

                foreach (var oldBlock in oldBlocks)
                {
                    // is this a new chapter?
                    if (oldBlock.IsParagraphStart || (currentBlock == null))
                    {
                        if (currentBlock != null)
                        {
                            newBlocks.Add(currentBlock);
                        }

                        if (CharacterVerseData.IsCharacterExtraBiblical(oldBlock.CharacterId) && !oldBlock.UserConfirmed)
                        {
                            newBlocks.Add(oldBlock.Clone());
                            currentBlock = null;
                            continue;
                        }
                        else
                        {
                            currentBlock = new Block(oldBlock.StyleTag, oldBlock.ChapterNumber, oldBlock.InitialStartVerseNumber,
                                                     oldBlock.InitialEndVerseNumber);
                            currentBlock.IsParagraphStart = oldBlock.IsParagraphStart;
                        }
                    }

                    foreach (var element in oldBlock.BlockElements)
                    {
                        if (element is Verse)
                        {
                            currentBlock.BlockElements.Add(element.Clone());
                            continue;
                        }

                        // element is Glyssen.ScriptText
                        // check if this text should be appended to the previous element
                        var lastElement = currentBlock.BlockElements.LastOrDefault() as ScriptText;
                        if (lastElement != null)
                        {
                            lastElement.Content += ((ScriptText)element).Content;
                        }
                        else
                        {
                            currentBlock.BlockElements.Add(element.Clone());
                        }
                    }
                }

                // add the last block now
                if (currentBlock != null)
                {
                    newBlocks.Add(currentBlock);
                }

                blocksInBook.AddOrUpdate(book, newBlocks, (script, list) => newBlocks);
            });

            return(blocksInBook);
        }
        public void DistributeBooksAmongNarratorGroups_ThirtySixNarrators_BottomFourAuthorsCombineIntoTwoGroups()
        {
            var narratorGroups = GetNarratorCharacterGroups(36);

            VerifyBasic(narratorGroups, 34);

            Assert.AreEqual(2, narratorGroups[34].CharacterIds.Count);
            Assert.AreEqual(2, narratorGroups[35].CharacterIds.Count);
            // Obadiah and Jude are tied for the fewest number of keystrokes. Haggai is by itself in second-to-last place.
            // Joel, Nahum, Habakkuk, Zephaniah, and Zechariah are all tied for third-to-last place.
            var bookCombinedWithHaggai = CharacterVerseData.GetBookCodeFromStandardCharacterId(narratorGroups[35].CharacterIds.Single(
                                                                                                   c => c != CharacterVerseData.GetStandardCharacterId("HAG", CharacterVerseData.StandardCharacter.Narrator)));
            string bookWhoseAuthorCombinedWithThirdToLastPlaceAuthor;

            if (bookCombinedWithHaggai == "JUD")
            {
                bookWhoseAuthorCombinedWithThirdToLastPlaceAuthor = "OBA";
            }
            else
            {
                Assert.AreEqual("OBA", bookCombinedWithHaggai);
                bookWhoseAuthorCombinedWithThirdToLastPlaceAuthor = "JUD";
            }
            var thirdToLastPlaceBookThatGotCombined = CharacterVerseData.GetBookCodeFromStandardCharacterId(
                narratorGroups[34].CharacterIds.Single(c => c != CharacterVerseData.GetStandardCharacterId(bookWhoseAuthorCombinedWithThirdToLastPlaceAuthor, CharacterVerseData.StandardCharacter.Narrator)));

            Assert.IsTrue(
                thirdToLastPlaceBookThatGotCombined == "JOL" ||
                thirdToLastPlaceBookThatGotCombined == "NAM" ||
                thirdToLastPlaceBookThatGotCombined == "HAB" ||
                thirdToLastPlaceBookThatGotCombined == "ZEP" ||
                thirdToLastPlaceBookThatGotCombined == "ZEC");
        }
        public void FixtureSetup()
        {
            m_keyStrokesByBook = new Dictionary <string, int>();
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("GEN", CharacterVerseData.StandardCharacter.Narrator)] = 50000;            // MOSES
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EXO", CharacterVerseData.StandardCharacter.Narrator)] = 40000;            // MOSES
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("LEV", CharacterVerseData.StandardCharacter.Narrator)] = 27000;            // MOSES
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("NUM", CharacterVerseData.StandardCharacter.Narrator)] = 36000;            // MOSES
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("DEU", CharacterVerseData.StandardCharacter.Narrator)] = 34000;            // MOSES:     187000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JOS", CharacterVerseData.StandardCharacter.Narrator)] = 24000;            // JOSHUA:     24000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JDG", CharacterVerseData.StandardCharacter.Narrator)] = 21000;            // JUDGES:     21000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("RUT", CharacterVerseData.StandardCharacter.Narrator)] = 4000;             // RUTH:        4000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("1SA", CharacterVerseData.StandardCharacter.Narrator)] = 31000;            // SAMUEL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("2SA", CharacterVerseData.StandardCharacter.Narrator)] = 24000;            // SAMUEL:     55000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("1KI", CharacterVerseData.StandardCharacter.Narrator)] = 24000;            // KINGS
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("2KI", CharacterVerseData.StandardCharacter.Narrator)] = 25000;            // KINGS:      49000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("1CH", CharacterVerseData.StandardCharacter.Narrator)] = 35000;            // CHRONICLES
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("2CH", CharacterVerseData.StandardCharacter.Narrator)] = 36000;            // CHRONICLES: 71000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EZR", CharacterVerseData.StandardCharacter.Narrator)] = 10000;            // EZRA:       10000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("NEH", CharacterVerseData.StandardCharacter.Narrator)] = 13000;            // NEHEMIAH:   13000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EST", CharacterVerseData.StandardCharacter.Narrator)] = 10000;            // ESTHER:     10000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JOB", CharacterVerseData.StandardCharacter.Narrator)] = 42000;            // JOB:        42000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("PSA", CharacterVerseData.StandardCharacter.Narrator)] = 99999;            // PSALMS:     99999
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("PRO", CharacterVerseData.StandardCharacter.Narrator)] = 31000;            // SOLOMON
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ECC", CharacterVerseData.StandardCharacter.Narrator)] = 12000;            // SOLOMON
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("SNG", CharacterVerseData.StandardCharacter.Narrator)] = 8000;             // SOLOMON:     51000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ISA", CharacterVerseData.StandardCharacter.Narrator)] = 66000;            // ISAIAH:     66000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JER", CharacterVerseData.StandardCharacter.Narrator)] = 52000;            // JEREMIAH
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("LAM", CharacterVerseData.StandardCharacter.Narrator)] = 5000;             // JEREMIAH:    57000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EZK", CharacterVerseData.StandardCharacter.Narrator)] = 48000;            // EZEKIEL:    48000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("DAN", CharacterVerseData.StandardCharacter.Narrator)] = 12000;            // DANIEL:     12000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("HOS", CharacterVerseData.StandardCharacter.Narrator)] = 14000;            // HOSEA:      14000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JOL", CharacterVerseData.StandardCharacter.Narrator)] = 3000;             // JOEL:         3000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("AMO", CharacterVerseData.StandardCharacter.Narrator)] = 9000;             // AMOS:         9000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("OBA", CharacterVerseData.StandardCharacter.Narrator)] = 1000;             // OBADIAH:      1000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JON", CharacterVerseData.StandardCharacter.Narrator)] = 4000;             // JONAH:        4000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("MIC", CharacterVerseData.StandardCharacter.Narrator)] = 7000;             // MICAH:        7000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("NAM", CharacterVerseData.StandardCharacter.Narrator)] = 3000;             // NAHUM:        3000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("HAB", CharacterVerseData.StandardCharacter.Narrator)] = 3000;             // HABAKKUK:     3000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ZEP", CharacterVerseData.StandardCharacter.Narrator)] = 3000;             // ZEPHANIAH:    3000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("HAG", CharacterVerseData.StandardCharacter.Narrator)] = 2000;             // HAGGAI:       2000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ZEC", CharacterVerseData.StandardCharacter.Narrator)] = 3000;             // ZECHARIAH:    3000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("MAL", CharacterVerseData.StandardCharacter.Narrator)] = 4000;             // MALACHI:      4000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("MAT", CharacterVerseData.StandardCharacter.Narrator)] = 28000;            // MATTHEW:    28000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("MRK", CharacterVerseData.StandardCharacter.Narrator)] = 16000;            // MARK:       16000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("LUK", CharacterVerseData.StandardCharacter.Narrator)] = 24000;            // LUKE
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.Narrator)] = 28000;            // LUKE:       52000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JHN", CharacterVerseData.StandardCharacter.Narrator)] = 20000;            // JOHN
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("1JN", CharacterVerseData.StandardCharacter.Narrator)] = 5000;             // JOHN
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("2JN", CharacterVerseData.StandardCharacter.Narrator)] = 1000;             // JOHN
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("3JN", CharacterVerseData.StandardCharacter.Narrator)] = 1000;             // JOHN
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("REV", CharacterVerseData.StandardCharacter.Narrator)] = 22000;            // JOHN:       49000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ROM", CharacterVerseData.StandardCharacter.Narrator)] = 16000;            // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("1CO", CharacterVerseData.StandardCharacter.Narrator)] = 16000;            // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("2CO", CharacterVerseData.StandardCharacter.Narrator)] = 13000;            // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("GAL", CharacterVerseData.StandardCharacter.Narrator)] = 6000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EPH", CharacterVerseData.StandardCharacter.Narrator)] = 6000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("PHP", CharacterVerseData.StandardCharacter.Narrator)] = 4000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("COL", CharacterVerseData.StandardCharacter.Narrator)] = 4000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("1TH", CharacterVerseData.StandardCharacter.Narrator)] = 5000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("2TH", CharacterVerseData.StandardCharacter.Narrator)] = 3000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("1TI", CharacterVerseData.StandardCharacter.Narrator)] = 6000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("2TI", CharacterVerseData.StandardCharacter.Narrator)] = 4000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("TIT", CharacterVerseData.StandardCharacter.Narrator)] = 3000;             // PAUL
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("PHM", CharacterVerseData.StandardCharacter.Narrator)] = 1000;             // PAUL:        87000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("HEB", CharacterVerseData.StandardCharacter.Narrator)] = 13000;            // HEBREWS:    13000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JAS", CharacterVerseData.StandardCharacter.Narrator)] = 5000;             // JAMES:        5000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("1PE", CharacterVerseData.StandardCharacter.Narrator)] = 5000;             // PETER
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("2PE", CharacterVerseData.StandardCharacter.Narrator)] = 3000;             // PETER:        8000
            m_keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.Narrator)] = 1000;             // JUDE:         1000

            m_authorStats = new List <AuthorStats>();

            m_moses = new BiblicalAuthors.Author {
                Name = "Moses"
            };
            m_joshua = new BiblicalAuthors.Author {
                Name = "Joshua"
            };
            m_judges = new BiblicalAuthors.Author {
                Name = "Author of Judges"
            };
            m_ruth = new BiblicalAuthors.Author {
                Name = "Author of Ruth"
            };
            m_samuel = new BiblicalAuthors.Author {
                Name = "Samuel"
            };
            m_kings = new BiblicalAuthors.Author {
                Name = "Author of Kings"
            };
            m_chronicles = new BiblicalAuthors.Author {
                Name = "Author of Chronicles"
            };
            m_ezra = new BiblicalAuthors.Author {
                Name = "Ezra"
            };
            m_nehemiah = new BiblicalAuthors.Author {
                Name = "Nehemiah"
            };
            m_esther = new BiblicalAuthors.Author {
                Name = "Author of Esther"
            };
            m_job = new BiblicalAuthors.Author {
                Name = "Job"
            };
            m_psalms = new BiblicalAuthors.Author {
                Name = "Author of Psalms"
            };
            m_solomon = new BiblicalAuthors.Author {
                Name = "Solomon"
            };
            m_isaiah = new BiblicalAuthors.Author {
                Name = "Isaiah"
            };
            m_jeremiah = new BiblicalAuthors.Author {
                Name = "Jeremiah"
            };
            m_ezekiel = new BiblicalAuthors.Author {
                Name = "Ezekiel"
            };
            m_daniel = new BiblicalAuthors.Author {
                Name = "Daniel"
            };
            m_hosea = new BiblicalAuthors.Author {
                Name = "Hosea"
            };
            m_joel = new BiblicalAuthors.Author {
                Name = "Joel"
            };
            m_amos = new BiblicalAuthors.Author {
                Name = "Amos"
            };
            m_obadiah = new BiblicalAuthors.Author {
                Name = "Obadiah"
            };
            m_jonah = new BiblicalAuthors.Author {
                Name = "Jonah"
            };
            m_micah = new BiblicalAuthors.Author {
                Name = "Micah"
            };
            m_nahum = new BiblicalAuthors.Author {
                Name = "Nahum"
            };
            m_habakkuk = new BiblicalAuthors.Author {
                Name = "Habakkuk"
            };
            m_zephaniah = new BiblicalAuthors.Author {
                Name = "Zephaniah"
            };
            m_haggai = new BiblicalAuthors.Author {
                Name = "Haggai"
            };
            m_zechariah = new BiblicalAuthors.Author {
                Name = "Zechariah"
            };
            m_malachi = new BiblicalAuthors.Author {
                Name = "Malachi"
            };
            m_matthew = new BiblicalAuthors.Author {
                Name = "Matthew"
            };
            m_mark = new BiblicalAuthors.Author {
                Name = "Mark"
            };
            m_luke = new BiblicalAuthors.Author {
                Name = "Luke"
            };
            m_john = new BiblicalAuthors.Author {
                Name = "John"
            };
            m_paul = new BiblicalAuthors.Author {
                Name = "Paul"
            };
            m_hebrews = new BiblicalAuthors.Author {
                Name = "Author of Hebrews"
            };
            m_james = new BiblicalAuthors.Author {
                Name = "James"
            };
            m_peter = new BiblicalAuthors.Author {
                Name = "Peter"
            };
            m_jude = new BiblicalAuthors.Author {
                Name = "Jude"
            };

            m_authorStats.Add(new AuthorStats(m_moses, m_keyStrokesByBook, "GEN", "EXO", "LEV", "NUM", "DEU"));
            m_authorStats.Add(new AuthorStats(m_joshua, m_keyStrokesByBook, "JOS"));
            m_authorStats.Add(new AuthorStats(m_judges, m_keyStrokesByBook, "JDG"));
            m_authorStats.Add(new AuthorStats(m_ruth, m_keyStrokesByBook, "RUT"));
            m_authorStats.Add(new AuthorStats(m_samuel, m_keyStrokesByBook, "1SA", "2SA"));
            m_authorStats.Add(new AuthorStats(m_kings, m_keyStrokesByBook, "1KI", "2KI"));
            m_authorStats.Add(new AuthorStats(m_chronicles, m_keyStrokesByBook, "1CH", "2CH"));
            m_authorStats.Add(new AuthorStats(m_ezra, m_keyStrokesByBook, "EZR"));
            m_authorStats.Add(new AuthorStats(m_nehemiah, m_keyStrokesByBook, "NEH"));
            m_authorStats.Add(new AuthorStats(m_esther, m_keyStrokesByBook, "EST"));
            m_authorStats.Add(new AuthorStats(m_job, m_keyStrokesByBook, "JOB"));
            m_authorStats.Add(new AuthorStats(m_psalms, m_keyStrokesByBook, "PSA"));
            m_authorStats.Add(new AuthorStats(m_solomon, m_keyStrokesByBook, "PRO", "ECC", "SNG"));
            m_authorStats.Add(new AuthorStats(m_isaiah, m_keyStrokesByBook, "ISA"));
            m_authorStats.Add(new AuthorStats(m_jeremiah, m_keyStrokesByBook, "JER", "LAM"));
            m_authorStats.Add(new AuthorStats(m_ezekiel, m_keyStrokesByBook, "EZK"));
            m_authorStats.Add(new AuthorStats(m_daniel, m_keyStrokesByBook, "DAN"));
            m_authorStats.Add(new AuthorStats(m_hosea, m_keyStrokesByBook, "HOS"));
            m_authorStats.Add(new AuthorStats(m_joel, m_keyStrokesByBook, "JOL"));
            m_authorStats.Add(new AuthorStats(m_amos, m_keyStrokesByBook, "AMO"));
            m_authorStats.Add(new AuthorStats(m_obadiah, m_keyStrokesByBook, "OBA"));
            m_authorStats.Add(new AuthorStats(m_jonah, m_keyStrokesByBook, "JON"));
            m_authorStats.Add(new AuthorStats(m_micah, m_keyStrokesByBook, "MIC"));
            m_authorStats.Add(new AuthorStats(m_nahum, m_keyStrokesByBook, "NAM"));
            m_authorStats.Add(new AuthorStats(m_habakkuk, m_keyStrokesByBook, "HAB"));
            m_authorStats.Add(new AuthorStats(m_zephaniah, m_keyStrokesByBook, "ZEP"));
            m_authorStats.Add(new AuthorStats(m_haggai, m_keyStrokesByBook, "HAG"));
            m_authorStats.Add(new AuthorStats(m_zechariah, m_keyStrokesByBook, "ZEC"));
            m_authorStats.Add(new AuthorStats(m_malachi, m_keyStrokesByBook, "MAL"));
            m_authorStats.Add(new AuthorStats(m_matthew, m_keyStrokesByBook, "MAT"));
            m_authorStats.Add(new AuthorStats(m_mark, m_keyStrokesByBook, "MRK"));
            m_authorStats.Add(new AuthorStats(m_luke, m_keyStrokesByBook, "LUK", "ACT"));
            m_authorStats.Add(new AuthorStats(m_john, m_keyStrokesByBook, "JHN", "1JN", "2JN", "3JN", "REV"));
            m_authorStats.Add(new AuthorStats(m_paul, m_keyStrokesByBook, "ROM", "1CO", "2CO", "GAL", "EPH", "PHP", "COL", "1TH", "2TH", "1TI", "2TI", "TIT", "PHM"));
            m_authorStats.Add(new AuthorStats(m_hebrews, m_keyStrokesByBook, "HEB"));
            m_authorStats.Add(new AuthorStats(m_james, m_keyStrokesByBook, "JAS"));
            m_authorStats.Add(new AuthorStats(m_peter, m_keyStrokesByBook, "1PE", "2PE"));
            m_authorStats.Add(new AuthorStats(m_jude, m_keyStrokesByBook, "JUD"));
            Assert.AreEqual(38, m_authorStats.Count);
        }
 private void SetBlockCharacterToNarrator(string bookCode, int chapter, int verse, string existingCharacterId)
 {
     m_testProject.Books.Single(book => book.BookId == bookCode).GetBlocksForVerse(chapter, verse)
     .Single(b => b.CharacterId == existingCharacterId).CharacterId =
         CharacterVerseData.GetStandardCharacterId(bookCode, CharacterVerseData.StandardCharacter.Narrator);
 }
示例#28
0
        public System.Collections.Generic.IReadOnlyList <Block> GetScriptBlocks(bool join)
        {
            if (!join)
            {
                return(GetScriptBlocks());
            }

            EnsureBlockCount();

            if (!join || m_blockCount == 0)
            {
                return(m_blocks);
            }

            var list = new List <Block>(m_blockCount);

            if (SingleVoice)
            {
                list.Add(m_blocks[0].Clone());
                var prevBlock = list.Single();
                prevBlock.MatchesReferenceText = false;
                var narrator = CharacterVerseData.GetStandardCharacterId(BookId, CharacterVerseData.StandardCharacter.Narrator);
                for (var i = 1; i < m_blockCount; i++)
                {
                    var clonedBlock = m_blocks[i].Clone();
                    clonedBlock.MatchesReferenceText = false;
                    if (!clonedBlock.CharacterIsStandard)
                    {
                        clonedBlock.CharacterId = narrator;
                    }

                    if (!clonedBlock.IsParagraphStart || (clonedBlock.IsFollowOnParagraphStyle && !CharacterUtils.EndsWithSentenceFinalPunctuation(prevBlock.GetText(false))))                     // && clonedBlock.CharacterId == prevBlock.CharacterId)
                    {
                        prevBlock.CombineWith(clonedBlock);
                    }
                    else
                    {
                        list.Add(clonedBlock);
                        prevBlock = clonedBlock;
                    }
                }
            }
            else
            {
                list.Add(m_blocks[0]);
                if (m_styleSheet == null)
                {
                    m_styleSheet = SfmLoader.GetUsfmStylesheet();
                }

                for (var i = 1; i < m_blockCount; i++)
                {
                    var block     = m_blocks[i];
                    var prevBlock = list.Last();

                    if (block.MatchesReferenceText == prevBlock.MatchesReferenceText &&
                        block.CharacterIdInScript == prevBlock.CharacterIdInScript && (block.Delivery ?? Empty) == (prevBlock.Delivery ?? Empty))
                    {
                        bool combine = false;
                        if (block.MatchesReferenceText)
                        {
                            combine = block.ReferenceBlocks.Single().StartsWithEllipsis ||
                                      ((!block.IsParagraphStart || (block.IsFollowOnParagraphStyle && !CharacterUtils.EndsWithSentenceFinalPunctuation(prevBlock.GetText(false)))) &&
                                       !block.ContainsVerseNumber &&
                                       ((!block.ReferenceBlocks.Single().BlockElements.OfType <Verse>().Any() &&
                                         !CharacterUtils.EndsWithSentenceFinalPunctuation(prevBlock.GetText(false))) ||
                                        block.ReferenceBlocks.Single().BlockElements.OfType <ScriptText>().All(t => t.Content.All(IsWhiteSpace)) ||
                                        prevBlock.ReferenceBlocks.Single().BlockElements.OfType <ScriptText>().All(t => t.Content.All(IsWhiteSpace))));
                        }
                        else if (!block.StartsAtVerseStart)
                        {
                            var style = (StyleAdapter)m_styleSheet.GetStyle(block.StyleTag);
                            combine = !block.IsParagraphStart || (style.IsPoetic && !CharacterUtils.EndsWithSentenceFinalPunctuation(prevBlock.GetText(false)));
                        }
                        if (combine)
                        {
                            list[list.Count - 1] = Block.CombineBlocks(prevBlock, block);
                            continue;
                        }
                    }
                    list.Add(block);
                }
            }
            return(list);
        }
        public void DataIntegrity_RequiredFieldsHaveValidFormatAndThereAreNoDuplicateLines()
        {
            Regex regex            = new Regex(kRegexBCV + "(?<character>[^\t]+)\t(?<delivery>[^\t]*)\t(?<alias>[^\t]*)\t(?<type>" + typeof(QuoteType).GetRegexEnumValuesString() + ")\t(?<defaultCharacter>[^\t]*)\t(?<parallelPassageRef>[^\t]*)$", RegexOptions.Compiled);
            Regex extraSpacesRegex = new Regex("^ |\t | \t| $", RegexOptions.Compiled);

            var set = new HashSet <string>();
            ISet <CharacterVerse> uniqueCharacterVerses = new HashSet <CharacterVerse>();

            foreach (var line in AllDataLines)
            {
                var match = regex.Match(line);
                Assert.IsTrue(match.Success, "Failed to match line: " + line);

                var bookId  = match.Result("${bookId}");
                var bookNum = BCVRef.BookToNumber(bookId);
                Assert.IsTrue(bookNum > 0, "Line: " + line);
                Assert.IsTrue(bookNum <= 66, "Line: " + line);

                var chapterAsString = match.Result("${chapter}");
                var chapter         = Int32.Parse(chapterAsString);
                Assert.IsTrue(chapter > 0, "Line: " + line);
                Assert.IsTrue(chapter <= ScrVers.English.GetLastChapter(bookNum), "Line: " + line);

                var verseAsString = match.Result("${verse}");
                var verse         = Int32.Parse(verseAsString);
                Assert.IsTrue(verse > 0 || verse == 0 && bookId == "PSA", "Line: " + line);
                Assert.IsTrue(verse <= ScrVers.English.GetLastVerse(bookNum, chapter), "Line: " + line);

                var sEndVerse = match.Result("${endVerse}");
                if (!string.IsNullOrEmpty(sEndVerse))
                {
                    var endVerse = Int32.Parse(sEndVerse);
                    Assert.IsTrue(endVerse > verse, "Line: " + line);
                    Assert.IsTrue(endVerse <= 152, "Line: " + line);
                }

                var character = match.Result("${character}");

                var alias = match.Result("${alias}");
                if (!string.IsNullOrEmpty(alias))
                {
                    Assert.AreNotEqual(character, alias, "Line: " + line);
                }

                var defaultCharacter = match.Result("${defaultCharacter}");
                if (!string.IsNullOrEmpty(defaultCharacter))
                {
                    Assert.AreNotEqual(character, defaultCharacter, "Line: " + line);
                    Assert.IsFalse(defaultCharacter.Contains("/"), $"Line: {line} has a default character which is a multi-character ID.");
                }

                string typeAsString = match.Result("${type}");
                if (CharacterVerseData.IsCharacterOfType(character, CharacterVerseData.StandardCharacter.Narrator))
                {
                    Assert.AreNotEqual("Dialogue", typeAsString, "Line: " + line);
                }

                var matchResult = match.Result("$&");
                Assert.IsTrue(set.Add(matchResult), "Duplicate line: " + matchResult);

                Assert.IsTrue(QuoteType.TryParse(typeAsString, out QuoteType type));
                foreach (var bcvRef in CharacterVerseData.GetAllVerses(new [] { bookId, chapterAsString, verseAsString }, () => throw new Exception("This should never happen")))
                {
                    var cv = new CharacterVerse(bcvRef, character, match.Result("${delivery}"), alias, false, type, defaultCharacter);
                    Assert.IsTrue(uniqueCharacterVerses.Add(cv), "Line is equivalent to another line even though they are not identical: " + matchResult);
                }

                var extraSpacesMatch = extraSpacesRegex.Match(line);
                Assert.IsFalse(extraSpacesMatch.Success, "Line with extra space(s): " + line);
            }
        }
        public void MakeMinimalAdjustments_FewAdditions_NewGroupAddedWithNewCharacters()
        {
            SetVoiceActors(9, 2, 1);
            GenerateGroups();
            m_testProject.AvailableBooks.Single(b => b.Code == "JUD").IncludeInScript = true;
            m_testProject.ClearCharacterStatistics();             // This simulates behavior in UI when the project is saved after displaying ScriptureRangeSelectionDlg
            var adjuster = new CharacterGroupsAdjuster(m_testProject);

            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.Narrator)));
            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.ExtraBiblical)));
            Assert.IsTrue(adjuster.CharactersNotCoveredByAnyGroup.Contains(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.BookOrChapter)));
            var countOfCharactersNotCovered = adjuster.CharactersNotCoveredByAnyGroup.Count();

            Assert.AreEqual(0, adjuster.CharactersNoLongerInUse.Count());
            var originalCountOfGroups = m_testProject.CharacterGroupList.CharacterGroups.Count;

            adjuster.MakeMinimalAdjustments();
            Assert.IsFalse(adjuster.GroupsAreNotInSynchWithData);
            Assert.AreEqual(0, adjuster.CharactersNotCoveredByAnyGroup.Count());
            Assert.AreEqual(0, adjuster.CharactersNoLongerInUse.Count());
            Assert.AreEqual(originalCountOfGroups + 1, m_testProject.CharacterGroupList.CharacterGroups.Count);
            var newGroup = m_testProject.CharacterGroupList.GroupContainingCharacterId(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.Narrator));

            Assert.IsFalse(m_testProject.CharacterGroupList.CharacterGroups.Any(g => g.GroupId == newGroup.GroupId && g != newGroup));
            Assert.IsTrue(newGroup.CharacterIds.Contains(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.ExtraBiblical)));
            Assert.IsTrue(newGroup.CharacterIds.Contains(CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.BookOrChapter)));
            Assert.AreEqual(countOfCharactersNotCovered, newGroup.CharacterIds.Count);
        }