| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| QualifiedKey |
|
| 2.0952380952380953;2.095 | ||||
| QualifiedKey$1 |
|
| 2.0952380952380953;2.095 | ||||
| QualifiedKey$Qualifier |
|
| 2.0952380952380953;2.095 | ||||
| QualifiedKey$Qualifier$1 |
|
| 2.0952380952380953;2.095 | ||||
| QualifiedKey$Qualifier$2 |
|
| 2.0952380952380953;2.095 | ||||
| QualifiedKey$Qualifier$3 |
|
| 2.0952380952380953;2.095 |
| 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, 2013 - 2016 | |
| 18 | * | |
| 19 | */ | |
| 20 | package org.crosswire.jsword.versification; | |
| 21 | ||
| 22 | import org.crosswire.jsword.passage.Verse; | |
| 23 | import org.crosswire.jsword.passage.VerseKey; | |
| 24 | import org.crosswire.jsword.passage.VerseRange; | |
| 25 | import org.crosswire.jsword.versification.system.Versifications; | |
| 26 | ||
| 27 | /** | |
| 28 | * A QualifiedKey represents the various left and right sides of a map entry. | |
| 29 | * <p> | |
| 30 | * The QualifiedKey is Qualified: | |
| 31 | * </p> | |
| 32 | * <ul> | |
| 33 | * <li><strong>DEFAULT</strong> - This QualifiedKey is either a Verse or a VerseRange.</li> | |
| 34 | * <li><strong>ABSENT_IN_KJV</strong> - This QualifiedKey has a section name for what is absent in the KJV (the right hand of the map entry).</li> | |
| 35 | * <li><strong>ABSENT_IN_LEFT</strong> - This QualifiedKey has no other content.</li> | |
| 36 | * </ul> | |
| 37 | * <p> | |
| 38 | * The mapping can indicate a part of a verse. This is an internal implementation detail of the Versification mapping code. | |
| 39 | * Here it is used to distinguish one QualifiedKey from another in equality tests and in containers. | |
| 40 | * </p> | |
| 41 | * | |
| 42 | * @author Chris Burrell | |
| 43 | * @see gnu.lgpl.License The GNU Lesser General Public License for details.<br> | |
| 44 | * The copyright to this program is held by its authors. | |
| 45 | */ | |
| 46 | public final class QualifiedKey { | |
| 47 | /** | |
| 48 | * A Qualifier indicates whether the verse is numbered the same in both the KJV and the other, is missing in the KJV or the other. | |
| 49 | */ | |
| 50 | 0 | enum Qualifier { |
| 51 | /** | |
| 52 | * The DEFAULT Qualifier indicates a Verse or a VerseRange. | |
| 53 | */ | |
| 54 | 0 | DEFAULT { |
| 55 | @Override | |
| 56 | public String getDescription(QualifiedKey q) { | |
| 57 | 0 | return ""; |
| 58 | } | |
| 59 | }, | |
| 60 | /** | |
| 61 | * The ABSENT_IN_LEFT Qualifier indicates that the left side of the map has no equivalent on the right (KJV). | |
| 62 | */ | |
| 63 | 0 | ABSENT_IN_LEFT { |
| 64 | @Override | |
| 65 | public String getDescription(QualifiedKey q) { | |
| 66 | 0 | return "Absent in Left"; |
| 67 | } | |
| 68 | }, | |
| 69 | /** | |
| 70 | * The ABSENT_IN_KJV Qualifier indicates that the right (KJV) side of the map has no equivalent on the left. | |
| 71 | */ | |
| 72 | 0 | ABSENT_IN_KJV { |
| 73 | @Override | |
| 74 | public String getDescription(QualifiedKey q) { | |
| 75 | 0 | return q != null && q.getSectionName() != null ? q.getSectionName() : "Missing section name"; |
| 76 | } | |
| 77 | }; | |
| 78 | ||
| 79 | /** | |
| 80 | * @param q the QualifiedKey that this describes | |
| 81 | * @return The description for the qualified key | |
| 82 | */ | |
| 83 | public abstract String getDescription(QualifiedKey q); | |
| 84 | ||
| 85 | } | |
| 86 | ||
| 87 | /** | |
| 88 | * Construct a QualifiedKey from a Verse. | |
| 89 | * | |
| 90 | * @param key the verse from which to create this QualifiedKey | |
| 91 | */ | |
| 92 | 0 | protected QualifiedKey(Verse key) { |
| 93 | 0 | setKey(key); |
| 94 | 0 | this.absentType = Qualifier.DEFAULT; |
| 95 | 0 | } |
| 96 | ||
| 97 | /** | |
| 98 | * Construct a QualifiedKey from a Verse. | |
| 99 | * | |
| 100 | * @param key the verse range from which to create this QualifiedKey | |
| 101 | */ | |
| 102 | 0 | public QualifiedKey(VerseRange key) { |
| 103 | 0 | setKey(key); |
| 104 | 0 | this.absentType = Qualifier.DEFAULT; |
| 105 | 0 | } |
| 106 | ||
| 107 | /** | |
| 108 | * @param sectionName with a given section name, we assume absent in KJV | |
| 109 | */ | |
| 110 | 0 | public QualifiedKey(String sectionName) { |
| 111 | 0 | this.sectionName = sectionName; |
| 112 | 0 | this.absentType = Qualifier.ABSENT_IN_KJV; |
| 113 | 0 | } |
| 114 | ||
| 115 | /** | |
| 116 | * Constructs the QualifiedKey with the ABSENT_IN_LEFT qualifier. | |
| 117 | * This really means that there are no fields in this QualifiedKey. | |
| 118 | */ | |
| 119 | 0 | public QualifiedKey() { |
| 120 | 0 | this.absentType = Qualifier.ABSENT_IN_LEFT; |
| 121 | 0 | } |
| 122 | ||
| 123 | /** | |
| 124 | * Create a QualifiedKey from a Verse or a VerseRange. | |
| 125 | * | |
| 126 | * @param k the Verse or VerseRange | |
| 127 | * @return the created QualifiedKey | |
| 128 | * @throws ClassCastException | |
| 129 | */ | |
| 130 | public static QualifiedKey create(VerseKey k) { | |
| 131 | 0 | return k instanceof Verse ? new QualifiedKey((Verse) k) : new QualifiedKey((VerseRange) k); |
| 132 | } | |
| 133 | ||
| 134 | /** | |
| 135 | * @return * The internal key which is either a Verse or VerseRange | |
| 136 | */ | |
| 137 | public VerseKey getKey() { | |
| 138 | 0 | return wholeKey; |
| 139 | } | |
| 140 | ||
| 141 | /** | |
| 142 | * @return * The internal key cast as a Verse | |
| 143 | * @throws ClassCastException | |
| 144 | */ | |
| 145 | public Verse getVerse() { | |
| 146 | 0 | return (Verse) wholeKey; |
| 147 | } | |
| 148 | ||
| 149 | /** | |
| 150 | * @return the type of the unknown qualifier | |
| 151 | */ | |
| 152 | public Qualifier getAbsentType() { | |
| 153 | 0 | return absentType; |
| 154 | } | |
| 155 | ||
| 156 | /** | |
| 157 | * @return the name (any name) of the section represented within the KJV | |
| 158 | */ | |
| 159 | public String getSectionName() { | |
| 160 | 0 | return sectionName; |
| 161 | } | |
| 162 | ||
| 163 | /** | |
| 164 | * A QualifiedKey is whole if it does not split part of a reference. | |
| 165 | * | |
| 166 | * @return whether this QualifiedKey has a whole reference | |
| 167 | */ | |
| 168 | public boolean isWhole() { | |
| 169 | // If the reference is null, then it cannot be part or whole. | |
| 170 | // But we say it is whole because the calls to this are really testing | |
| 171 | // to see if it is a part. | |
| 172 | 0 | return qualifiedKey == null || qualifiedKey.isWhole(); |
| 173 | } | |
| 174 | ||
| 175 | /** | |
| 176 | * Convert this QualifiedKey from one Versification to another. | |
| 177 | * This is a potentially dangerous operation that does no mapping | |
| 178 | * from one versification to another. Use it only when it is known | |
| 179 | * to be safe. | |
| 180 | * | |
| 181 | * @param target The target versification | |
| 182 | * @return The reversified QualifiedKey | |
| 183 | */ | |
| 184 | public QualifiedKey reversify(Versification target) { | |
| 185 | // Only if it has a qualified key can it be reversified | |
| 186 | 0 | if (this.qualifiedKey == null) { |
| 187 | 0 | return this; |
| 188 | } | |
| 189 | ||
| 190 | 0 | final VerseKey reversifiedKey = qualifiedKey.reversify(target); |
| 191 | 0 | if (reversifiedKey != null) { |
| 192 | 0 | return create(reversifiedKey); |
| 193 | } | |
| 194 | ||
| 195 | 0 | if (target.getName().equals(Versifications.DEFAULT_V11N)) { |
| 196 | //then we're absent in KJV | |
| 197 | 0 | return new QualifiedKey(qualifiedKey.getOsisID()); |
| 198 | } | |
| 199 | 0 | return new QualifiedKey(); |
| 200 | ||
| 201 | } | |
| 202 | ||
| 203 | @Override | |
| 204 | public String toString() { | |
| 205 | 0 | StringBuilder buf = new StringBuilder(); |
| 206 | 0 | if (wholeKey != null) { |
| 207 | 0 | buf.append(qualifiedKey.getOsisRef()); |
| 208 | } | |
| 209 | 0 | String desc = absentType.getDescription(this); |
| 210 | 0 | if (desc.length() > 0) { |
| 211 | 0 | if (buf.length() > 0) { |
| 212 | 0 | buf.append(": "); |
| 213 | } | |
| 214 | 0 | buf.append(absentType.getDescription(this)); |
| 215 | } | |
| 216 | 0 | return buf.toString(); |
| 217 | } | |
| 218 | ||
| 219 | @Override | |
| 220 | public int hashCode() { | |
| 221 | // Use a prime number in case one of the values is not around | |
| 222 | 0 | return (this.qualifiedKey == null ? 17 : qualifiedKey.hashCode()) |
| 223 | + (this.absentType == null ? 13 : this.absentType.ordinal()) | |
| 224 | + (this.sectionName == null ? 19 : this.sectionName.hashCode()); | |
| 225 | } | |
| 226 | ||
| 227 | @Override | |
| 228 | public boolean equals(final Object obj) { | |
| 229 | 0 | if (obj instanceof QualifiedKey) { |
| 230 | 0 | final QualifiedKey otherKey = (QualifiedKey) obj; |
| 231 | 0 | return this.getAbsentType() == otherKey.getAbsentType() |
| 232 | && bothNullOrEqual(this.sectionName, otherKey.sectionName) | |
| 233 | && bothNullOrEqual(this.qualifiedKey, otherKey.qualifiedKey); | |
| 234 | } | |
| 235 | 0 | return false; |
| 236 | } | |
| 237 | ||
| 238 | /** | |
| 239 | * Allow override of the key, particular useful if we're constructing in 2 stages like the offset mechanism | |
| 240 | * | |
| 241 | * @param key the new key | |
| 242 | */ | |
| 243 | private void setKey(final Verse key) { | |
| 244 | 0 | this.qualifiedKey = key; |
| 245 | 0 | this.wholeKey = key.getWhole(); |
| 246 | 0 | } |
| 247 | ||
| 248 | /** | |
| 249 | * Allow override of the key, particular useful if we're constructing in 2 stages like the offset mechanism | |
| 250 | * | |
| 251 | * @param key the new key | |
| 252 | */ | |
| 253 | private void setKey(final VerseRange key) { | |
| 254 | 0 | if (key.getCardinality() == 1) { |
| 255 | 0 | this.qualifiedKey = key.getStart(); |
| 256 | } else { | |
| 257 | 0 | this.qualifiedKey = key; |
| 258 | } | |
| 259 | 0 | this.wholeKey = this.qualifiedKey.getWhole(); |
| 260 | 0 | } |
| 261 | ||
| 262 | /** | |
| 263 | * Determine whether two objects are equal, allowing nulls | |
| 264 | * | |
| 265 | * @param x | |
| 266 | * @param y | |
| 267 | * @return true if both are null or the two are equal | |
| 268 | */ | |
| 269 | private static boolean bothNullOrEqual(Object x, Object y) { | |
| 270 | 0 | return x == y || (x != null && x.equals(y)); |
| 271 | } | |
| 272 | ||
| 273 | private VerseKey qualifiedKey; | |
| 274 | private VerseKey wholeKey; | |
| 275 | private String sectionName; | |
| 276 | private Qualifier absentType; | |
| 277 | ||
| 278 | } |