org.crosswire.jsword.versification

## Class VersificationToKJVMapper

- java.lang.Object
- - org.crosswire.jsword.versification.VersificationToKJVMapper

-     public class VersificationToKJVMapper
      extends Object

  A Versification mapper allows you to a map a given verse to the KJV versification, or unmap it from the KJV versification into your own versification.

  A properties-like file will contain the non-KJV versification as they key, and the KJV versification value as the target value... Duplicate keys are allowed.

  i.e. Gen.1.1=Gen.1.2 means Gen.1.1 in X versification is Gen.1.2 in the KJV versification

  You can specify a range on either side. If a range is present on both sides, they have to have the same number of verses, i.e. verses are mapped verse by verse to each other
  Gen.1.1-Gen.1.2=Gen.1.2-Gen.1.3 means Gen.1.1=Gen.1.2 and Gen.1.2=Gen.1.3
  Note: if the cardinality of the left & KJV sides are different by only one, the algorithm makes the assumption that verse 0 should be disregarded in both ranges.

  Mappings can be specified by offset. In this case, be aware this maps verse 0 as well. So for example:

  Ps.19-Ps.20=-1 means Ps.19.0=Ps.18.50, Ps.19.1=Ps.19.0, Ps.19.2=Ps.19.1, etc.
  It does not make much sense to have an offset for a single verse, so this is not supported. Offsetting for multiple ranges however does, and operates range by range, i.e. each range is calculated separately. Offsetting is somewhat equivalent to specifying ranges, and as a result, the verse 0 behaviour is identical.

  You can use part-mappings. This is important if you want to preserve transformations from one side to another without losing resolution of the verse.

  For example,
  if V1 defines Gen.1.1=Gen.1.1, Gen.1.2=Gen1.1
  if V2 defines Gen.1.1=Gen.1.1, Gen.1.2=Gen.1.1
  then, mapping from V1=>KJV and KJV=>V2 gives you Gen.1.1=>Gen.1.1=>Gen.1.1-Gen.1.2 which is inaccurate if in fact V1(Gen.1.1) actually equals V2(Gen.1.1). So instead, we use a split on the right hand-side:

  For example,
  V1 defines Gen.1.1=Gen1.1!a, Gen.1.2=Gen.1.1!b
  V2 defines Gen.1.1=Gen1.1!a, Gen.1.2=Gen.1.1!b
  then, mapping from V1=>KJV and KJV=>V2 gives you Gen.1.1=>Gen.1.1!a=>Gen.1.1, which is now accurate. A part is a string fragment placed after the end of a key reference. We cannot use # because that is commonly known as a comment in real properties-file. Using a marker, means we can have meaningful part names if we so choose. Parts of ranges are not supported.

  Note: splits should never be seen by a user. The mapping from one versification to another is abstracted such that the user can simply request the mapping between 2 verse (ranges).

  Unmapped verses can be specified by inventing ids, either for whole sections, or verse by verse (this would come in handy if two versifications have the same content, but the KJV doesn't). A section must be preceded with a '?' character indicating that there will be no need to try and look up a reference. Gen.1.1=?NewPassage

  Since not specifying a verse mappings means there is a 1-2-1 unchanged mapping, we need a way of specifying absent verses altogether:
  ?=Gen.1.1
  ?=Gen.1.5
  means that the non-KJV book simply does not contain verses Gen.1.1 and Gen.1.5 and therefore can't be mapped.

  We allow some global flags (one at present):
  !zerosUnmapped : means that any mapping to or from a zero verse

  TODO(CJB): think about whether when returning, we should clone, or make things immutable.

  Author:
    Chris Burrell
  See Also:
    `The GNU Lesser General Public License for details.`

- - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `private Passage` | `absentVerses`
    `private Map<QualifiedKey,Passage>` | `fromKJVMappings`
    `private boolean` | `hasErrors`
    `private static Versification` | `KJV`
    `private static org.slf4j.Logger` | `LOGGER`
    `private Versification` | `nonKjv`
    `private OsisParser` | `osisParser`
    `private Map<VerseKey,List<QualifiedKey>>` | `toKJVMappings`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `VersificationToKJVMapper(Versification nonKjv, FileVersificationMapping mapping)`

  - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `private void` | `add1ToManyMappings(Verse leftHand, QualifiedKey kjvHand)` A simple two way entry between 2 1-1 entries.
    `private void` | `addForwardMappingFromSingleKeyToRange(Verse leftHand, QualifiedKey kjvHand)` Adds a forward mappings from left to KJV.
    `private void` | `addKJVToMapping(QualifiedKey kjvVerses, Verse leftKey)` If leftKey is non-null (i.e.
    `private void` | `addManyToMany(QualifiedKey leftHand, QualifiedKey kjvVerses)` Adds a many to many mapping, mappings all the verses on the left hand side to all the verses on the right hand side.
    `private void` | `addMappings(QualifiedKey leftHand, QualifiedKey kjvVerses)` Adds a 1-Many mapping, by simply listing out all the properties.
    `private void` | `addReverse1ToManyMappings(Verse leftHand, QualifiedKey kjvHand)` Adds the data into the reverse mappings.
    `private Passage` | `createEmptyPassage(Versification versification)` Simplify creation of an empty passage object of the default type, with the required v11n.
    `void` | `dump(PrintStream out)` Dump a debug representation of this map to the output stream.
    `private QualifiedKey` | `getAbsentQualifiedKey(Versification versification, String versesKey)` Deals with absent markers, whether absent in the KJV or absent in the current versification.
    `private QualifiedKey` | `getExistingQualifiedKey(Versification versification, String versesKey)` Deals with real keys found in the versification.
    `private VerseKey` | `getNonEmptyKey(Map<QualifiedKey,Passage> mappings, QualifiedKey key)` Gets a non-empty key list, either new or the one existing in the map already.
    `private <T,S> List<S>` | `getNonEmptyMappings(Map<T,List<S>> mappings, T key)` Gets a non-empty list, either new or the one existing in the map already
    `private QualifiedKey` | `getOffsetQualifiedKey(Versification versification, String versesKey, VerseKey offsetBasis)` Deals with offset markers, indicating a passage is +x or -x verses from this one.
    `private List<QualifiedKey>` | `getQualifiedKeys(Key leftKey)`
    `private QualifiedKey` | `getRange(Versification versification, String versesKey, VerseKey offsetBasis)` Expands a reference to all its verses
    `(package private) boolean` | `hasErrors()` Returns whether we initialised with errors
    `List<QualifiedKey>` | `map(QualifiedKey qualifiedKey)` Maps the full qualified key to its proper equivalent in the KJV.
    `private void` | `processEntry(KeyValuePair entry)`
    `private void` | `processMappings(FileVersificationMapping mappings)` This is the crux of the decoding facility.
    `private void` | `reportCardinalityError(VerseKey leftKeys, VerseKey kjvKeys)` If for some reason cardinalities of keys are different, we report it.
    `private void` | `trace()` Outputs the mappings for debug purposes to the log file.
    `VerseKey` | `unmap(QualifiedKey kjvVerse)` Converts a KJV verse to the target versification, from a qualified key, rather than a real key

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Field Detail

    - #### nonKjv

          private Versification nonKjv

    - #### absentVerses

          private Passage absentVerses

    - #### toKJVMappings

          private Map<VerseKey,List<QualifiedKey>> toKJVMappings

    - #### fromKJVMappings

          private Map<QualifiedKey,Passage> fromKJVMappings

    - #### hasErrors

          private boolean hasErrors

    - #### osisParser

          private OsisParser osisParser

    - #### KJV

          private static final Versification KJV

    - #### LOGGER

          private static final org.slf4j.Logger LOGGER

  - ### Constructor Detail

    - #### VersificationToKJVMapper

          public VersificationToKJVMapper(Versification nonKjv,
                                  FileVersificationMapping mapping)

      Parameters:
        `nonKjv` - a versification that is not the KJV
        `mapping` - the mappings from one versification to another

  - ### Method Detail

    - #### processMappings

          private void processMappings(FileVersificationMapping mappings)

      This is the crux of the decoding facility. The properties are expanded.
      Parameters:
        `mappings` - the input mappings, in a contracted, short-hand form

    - #### processEntry

          private void processEntry(KeyValuePair entry)
                             throws NoSuchKeyException

      Throws:
        `NoSuchKeyException`

    - #### addMappings

          private void addMappings(QualifiedKey leftHand,
                         QualifiedKey kjvVerses)
                            throws NoSuchVerseException

      Adds a 1-Many mapping, by simply listing out all the properties. There is probably a better way for storing this, perhaps in a tree - but for simplicity, we're going to list them out.
      Parameters:
        `leftHand` - the left hand side operand
        `kjvVerses` - the verses that are mapped by the left hand side
      Throws:
        `NoSuchVerseException`

    - #### addManyToMany

          private void addManyToMany(QualifiedKey leftHand,
                           QualifiedKey kjvVerses)

      Adds a many to many mapping, mappings all the verses on the left hand side to all the verses on the right hand side. We support 2 types: Many-to-1 and Many-to-Many.
      Parameters:
        `leftHand` - is assumed to be many
        `kjvVerses` - could be 1 or many

    - #### reportCardinalityError

          private void reportCardinalityError(VerseKey leftKeys,
                                    VerseKey kjvKeys)

      If for some reason cardinalities of keys are different, we report it.
      Parameters:
        `leftKeys` - the left hand key
        `kjvKeys` - the kjv qualified key

    - #### addKJVToMapping

          private void addKJVToMapping(QualifiedKey kjvVerses,
                             Verse leftKey)

      If leftKey is non-null (i.e. not attached to a simple specifier, then adds to the kjvTo mappings
      Parameters:
        `kjvVerses` - the kjv verses
        `leftKey` - the left-hand key, possibly null.

    - #### add1ToManyMappings

          private void add1ToManyMappings(Verse leftHand,
                                QualifiedKey kjvHand)
                                   throws NoSuchVerseException

      A simple two way entry between 2 1-1 entries.
      Parameters:
        `leftHand` - the verse on the left side, left is assumed to be 1 verse only
        `kjvHand` - the KJV reference
      Throws:
        `NoSuchVerseException`

    - #### addReverse1ToManyMappings

          private void addReverse1ToManyMappings(Verse leftHand,
                                       QualifiedKey kjvHand)

      Adds the data into the reverse mappings. Caters for 1-2-1 and 1-2-Many mappings
      Parameters:
        `leftHand` - the reference of the left hand reference
        `kjvHand` - the kjv reference/key, qualified with the part

    - #### addForwardMappingFromSingleKeyToRange

          private void addForwardMappingFromSingleKeyToRange(Verse leftHand,
                                                   QualifiedKey kjvHand)

      Adds a forward mappings from left to KJV.
      Parameters:
        `leftHand` - the left hand reference (corresponding to a non-kjv versification)
        `kjvHand` - the kjv reference (with part if applicable).

    - #### getNonEmptyKey

          private VerseKey getNonEmptyKey(Map<QualifiedKey,Passage> mappings,
                                QualifiedKey key)

      Gets a non-empty key list, either new or the one existing in the map already.
      Parameters:
        `mappings` - the map from key to list of values
        `key` - the key
      Returns:
        the non-empty mappings list

    - #### getNonEmptyMappings

          private <T,S> List<S> getNonEmptyMappings(Map<T,List<S>> mappings,
                                          T key)

      Gets a non-empty list, either new or the one existing in the map already
      Type Parameters:
        `T` - the type of the key
        `S` - the type of the value
      Parameters:
        `mappings` - the map from key to list of values
        `key` - the key
      Returns:
        the separate list of verses

    - #### getRange

          private QualifiedKey getRange(Versification versification,
                              String versesKey,
                              VerseKey offsetBasis)
                                 throws NoSuchKeyException

      Expands a reference to all its verses
      Parameters:
        `versesKey` - the verses
      Returns:
        the separate list of verses
      Throws:
        `NoSuchKeyException`

    - #### getOffsetQualifiedKey

          private QualifiedKey getOffsetQualifiedKey(Versification versification,
                                           String versesKey,
                                           VerseKey offsetBasis)
                                              throws NoSuchKeyException

      Deals with offset markers, indicating a passage is +x or -x verses from this one.
      Parameters:
        `versification` - the versification of the passed in key
        `versesKey` - the text of the reference we are trying to parse
      Returns:
        the qualified key representing this
      Throws:
        `NoSuchKeyException`

    - #### getExistingQualifiedKey

          private QualifiedKey getExistingQualifiedKey(Versification versification,
                                             String versesKey)

      Deals with real keys found in the versification.
      Parameters:
        `versification` - the versification of the passed in key
        `versesKey` - the text of the reference we are trying to parse
      Returns:
        the qualified key representing this

    - #### getAbsentQualifiedKey

          private QualifiedKey getAbsentQualifiedKey(Versification versification,
                                           String versesKey)

      Deals with absent markers, whether absent in the KJV or absent in the current versification.
      Parameters:
        `versification` - the versification of the passed in key
        `versesKey` - the text of the reference we are trying to parse
      Returns:
        the qualified key representing this

    - #### getQualifiedKeys

          private List<QualifiedKey> getQualifiedKeys(Key leftKey)

      Returns:
        the qualified keys associated with the input key.

    - #### map

          public List<QualifiedKey> map(QualifiedKey qualifiedKey)

      Maps the full qualified key to its proper equivalent in the KJV.
      Parameters:
        `qualifiedKey` - the qualified key
      Returns:
        the list of matching qualified keys in the KJV versification.

    - #### unmap

          public VerseKey unmap(QualifiedKey kjvVerse)

      Converts a KJV verse to the target versification, from a qualified key, rather than a real key
      Parameters:
        `kjvVerse` - the verse from the KJV
      Returns:
        the key in the left-hand versification

    - #### trace

          private void trace()

      Outputs the mappings for debug purposes to the log file.

    - #### dump

          public void dump(PrintStream out)

      Dump a debug representation of this map to the output stream.
      Parameters:
        `out` -

    - #### hasErrors

          boolean hasErrors()

      Returns whether we initialised with errors

    - #### createEmptyPassage

          private Passage createEmptyPassage(Versification versification)

      Simplify creation of an empty passage object of the default type, with the required v11n.
      Parameters:
        `versification` - required v11n for new Passage
      Returns:
        empty Passage