Coverage Report - org.crosswire.jsword.passage.OsisParser
 
Classes in this File Line Coverage Branch Coverage Complexity
OsisParser
0%
0/58
0%
0/46
7.6
 
 1  
 /**
 2  
  * Distribution License:
 3  
  * JSword is free software; you can redistribute it and/or modify it under
 4  
  * the terms of the GNU Lesser General Public License, version 2.1 or later
 5  
  * as published by the Free Software Foundation. This program is distributed
 6  
  * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 7  
  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 8  
  * See the GNU Lesser General Public License for more details.
 9  
  *
 10  
  * The License is available on the internet at:
 11  
  *      http://www.gnu.org/copyleft/lgpl.html
 12  
  * or by writing to:
 13  
  *      Free Software Foundation, Inc.
 14  
  *      59 Temple Place - Suite 330
 15  
  *      Boston, MA 02111-1307, USA
 16  
  *
 17  
  * © CrossWire Bible Society, 2005 - 2016
 18  
  *
 19  
  */
 20  
 package org.crosswire.jsword.passage;
 21  
 
 22  
 import java.util.ArrayList;
 23  
 import java.util.Arrays;
 24  
 import java.util.List;
 25  
 
 26  
 import org.crosswire.common.util.StringUtil;
 27  
 import org.crosswire.jsword.versification.BibleBook;
 28  
 import org.crosswire.jsword.versification.Versification;
 29  
 
 30  
 /**
 31  
  * The Osis ID parser simply assumes 1-3 parts divided by '.'.
 32  
  * Any deviation from the dot-delimited formatted yields nulls.
 33  
  * 
 34  
  * OSIS Refs should be separated by a '-' if there are 2 refs signifying a range e.g. Gen.1-Gen.3.  
 35  
  * 
 36  
  * The current implementation doesn't support an OSIS ID or OSIS ref with a missing chapter, 
 37  
  * as are currently returned by the getOsisRef() calls occasionally.
 38  
  * 
 39  
  * Algorithm:
 40  
  * If ony 1 ID passed in then create ending id from it to enable a single flow through algorithm.
 41  
  * Missing chapter or verse of starting id will be set to 0/1. 
 42  
  * Missing chapter or verse of ending id will be set to last chapter/verse. 
 43  
  * 
 44  
  * @author Chris Burrell, mjdenham
 45  
  */
 46  0
 public final class OsisParser {
 47  
 
 48  
     // This could be 1 or 0 but for now I have used 1
 49  
     private static final String START_CHAPTER_OR_VERSE = "1";
 50  
 
 51  
     /**
 52  
      * String OSIS Ref parser, assumes a - separating two osis IDs
 53  
      * @param v11n the v11n
 54  
      * @param osisRef the ref
 55  
      * @return the equivalent verse range
 56  
      */
 57  
     public VerseRange parseOsisRef(final Versification v11n, final String osisRef) {
 58  0
         final String[] osisIDs = StringUtil.splitAll(osisRef, VerseRange.RANGE_OSIS_DELIM);
 59  
         // Too many or few parts?
 60  0
         if (osisIDs.length < 1 || osisIDs.length > 2) {
 61  0
             return null;
 62  
         }
 63  
 
 64  
         // Parts must have content.
 65  0
         if (osisIDs[0].length() == 0 || (osisIDs.length == 2 && osisIDs[1].length() == 0)) {
 66  0
             return null;
 67  
         }
 68  
 
 69  
         // Ensure ending OSIS id exists to simplify future logic - yes it is okay to use the start id as the end id here
 70  0
         String startOsisID = osisIDs[0];
 71  
         String endOsisID;
 72  0
         if (osisIDs.length == 1) {
 73  0
             endOsisID = startOsisID;
 74  
         } else {
 75  0
             endOsisID = osisIDs[1];
 76  
         }
 77  
 
 78  
         // ensure no empty parts in osis id1 and not too many parts
 79  0
         List<String> startOsisIDParts = splitOsisId(startOsisID);
 80  0
         if (isAnEmptyPart(startOsisIDParts) || startOsisIDParts.size() > 3) {
 81  0
             return null;
 82  
         }
 83  
 
 84  
         // manipulate first osis id to 3 parts, padding with first chapter or verse
 85  0
         while (startOsisIDParts.size() < 3) {
 86  0
             startOsisIDParts.add(START_CHAPTER_OR_VERSE);
 87  
         }
 88  
         // now we have a full 3 part start OSIS id
 89  
 
 90  
         // Now let us manufacture a 3 part end OSIS id
 91  
 
 92  
         // First check no empty parts were passed in for osis id 2
 93  0
         List<String> endOsisIDParts = splitOsisId(endOsisID);
 94  0
         if (isAnEmptyPart(endOsisIDParts)) {
 95  0
             return null;
 96  
         }
 97  
 
 98  
         // Add end chapter/verse if missing
 99  0
         int endOsisIDPartCount = endOsisIDParts.size();
 100  0
         if (endOsisIDPartCount < 3) {
 101  
             // need to calculate chapter and verse for osis id 2
 102  
 
 103  
             // there will always be a book
 104  0
             String bookName = endOsisIDParts.get(0);
 105  0
             final BibleBook book = BibleBook.fromExactOSIS(bookName);
 106  
 
 107  
             // can asssume last chapter if unspecified because this is the trailing osis Id
 108  
             int chapter;
 109  0
             if (endOsisIDPartCount == 1) {
 110  0
                 chapter = v11n.getLastChapter(book);
 111  0
                 endOsisIDParts.add(Integer.toString(chapter));
 112  
             } else {
 113  0
                 chapter = Integer.parseInt(endOsisIDParts.get(1));
 114  
             }
 115  
 
 116  
             // can asssume last verse if unspecified because this is the trailing osis Id
 117  
             int verse;
 118  0
             if (endOsisIDPartCount < 3) {
 119  0
                 verse = v11n.getLastVerse(book, chapter);
 120  0
                 endOsisIDParts.add(Integer.toString(verse));
 121  
             }
 122  
         }
 123  
 
 124  
         // Now there is exactly 1 beginning and 1 ending 3-part verse only beyond this point
 125  0
         Verse start = parseOsisID(v11n, startOsisIDParts);
 126  0
         if (start == null) {
 127  0
             return null;
 128  
         }
 129  
 
 130  0
         Verse end = parseOsisID(v11n, endOsisIDParts);
 131  0
         if (end == null) {
 132  0
             return null;
 133  
         }
 134  
 
 135  0
         return new VerseRange(v11n, start, end);
 136  
     }
 137  
 
 138  
     /**
 139  
      * Strict OSIS ID parsers, case-sensitive
 140  
      * @param v11n the versification to use when constructing the verse
 141  
      * @param osisID the ID we want to parse
 142  
      * @return the verse that matches the OSIS ID
 143  
      */
 144  
     public Verse parseOsisID(final Versification v11n, final String osisID) {
 145  0
         if (osisID == null) {
 146  0
             return null;
 147  
         }
 148  
 
 149  0
         final List<String> osisIDParts = splitOsisId(osisID);
 150  
 
 151  0
         if (osisIDParts.size() != 3 || isAnEmptyPart(osisIDParts)) {
 152  0
             return null;
 153  
         }
 154  
 
 155  0
         return parseOsisID(v11n, osisIDParts);
 156  
     }
 157  
 
 158  
     private Verse parseOsisID(final Versification v11n, final List<String> osisIDParts) {
 159  
 
 160  0
         final BibleBook b = BibleBook.fromExactOSIS(osisIDParts.get(0));
 161  0
         if (b == null) {
 162  0
             return null;
 163  
         }
 164  
 
 165  
         // Allow a Verse to have a sub identifier on the last part.
 166  
         // We should use it, but throwing it away for now.
 167  0
         String[] endParts = StringUtil.splitAll(osisIDParts.get(2), Verse.VERSE_OSIS_SUB_PREFIX);
 168  0
         String subIdentifier = null;
 169  0
         if (endParts.length == 2 && endParts[1].length() > 0) {
 170  0
             subIdentifier = endParts[1];
 171  
         }
 172  0
         return new Verse(v11n, b, Integer.parseInt(osisIDParts.get(1)), Integer.parseInt(endParts[0]), subIdentifier);
 173  
     }
 174  
 
 175  
     /**
 176  
      * Split string like 'Gen.1.1' into a 3 element list
 177  
      */
 178  
     private List<String> splitOsisId(String osisID1) {
 179  0
         String[] partArray = StringUtil.splitAll(osisID1, Verse.VERSE_OSIS_DELIM);
 180  
 
 181  
         // add to an appropriately sized editable list
 182  0
         List<String> list = new ArrayList(3);
 183  0
         list.addAll(Arrays.asList(partArray));
 184  0
         return list;
 185  
     }
 186  
 
 187  
     /** 
 188  
      * Check no part of the Osis ref is empty
 189  
      */
 190  
     private static boolean isAnEmptyPart(List<String> parts) {
 191  0
         for (String part : parts) {
 192  0
             if (part.length() == 0) {
 193  0
                 return true;
 194  
             }
 195  
         }
 196  0
         return false;
 197  
     }
 198  
 }