package net.bible.android.control.versification; import net.bible.android.control.ApplicationScope; import net.bible.android.control.navigation.DocumentBibleBooks; import net.bible.android.control.navigation.DocumentBibleBooksFactory; import org.crosswire.jsword.book.basic.AbstractPassageBook; import org.crosswire.jsword.passage.Verse; import org.crosswire.jsword.passage.VerseRange; import org.crosswire.jsword.versification.BibleBook; import org.crosswire.jsword.versification.Versification; import javax.inject.Inject; /** * Enable separation of Scripture books * * @author Martin Denham [mjdenham at gmail dot com] * @see gnu.lgpl.License for license details.<br> * The copyright to this program is held by it's author. */ @ApplicationScope public class BibleTraverser { private final DocumentBibleBooksFactory documentBibleBooksFactory; @Inject public BibleTraverser(DocumentBibleBooksFactory documentBibleBooksFactory) { this.documentBibleBooksFactory = documentBibleBooksFactory; } /** Get next Scriptural Verse with same scriptural status */ public Verse getNextVerse(AbstractPassageBook document, Verse verse) { Versification v11n = verse.getVersification(); BibleBook book = verse.getBook(); int chapter = verse.getChapter(); int verseNo = verse.getVerse(); // if past last chapter of book then go to next book - algorithm not foolproof but we only move one chapter at a time like this if (verseNo<v11n.getLastVerse(book, chapter)) { return new Verse(v11n, book, chapter, verseNo+1); } else { return getNextChapter(document, verse); } } /** Get previous Verse with same scriptural status */ public Verse getPrevVerse(AbstractPassageBook document, Verse verse) { Versification v11n = verse.getVersification(); BibleBook book = verse.getBook(); int chapter = verse.getChapter(); int verseNo = verse.getVerse(); if (verseNo>1) { verseNo -= 1; } else { Verse prevChap = getPrevChapter(document, verse); if (!v11n.isSameChapter(verse, prevChap)) { book = prevChap.getBook(); chapter = prevChap.getChapter(); verseNo = v11n.getLastVerse(book, chapter); } } return new Verse(v11n, book, chapter, verseNo); } public VerseRange getNextVerseRange(AbstractPassageBook document, VerseRange verseRange) { return getNextVerseRange(document, verseRange, true); } public VerseRange getNextVerseRange(AbstractPassageBook document, VerseRange verseRange, boolean continueToNextChapter) { Versification v11n = verseRange.getVersification(); int verseCount = verseRange.getCardinality(); // shuffle forward Verse start = verseRange.getStart(); Verse end = verseRange.getEnd(); int i=0; while (i++<verseCount && (continueToNextChapter || !v11n.isEndOfChapter(end))) { start = getNextVerse(document, start); end = getNextVerse(document, end); } return new VerseRange(v11n, start, end); } public VerseRange getPreviousVerseRange(AbstractPassageBook document, VerseRange verseRange) { return getPreviousVerseRange(document, verseRange, true); } public VerseRange getPreviousVerseRange(AbstractPassageBook document, VerseRange verseRange, boolean continueToPreviousChapter) { Versification v11n = verseRange.getVersification(); int verseCount = verseRange.getCardinality(); // shuffle backward Verse start = verseRange.getStart(); Verse end = verseRange.getEnd(); int i=0; while (i++<verseCount && (continueToPreviousChapter || !v11n.isStartOfChapter(start))) { start = getPrevVerse(document, start); end = getPrevVerse(document, end); } return new VerseRange(v11n, start, end); } /** Get next chapter consistent with current verses scriptural status ie don't hop between book with different scriptural states */ public Verse getNextChapter(AbstractPassageBook document, Verse verse) { Versification v11n = verse.getVersification(); BibleBook book = verse.getBook(); int chapter = verse.getChapter(); // if past last chapter of book then go to next book - algorithm not foolproof but we only move one chapter at a time like this if (chapter<v11n.getLastChapter(book)) { chapter += 1; } else { BibleBook nextBook = getNextBook(document, v11n, book); // if there was a next book then go to it's first chapter if (nextBook!=null) { book = nextBook; chapter=1; } } return new Verse(v11n, book, chapter, 1); } /** Get previous chapter consistent with current verses scriptural status ie don't hop between book with different scriptural states */ public Verse getPrevChapter(AbstractPassageBook document, Verse verse) { Versification v11n = verse.getVersification(); BibleBook book = verse.getBook(); int chapter = verse.getChapter(); // if past last chapter of book then go to next book - algorithm not foolproof but we only move one chapter at a time like this if (chapter>1) { chapter -= 1; } else { BibleBook prevBook = getPrevBook(document, v11n, book); // if there was a next book then go to it's first chapter if (prevBook!=null) { book = prevBook; chapter=v11n.getLastChapter(book); } } return new Verse(v11n, book, chapter, 1); } /** * Get next book but separate scripture from other books to prevent unintentional jumping between Scripture and other */ private BibleBook getNextBook(AbstractPassageBook document, Versification v11n, BibleBook book) { boolean isCurrentlyScripture = Scripture.isScripture(book); DocumentBibleBooks documentBibleBooks = documentBibleBooksFactory.getDocumentBibleBooksFor(document); BibleBook nextBook = book; do { nextBook = v11n.getNextBook(nextBook); } while (nextBook!=null && ( Scripture.isScripture(nextBook)!=isCurrentlyScripture || Scripture.isIntro(nextBook) || !documentBibleBooks.contains(nextBook) ) ); return nextBook; } private BibleBook getPrevBook(AbstractPassageBook document, Versification v11n, BibleBook book) { boolean isCurrentlyScripture = Scripture.isScripture(book); DocumentBibleBooks documentBibleBooks = documentBibleBooksFactory.getDocumentBibleBooksFor(document); BibleBook prevBook = book; do { prevBook = v11n.getPreviousBook(prevBook); } while (prevBook!=null && ( Scripture.isScripture(prevBook)!=isCurrentlyScripture || Scripture.isIntro(prevBook) || !documentBibleBooks.contains(prevBook) ) ); return prevBook; } }