
/**
 * Defines a reference
 * At first you have to create an instance of Reference 
 * array of BookData should be passed to the constructor.
 * Next step is to call the parse method.
 */
function Reference(books){
	this.books = books;	
}

Reference.prototype.referenceSeparator = new RegExp("[\r\n;,.]+");

Reference.prototype.bookSeparator = " ";

Reference.prototype.chapterVerseSeparator = new RegExp(":");

Reference.prototype.rangeSeparator = new RegExp("\-");

Reference.prototype.charSequence = "[a-z0-9 ]*";

Reference.prototype.anyChar = new RegExp("[a-zA-Z]+");

Reference.prototype.space = new RegExp("[ ]");

Reference.prototype.splitReferences = function (references){
	this.separators = references.match(new RegExp(this.referenceSeparator.source,"g"));
	return references.split(this.referenceSeparator);
}

Reference.prototype.normalizeSpaces = function(str){
	str = this.trim(str);
	return str.replace(new RegExp("[ ]{2,}","g")," ");
}

Reference.prototype.trim = function(str){
	return str.replace(new RegExp("(^([ ]+))|(([ ]+)$)","g"),"");
}

/*Reference.prototype.trim = function(str){
	var strs = str.split(this.space);
	var result = null;
	for (i in strs){
		if (strs[i] && strs[i].length >0){
			result = (result) ? result+strs[i] : strs[i];
		}else if (result) result +=" ";
	}
	return result;
}*/

/**
 * Parses a book reference.
 * Return true if the reference is correct.
 * Fills the following fields:
 *    bookData - The BookData instance
 *	  chapterFrom - optional, The ChapterData instance;
 *	  chapterTo - optional, The ChapterData instance;
 *	  verseNoFrom - optional, integer type defines number of the verse (starts form 1);
 *	  verseNoTo - optional, integer type defines number of the verse (starts form 1);
 */
Reference.prototype.parse = function (reference,count){
	this.bookData = null;
	this.chapterFrom = null;
	this.chapterTo = null;
	this.verseNoFrom = null;
	this.verseNoTo = null;

	reference = this.replaceRomanNumbers(reference)
	var bookName = reference;
	this.count = count;
	var chapterVerse = null;
	var i = reference.lastIndexOf(this.bookSeparator);
	if (i>0){
		var chv = reference.substring(i+this.bookSeparator.length);
		if (!chv.match(this.anyChar)){
			bookName = reference.substring(0,i);
			chapterVerse = chv;
		}
	}
	if (!this.parseBook(bookName)){
		if (this.prevBookData && !chapterVerse && !bookName.match(this.anyChar)){
			chapterVerse = bookName;
			this.bookData = this.prevBookData;
		}else{
			return false;
		}
	}
	if (chapterVerse){
		if (!this.parseChapterVerse(chapterVerse)) return false;
	}
	
	this.prevBookData = this.bookData;
	this.prevChapterFrom = this.chapterFrom;
	this.prevChapterTo = this.chapterTo;
	this.prevVerseNoFrom = this.verseNoFrom;
	this.prevVerseNoTo = this.verseNoTo;	
	return true;
}

/**
 * Return true if the Reference presents a range of verses or chapters
 */
Reference.prototype.isRange = function(){
	return (this.chapterTo!=null || this.verseNoTo!=null); 
}

Reference.prototype.replaceRomanNumbers = function(reference){
	var romanNumbers = getRomanNumbers();
	for (rExp in romanNumbers){
		var regExp = new RegExp(rExp, "g");
		reference = reference.replace(regExp,romanNumbers[rExp]);	
	}
	return reference;
}

Reference.prototype.getVerseFromId = function(){
	if (this.chapterFrom ==null || this.verseNoFrom) return null;
	return (this.chapterFrom.firstVerseId+this.verseNoFrom-1); 
}

Reference.prototype.getVerseToId = function(){
	var ch = this.chapterTo ? this.chapterTo : this.chapterFrom
	if (ch ==null  || this.verseToFrom) return null;
	return (ch.firstVerseId+this.verseNoFrom-1); 
}

Reference.prototype.parseBook = function (bookPart){
	var pattern = "^";
	var part = this.normalizeSpaces(bookPart);
	for(var i=0; i<part.length; i++){
		pattern+=part.substring(i,i+1).toLowerCase();
		pattern+=this.charSequence;
	}

	try{
		var bd = null;
		var bdrate = 100;
		
		var regExp = new RegExp(pattern);
		for (i in this.books){
			var name = this.books[i].text.toLowerCase();
			var rate = this.mathesRate(name,regExp,part.length)
			if (this.betterCandidate(rate,bdrate,bd,name,part)){
				bdrate = rate;
				bd = this.books[i];
			}
		}
		if (bd){
			this.bookData = bd;
			return true;
		}
	}catch(e){
//		alert("Parse Book Name Exception - "+e)
	}
	delete pattern;
	return false;
}

Reference.prototype.mathesRate = function (name,regexp,min){
	if (!name.match(regexp)) return null;
	for (var i=min; i<name.length-1; i++){
		var s = name.substring(0,i)
		if (s.match(regexp)){
			return i;
		}
	}
	return name.length;
}

Reference.prototype.betterCandidate = function(rate,bdrate,currentBD,candName,userInput){
	if (!rate) return false;
	if (!currentBD) return (rate < bdrate);
	
	var f1 = mathesBookName(currentBD.text.toLowerCase(),userInput);
	var f2 = mathesBookName(candName,userInput);
	
	if ((f1 && f2) || (!f1 && !f2)) return (rate < bdrate);
	
	return f2;

	function mathesBookName(name,userInput){
		if (userInput.length > name.length) return false;
//		alert("name.substring(0,userInput.length) = " + name.substring(0,userInput.length) + "\nuserInput = " + userInput)
		return (name.substring(0,userInput.length) == userInput.toLowerCase());
	}
}

Reference.prototype.parseChapterVerse = function(numbersPart){
	var parts = numbersPart.split(this.rangeSeparator);
	if (parts.length <1) return false
	if (!this.parseFrom(parts[0])) return false
	if (parts.length >1) return this.parseTo(parts[1])
	return true
}

Reference.prototype.parseFrom = function (fromPart){
	var parts = fromPart.split(this.chapterVerseSeparator);
	if (parts.length <1) return false
	//alert('parts.length = ' + parts.length + "\nthis.prevVerseNoFrom = " + this.prevVerseNoFrom + "\nthis.count = " + this.count)
	if (parts.length==1 && this.prevVerseNoFrom && this.count>0 && this.separators[this.count-1] && this.separators[this.count-1] == ","){
		this.chapterFrom = this.prevChapterTo>0?this.prevChapterTo:this.prevChapterFrom;
		this.verseNoFrom = this.parseChapterVerseNo(this.chapterFrom,parts[0]);
		if (!this.verseNoFrom) return false;		
	}else{
		this.chapterFrom = this.parseChapter(parts[0]);
		if (!this.chapterFrom) return false;
		if (parts.length >1){
			this.verseNoFrom = this.parseChapterVerseNo(this.chapterFrom,parts[1]);
			if (!this.verseNoFrom) return false;
		}
	}
	return true;
}

Reference.prototype.parseTo = function (toPart){
	var parts = toPart.split(this.chapterVerseSeparator);
	if (parts.length < 1 ) return false;
	if (this.verseNoFrom && parts.length == 1){
		this.verseNoTo = this.parseChapterVerseNo(this.chapterFrom,parts[0])
		return (this.verseNoTo!=null && parseInt(this.verseNoFrom)<=parseInt(this.verseNoTo));
	}else{
		this.chapterTo = this.parseChapter(parts[0]);
		if (!this.chapterTo) return false;
		for (i in this.bookData.dataArray){
			if (this.chapterFrom == this.bookData.dataArray[i]) break;
			if (this.chapterTo == this.bookData.dataArray[i])	return false;
		}
		if (parts.length >1){
			this.verseNoTo = this.parseChapterVerseNo(this.chapterTo,parts[1]);
			if (this.verseNoTo==null) return false;
			if (this.chapterFrom == this.chapterTo)
				return ( parseInt(this.verseNoFrom)<=parseInt(this.verseNoTo) );
		}
	}
	return true;
}


Reference.prototype.parseChapter = function (chapterName){
	for (i in this.bookData.dataArray){
		if (chapterName == this.bookData.dataArray[i].text){
			return this.bookData.dataArray[i];
		}
	}
	return false;
}

Reference.prototype.parseChapterVerseNo = function (chapterData,verse){
	try{
		var number = parseInt(verse);
		if (number>0 && chapterData.verseNumber>=number) return number
	}catch(e){
//		alert(e);
	}
	return null;
}



// #############################################################################
// Functions
// #########################################

function provideNumberSeparator(name){
	try{		
	  var regexp = new RegExp("[0-9][ ]+[0-9]");
	  var s = name.match(regexp);
	  var news = s[0].replace(new RegExp("[ ]+"),":");
	  return name.replace(new RegExp(s[0]),news);
	}catch(e){
//		alert(e);
	}
	return name;	  
}

function getRomanNumbers(){
	var r = new Array();
	r["[iI]{2,}[ ]+[sS]"] = "2 S";
	r["[iI][ ]+[sS]"] = "1 S";
	r["[iI]{2,}[ ]+[kK]"] = "2 K";
	r["[iI][ ]+[kK]"] = "1 K";
	r["[iI]{2,}[ ]+[cC][hH]"] = "2 Ch";
	r["[iI][ ]+[cC][hH]"] = "1 Ch";
	r["[iI]{2,}[ ]+[cC]"] = "2 C";
	r["[iI][ ]+[cC]"] = "1 C";
	r["[iI]{2,}[ ]+[tT][hH]"] = "2 Th";
	r["[iI][ ]+[tT][hH]"] = "1 Th";
	r["[iI]{2,}[ ]+[tT]"] = "2 T";
	r["[iI][ ]+[tT]"] = "1 T";
	r["[iI]{2,}[ ]+[pP]"] = "2 P";
	r["[iI][ ]+[pP]"] = "1 P";
	r["[iI]{3,}[ ]+[jJ]"] = "3 J";
	r["[iI]{2}[ ]+[jJ]"] = "2 J";
	r["[iI][ ]+[jJ]"] = "1 J";
	return r;
}

function fillBooksSelect(bookSelect, defaultBook, dataArray){
	for (i in dataArray){
		var option = dataArray[i].buildOptionElement(bookSelect);
		if (dataArray[i].text == defaultBook) {
			option.selected = true;
		}
	}
}

function changeOptions(parentSelect, idAsValue, selectLast){
	// clear select element
	var orphanSelect = parentSelect.orphan;
	while(orphanSelect.childNodes.length > 0){
		orphanSelect.removeChild(orphanSelect.firstChild);
	}
	var optionSelected = parentSelect.options[parentSelect.selectedIndex];
	var dataArray = optionSelected.optionData.getDataArray();
	//var dataArray = optionSelected.dataArray? optionSelected.dataArray : optionSelected.optionData.dataArray;
	if (dataArray){
		for (var i = 0; i < dataArray.length; i++)
			dataArray[i].buildOptionElement(orphanSelect, idAsValue);
		if (orphanSelect.orphan) {
			changeOptions(orphanSelect, idAsValue, selectLast);
		}
		orphanSelect.className = "inherit_visibility_select";
	}
	if (selectLast && !orphanSelect.orphan){
		orphanSelect.options[orphanSelect.options.length-1].selected = true;
	}	
}

function initChooser(bookselectid,chapterselectid,verseselectid,selectedbooktitle,useVerseId,selectLast,defaultVerse){
	var bookSelect = document.getElementById(bookselectid);
	if (!bookSelect.orphan){
		bookSelect.orphan = document.getElementById(chapterselectid);
		var verseSelect = document.getElementById(verseselectid);
		document.getElementById(chapterselectid).orphan = verseSelect;
		fillBooksSelect(bookSelect, selectedbooktitle, bookData)
		changeOptions(bookSelect,useVerseId,selectLast);
		
		if (defaultVerse) verseSelect.value = defaultVerse;
	}
}