Coverage Report - org.crosswire.jsword.versification.QualifiedKey
 
Classes in this File Line Coverage Branch Coverage Complexity
QualifiedKey
0%
0/52
0%
0/40
2.095
QualifiedKey$1
N/A
N/A
2.095
QualifiedKey$Qualifier
0%
0/4
N/A
2.095
QualifiedKey$Qualifier$1
0%
0/2
N/A
2.095
QualifiedKey$Qualifier$2
0%
0/2
N/A
2.095
QualifiedKey$Qualifier$3
0%
0/2
0%
0/4
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  
 }