// ===================================================================
/** 
  @fileoverview Class for handling data of one Bible reference
  (reference to sequence of verses in one chapter)
  
  @requires Bible20.Bible.BookNames The indexing of bible book names (for #compareTo).

  @author Helmut Steeb hs2009@bible.net (insert current year)
  @version $Id: BibleRef.js 3495 2009-05-14 17:42:01Z helmut $
**/
var Bible20;
if (!Bible20) {
  Bible20 = {};
}
else if (typeof Bible20 != "object") {
  throw new Error("Bible20 already exists and is not an object");
}

if (!Bible20.Bible) {
  Bible20.Bible = {};
}
else if (typeof Bible20.Bible != "object") {
  throw new Error("Bible20.Bible already exists and is not an object");
}

/**
  @class Bible20.Bible.BibleRef
  encapsulates a bible verse range within one chapter of a bible book.
  It is relative to a certain bible edition.

  @constructor
  Constructs a new Bible20.Bible.BibleRef object.
  @param book is the "canonical" latin book name, see #NAMES
  @param chapterNumber defaults to 1 if not given.
  @param verseNumberStart is the first verse of the range.
  @param verseNumberEnd is the last valid verseNumber (default: verseNumberStart).
  E.g. new Bible20.Bible.BibleRef("L", 1, 10, 13) denotes Luke 1, 10-13.
  Fails if verseNumberEnd $verseNumberStart.

  @requires Bible20.Bible.BookNames The indexing of bible book names (for #compareTo).
**/
Bible20.Bible.BibleRef = function(book, chapterNumber, verseNumberStart, verseNumberEnd)
{
  try {
    if (verseNumberEnd && verseNumberStart > verseNumberEnd) {
      throw new Error("verseNumberStart=" + verseNumberStart + " > verseNumberEnd=" + verseNumberEnd);
    }
    this._book = book;
    this._chapterNumber = chapterNumber || 1;
    this._verseNumberStart = verseNumberStart;
    this._verseNumberEnd = verseNumberEnd || verseNumberStart;
  }
  catch (e) {
    alert("Bible20.Bible.BibleRef: " + e);
  }
}

/**
Bible20.Bible.BibleRef.splitParolID(parolID)
returns false for invalid parolID, 
otherwise array A with
  A[0]: abbreviated book name
  A[1]: chapter number
  A[2]: verse number, or start number of verse range
  A[3]: false, or end number of verse range
The numbers are returned as Number, not String.
**/
Bible20.Bible.BibleRef.splitParolID = function(parolID)
{
  var result = parolID.match(/^(\d?[A-Za-z]+)([0-9]+)v([0-9]+)(?:-([0-9]+))?(?:_\w+)?$/);
  return result ? [result[1], Number(result[2]), Number(result[3]), Number(result[4])] : null;
}

Bible20.Bible.BibleRef.prototype.getBook = function()
{
  return this._book;
}

Bible20.Bible.BibleRef.prototype.getChapterNumber = function()
{
  return this._chapterNumber;
}

Bible20.Bible.BibleRef.prototype.getVerseNumberStart = function()
{
  return this._verseNumberStart;
}

Bible20.Bible.BibleRef.prototype.getVerseNumberEnd = function()
{
  return this._verseNumberEnd;
}

Bible20.Bible.BibleRef.prototype.fromParolID = function(parolID)
{
  var res = Bible20.Bible.BibleRef.splitParolID(parolID);
  if (res) {
    this._book = res[0];
    this._chapterNumber = res[1];
    this._verseNumberStart = res[2];
    this._verseNumberEnd = res[3] || res[2];
  }
  return this;
}

Bible20.Bible.BibleRef.prototype.toString = function()
{
  var s = this._book + this._chapterNumber + "v" + this._verseNumberStart;
  if (this._verseNumberEnd > this._verseNumberStart) {
    s += "-" + this._verseNumberEnd;
  }
  return s;
}

Bible20.Bible.BibleRef.prototype.equals = function(aBibleRef2)
{
  return this._book == aBibleRef2.getBook()
    && this._chapterNumber == aBibleRef2.getChapterNumber()
    && this._verseNumberStart == aBibleRef2.getVerseNumberStart()
    && this._verseNumberEnd == aBibleRef2.getVerseNumberEnd();
}

/**
Compare two BibleRefs
@param aBibleRef2
@return <0 if this < aBibleRef2, ==0 if this equals aBibleRef2, >0 if this > aBibleRef2
**/
Bible20.Bible.BibleRef.prototype.compareTo = function(aBibleRef2)
{
  // Flanagan, p. 166
  if (!aBibleRef2) {
    throw new Error("bad argument to Bible20.Bible.BibleRef.compareTo()");
  }
  var getBookIndex = Bible20.Bible.BookNames.getBookIndex;
  return (getBookIndex(this._book) - getBookIndex(aBibleRef2.getBook()))
    || this._chapterNumber - aBibleRef2.getChapterNumber()
    || this._verseNumberStart - aBibleRef2.getVerseNumberStart()
    || this._verseNumberEnd - aBibleRef2.getVerseNumberEnd();
}

/**
Static function to compare two BibleRefs, useful for sorting,
e.g. ArrayOfBibleRefs.sort(Bible20.Bible.BibleRef.compare)
@param aBibleRef1
@param aBibleRef2
@return <0, ==0, >0, see #compareTo
**/
Bible20.Bible.BibleRef.compare = function(aBibleRef1, aBibleRef2)
{
  // Flanagan, p. 166
  return aBibleRef1.compareTo(aBibleRef2);
}

Bible20.Bible.BibleRef.prototype.contains = function(chapterNumber, verseNumber)
{
  return this._chapterNumber == chapterNumber
    && this._verseNumberStart <= verseNumber
    && verseNumber <= this._verseNumberEnd;
}

Bible20.Bible.BibleRef.prototype.doesIntersect = function(aBibleRef2)
{
  return this._chapterNumber == aBibleRef2.getChapterNumber()
    && (this._verseNumberStart <= aBibleRef2.getVerseNumberEnd())
    && (this._verseNumberEnd   >= aBibleRef2.getVerseNumberStart());
}


