private void AddRecordToProjectCharacterVerseData(Block block, Character character, Delivery delivery)
        {
            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();
        }
        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();
        }
        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);
            }
        }