/// -------------------------------------------------------------------------------- /// <summary> /// Determines whether the ending reference of the previous section and the starting /// reference of the following section are contiguous. /// </summary> /// <param name="endRefOfSection">The ending reference of section.</param> /// <param name="startRefOfNextSection">The starting reference of following section.</param> /// <param name="bookId">The canonical number for the current book.</param> /// <param name="versification">The versification.</param> /// <returns> /// <c>true</c> if the sections do not have contiguous references, <c>false</c> /// otherwise /// </returns> /// -------------------------------------------------------------------------------- private static bool RefHasGap(BCVRef endRefOfSection, BCVRef startRefOfNextSection, int bookId, ScrVers versification) { if (endRefOfSection.Chapter == startRefOfNextSection.Chapter) { // For references in the same chapter, determine whether the starting verse // in the next section is the same or just one more than the end of the // current section. return((endRefOfSection.Verse + 1) < startRefOfNextSection.Verse); } VersificationTable verseTable = VersificationTable.Get(versification); if ((endRefOfSection.Chapter + 1) == startRefOfNextSection.Chapter) { if (endRefOfSection.Verse != verseTable.LastVerse(bookId, endRefOfSection.Verse) || startRefOfNextSection.Verse == 1) { // The current section's last verse is the end of the chapter and the // next section starts with the first verse of the next chapter. return(false); } } return(true); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Constructs and returns a new ScrReference representing Revelation 22:21 (or whatver /// the last verse is in Revelation for the current default versification scheme). /// </summary> /// <param name="versification">The versification scheme.</param> /// ------------------------------------------------------------------------------------ public static ScrReference EndOfBible(Paratext.ScrVers versification) { VersificationTable versificationTable = VersificationTable.Get(versification); int lastChapter = versificationTable.LastChapter(LastBook); return(new ScrReference(LastBook, lastChapter, versificationTable.LastVerse(LastBook, lastChapter), versification)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Check verse numbers. /// </summary> /// ------------------------------------------------------------------------------------ private void CheckVerseNumbers(ChapterToken chapToken, int bookId) { int lastVrsInChap = m_versification.LastVerse(bookId, chapToken.ChapterNumber); int nextExpectedVerse = 1; bool expectingPartB = false; int prevVerseStart = 0; int prevVerseEnd = 0; ITextToken[] versesFound = new ITextToken[lastVrsInChap + 1]; versesFound[0] = chapToken.Token; foreach (VerseToken verseToken in chapToken.VerseTokens) { ITextToken token = verseToken.VerseNumber; ITextToken reportedToken = token; string msg = null; int offset = 0; int length = token.Text.Length; object[] errorArgs = null; bool countFoundVerses = false; int curVerseStart; int curVerseEnd; VersePart vrsPart; if (verseToken.ImplicitVerseNumber == 1) { versesFound[1] = token; continue; } ParseVerseResult parseResult = ParseVerseNumber(token.Text, out curVerseStart, out curVerseEnd, out vrsPart); if (parseResult == ParseVerseResult.ValidWithSpaceInVerse) { // Log error telling user there are spaces before or after the verse // number. This means the space(s) have the verse number style. This isn't // considered an invalid verse number, but we do need to tell the user. AddError(token, 0, token.Text.Length, Localize("Space found in verse number"), token.Text); } else if (parseResult == ParseVerseResult.ValidWithSpaceInVerseBridge) { // Log error telling user there are spaces in a verse bridge. This // means the space(s) have the verse number style. This isn't considered // an invalid verse number, but we do need to tell the user. AddError(token, 0, token.Text.Length, Localize("Space found in verse bridge"), token.Text); } if (parseResult == ParseVerseResult.Invalid) { msg = Localize("Invalid verse number"); } else if ((parseResult != ParseVerseResult.InvalidFormat) && VersesAlreadyFound(curVerseStart, curVerseEnd, versesFound) && !(expectingPartB && vrsPart == VersePart.PartB)) { if (AnyOverlappingVerses(curVerseStart, curVerseEnd, prevVerseStart, prevVerseEnd, out errorArgs)) { // Duplicate verse(s) found. msg = (errorArgs.Length == 1 ? Localize("Duplicate verse number") : Localize("Duplicate verse numbers")); } else { // Verse number(s) are unexpected msg = (curVerseStart == curVerseEnd ? Localize("Unexpected verse number") : Localize("Unexpected verse numbers")); } } else if (AnyOverlappingVerses(curVerseStart, curVerseEnd, lastVrsInChap + 1, int.MaxValue, out errorArgs)) { countFoundVerses = true; // Start and/or end verse is out of range msg = (errorArgs.Length == 1 ? Localize("Verse number out of range") : Localize("Verse numbers out of range")); } else if (curVerseStart < nextExpectedVerse) { // Verse number(s) are out of order countFoundVerses = true; if (nextExpectedVerse <= lastVrsInChap) { errorArgs = new object[] { nextExpectedVerse }; msg = (curVerseStart == curVerseEnd ? Localize("Verse number out of order; expected verse {0}") : Localize("Verse numbers out of order; expected verse {0}")); } else { msg = (curVerseStart == curVerseEnd ? Localize("Verse number out of order") : Localize("Verse numbers out of order")); } } else if (((vrsPart == VersePart.PartB) != expectingPartB) && (curVerseStart == curVerseEnd)) { // Missing part A or B // TODO: cover cases like "4a 5-7" and "4 5b-7". This would require // ParseVerseNumber() to detect verse parts at the beginning of bridges. reportedToken = (vrsPart == VersePart.PartB ? token : versesFound[prevVerseEnd]); msg = Localize("Missing verse number {0}"); offset = (vrsPart == VersePart.PartB ? 0 : reportedToken.Text.Length); length = 0; int reportedVrsNum = (vrsPart == VersePart.PartB ? curVerseStart : prevVerseEnd); string fmt = (vrsPart == VersePart.PartB ? "{0}a" : "{0}b"); errorArgs = new object[] { string.Format(fmt, reportedVrsNum) }; countFoundVerses = true; } else if ((vrsPart == VersePart.PartB && curVerseStart > prevVerseEnd) && (curVerseStart == curVerseEnd)) { // Missing both a part B and A reportedToken = versesFound[prevVerseEnd]; AddError(reportedToken, reportedToken.Text.Length, 0, Localize("Missing verse number {0}"), new object[] { string.Format("{0}b", prevVerseEnd) }); AddError(token, 0, 0, Localize("Missing verse number {0}"), new object[] { string.Format("{0}a", curVerseStart) }); } if (msg != null) { // Report the error found. if (errorArgs == null) { AddError(reportedToken, offset, length, msg); } else { AddError(reportedToken, offset, length, msg, errorArgs); } } if (msg == null || countFoundVerses) { // No error was found for the current verse range so set all the verses // in our found verse list corresponding to those in the range. for (int i = curVerseStart; i <= Math.Min(curVerseEnd, lastVrsInChap); i++) { versesFound[i] = token; } } if (parseResult == ParseVerseResult.InvalidFormat) { AddError(token, 0, token.Text.Length, Localize("Invalid verse number"), token.Text); } // only worry about this if the chapter and/or verse tokens are in order if (verseToken.VerseTextCount < 1) { AddError(verseToken.VerseNumber, 0, verseToken.VerseNumber.Text.Length, Localize("Missing verse text in verse {0}"), verseToken.VerseNumber.Text); } // Determine next expected verse. // Don't expect a partB if there was an error with partA expectingPartB = (vrsPart == VersePart.PartA && msg == null); if (!expectingPartB && curVerseEnd <= lastVrsInChap) { nextExpectedVerse = curVerseEnd + 1; } prevVerseStart = curVerseStart; prevVerseEnd = curVerseEnd; } CheckForMissingVerses(versesFound, bookId, chapToken.ChapterNumber); }