// FBTop.js

//change default loading behavior- ensure search_onload() gets called when the page is loaded
//yes, this is kind of a lazy hack
if(document.addEventListener)
	document.addEventListener("DOMContentLoaded", search_onload, false);
else
	document.onreadystatechange = function() {
		if(document.readyState == "complete") {
			var orig_onload = document.body.onload;
			if(orig_onload != null)
				orig_onload(); //call the original onload function first
			document.body.onload = search_onload;
		}
	}

var documentLoaded = false;

//to align the suggestion box directly under a textbox
var TEXTBOX_OFFSET_X = -4;
var TEXTBOX_OFFSET_Y = 0;

//see bottom of page for definition of SuggestionBox
var AuthorBox = null;
var TitleBox = null;
var KeywordBox = null;

//avoid an infinite loop in firefox when hitting enter in the isbn box
var enterPressed = false;
	
function search_onload() {
	//I found this annoying. Uncomment it if you like.			   
	//document.forms['Search1'].isbn.focus();
	AuthorBox  = new SuggestionBox(document.forms['Search2'].author);
	TitleBox   = new SuggestionBox(document.forms['Search2'].title);
	KeywordBox = new SuggestionBox(document.forms['Search2'].keyword);
	
	if(document.getElementById("isbn").value != "Enter ISBN(s) separated by comma") {
		document.getElementById("isbn").style.color = "#41585e";
		document.getElementById("isbn").style.fontWeight = "bold";
	}
	
	documentLoaded = true;
	
	document.body.onclick = bodyOnClick;
}

function bodyOnClick(e) {
	if(!documentLoaded)
		return;
		
	if(!e)
		e = window.event;
	
	var textbox;
	
	if(AuthorBox.isVisible())
		textbox = document.getElementById("author");
	else if(TitleBox.isVisible())
		textbox = document.getElementById("title");
	else if(KeywordBox.isVisible())
		textbox = document.getElementById("keyword");
	else
		return;

	var result = getSuggestionBox(textbox).checkMouse(e.clientX, e.clientY);
	if(result == 1) {
		textbox.value = getSuggestionBox(textbox).getSelectedEntry(); //fill textbox if a suggestion was clicked
		getSuggestionBox(textbox).hide();
	}
	else if(result == 0)
		getSuggestionBox(textbox).hide(); //hide if the textbox wasn't clicked
}

function isbnFocus() {
	if(document.getElementById("isbn").value == "Enter ISBN(s) separated by comma")
		document.getElementById("isbn").value = "";
	document.getElementById("isbn").style.color = "#41585e";
	document.getElementById("isbn").style.fontWeight = "bold";
}

function isbnBlur() {
	if(document.getElementById("isbn").value == "")
	{
		document.getElementById("isbn").value = "Enter ISBN(s) separated by comma";
		document.getElementById("isbn").style.color = "#bbbbbb";
		document.getElementById("isbn").style.fontWeight = "normal";
	}
}

//this will be called to update the suggestion box after .2 seconds
function onTimeout(textbox) {
	if(textbox == "author")
		return AuthorBox.update(true);
	else if(textbox == "title")
		return TitleBox.update(true);
	else if(textbox == "keyword")
		return KeywordBox.update(true);
}

//could also have used an object to reference this
//There's really no good way to do it without pointers
function getSuggestionBox(textbox) {
	if(textbox.name == "author")
		return AuthorBox;
	else if(textbox.name == "title")
		return TitleBox;
	else if(textbox.name == "keyword")
		return KeywordBox;
}

function showSuggestionBox(textbox) {
	//switch to current suggestion box
	if(textbox.value.length > 0)
		getSuggestionBox(textbox).update(true);
}

//Used in search autosuggestions
function checkKeyUp(textbox, e) {	
	var keyCode;
	
	if(window.event)
		keyCode = window.event.keyCode;
	else if(e.which)
		keyCode = e.which;
		
	//see if it's something to be concerned about, otherwise return
	if((keyCode < 48  && keyCode != 8  && keyCode != 9  && keyCode != 13 &&
						 keyCode != 32 && keyCode != 38 && keyCode != 40 && keyCode != 46) ||
	   (keyCode > 90  && keyCode < 96) ||
	   (keyCode > 111 && keyCode < 186))
			return;
	   
	switch(keyCode)   
	{
		case 13: //enter key is pressed
			if((document.forms['Search1'].isbn.value == "Enter ISBN(s) separated by comma" ||
			   trim(document.forms['Search1'].isbn.value)    == '') &&
			  (trim(document.forms['Search2'].author.value)  != ''  ||
			   trim(document.forms['Search2'].title.value) 	 != ''  ||
			   trim(document.forms['Search2'].keyword.value) != ''  ))
			   //ISBN is empty, but another textbox is not
			   {
			   		if(validateSearch2())
			   			submitSearch2();
			   }
			else //ISBN is not empty, or all texboxes are empty
				document.forms['Search1'].isbn.focus(); //results in calling validate1()
			break;
		case 38: //up arrow is pressed
			if(getSuggestionBox(textbox).isVisible())
				getSuggestionBox(textbox).up();
			break;
		case 40: //down arrow is pressed
			if(getSuggestionBox(textbox).isVisible())
				getSuggestionBox(textbox).down();
			break;
		case 8: //backspace
			if(textbox.value.length > 0)
				getSuggestionBox(textbox).update(false);
			else
				getSuggestionBox(textbox).hide();
			break;
		case 9: //tab
			getSuggestionBox(textbox).hide();
			break;
		default: //show autosuggest control
			getSuggestionBox(textbox).update(false);
			break;
	}
}

//Check to see if enter has been pressed in the ISBN textbox
function checkSubmit(e) {
	if(enterPressed) {
		enterPressed = false;
		return false;
	}
	var key;
	if(window.event)
		key = window.event.keyCode;	
	else if(e.which)
		key = e.which;
	if(key == 13)
	{
		if(validateSearch1()) //enter key is pressed, check submit
			document.forms['Search1'].submit();
		else
			enterPressed = true;
	}
	else if(key == 188 && document.forms['Search1'].isbn.value.charAt(document.forms['Search1'].isbn.value.length - 1) == ",")
		document.forms['Search1'].isbn.value += "\n"; //comma
}

function validateSearch1() {	
	var value;

	// ISBN
	if ( document.forms['Search1'].isbn.value == "Enter ISBN(s) separated by comma" ||
		( trim(document.forms['Search1'].isbn.value) == '' )) {	
		window.alert('Must enter criteria: We suggest ISBN.');
		document.forms['Search1'].isbn.focus();
		return false;
	}

    value = trim(document.forms['Search1'].isbn.value).replace(/[\(\)\.\-]/g, '');
    if (( trim(document.forms['Search1'].isbn.value) != '' )) {

		if (( !validateISBN(value) )) {	
	       	window.alert('ISBN is not valid. Please make sure you have entered a comma between different ISBN numbers.');
	       	document.forms['Search1'].isbn.focus();
	       	document.forms['Search1'].isbn.select();
	       	return false;
        }	

        /*
	    // if ISBN does not start with '978', it must be 10 digits long
	    if ((value.indexOf('978') != 0) && ( value.length != 10 )) {	
		    window.alert('ISBN should be 10 characters.');
		    document.forms['Search1'].isbn.focus();
		    return false;
        }

	    // if ISBN starts with '978', it must be either 10 digits or 13 digits long
	    if ((value.indexOf('978') == 0) && ( value.length != 10 ) && (value.length != 13 )) {	
		    window.alert('ISBN should be either 10 characters or 13 characters.');
	     	document.forms['Search1'].isbn.focus();
	       	return false;
        }
        */		
	}	

	// Strip Characters
	document.forms['Search1'].isbn.value = trim(document.forms['Search1'].isbn.value).replace(/[\(\)\.\-\s]/g, '');
	
	return true;
}	

function validateSearch2() {	
	var value;

	// LastName, Title, Keyword
	if (( trim(document.forms['Search2'].author.value) == '' ) && ( trim(document.forms['Search2'].title.value) == '' ) && ( trim(document.forms['Search2'].keyword.value) == '' )) {	
		window.alert("Must enter criteria: We suggest First Author's Last Name.");
		document.forms['Search2'].author.focus();
		return false;
	}

	// author
	if (( trim(document.forms['Search2'].author.value) != '' ) && ( trim(document.forms['Search2'].author.value).length < 2 )) {	
		window.alert('Author should be at least 2 characters.');
		document.forms['Search2'].author.focus();
		document.forms['Search2'].author.select();
		return false;
	}
	
	// Title
	if (( trim(document.forms['Search2'].title.value) != '' ) && ( trim(document.forms['Search2'].title.value).length < 4 )) {	
		window.alert('Title should be at least 4 characters.');
		document.forms['Search2'].title.focus();
		document.forms['Search2'].title.select();
		return false;
	}
	
	// Keyword
	value = trim(document.forms['Search2'].keyword.value).replace(/^(a\s|an\s|and\s|the\s)|(\sa(?=\s))|(\san(?=\s))|(\sand(?=\s))|(\sthe(?=\s))|(\sa|\san|\sand|\sthe)$/gi, '');
	if (( trim(document.forms['Search2'].keyword.value) != '' ) && ( value.length < 3 )) {	
		window.alert('Keyword should be at least 3 characters.');
		document.forms['Search2'].keyword.focus();
		document.forms['Search2'].keyword.select();
		return false;
	}	

	// Strip Characters
	document.forms['Search2'].keyword.value = trim(document.forms['Search2'].keyword.value).replace(/^(a\s|an\s|and\s|the\s)|(\sa(?=\s))|(\san(?=\s))|(\sand(?=\s))|(\sthe(?=\s))|(\sa|\san|\sand|\sthe)$/gi, '');
	
	return true;
}

function validateISBN(value) {
	if(value.length != 10 && value.length < 13)
		return false;
	
	var isbns = value.split(",");
	
	while(isbns.length > 0) {
		var book = isbns.shift();
		book = book.replace(/\s/gm, ""); //remove all whitespace characters
		if(book.length != 0 && book.length != 10 && book.length != 13)
			return false;
	}
	
	return true;
}

function submitSearch1() {
	document.forms['Search1'].submit();	
}	

function submitSearch2() {
	document.forms['Search2'].submit();	
}	

//
//SuggestionBox definition
//

//Constructor
function SuggestionBox(textbox) {
	this.layer = null;
	this.textbox = textbox;
	this.entries = [];
	this.tempvalue = "";
	this.search = null;
	this.xPos = 0;
	this.yPos = 0;
	this.currentTimeout = null; //for clearing a timeout
	this.lastQuery = "";
	
	this.isVisible = function() { return (this.layer.style.visibility == "visible"); };
	
	//initialize
	if(typeof XMLHttpRequest != "undefined")
		this.search = new XMLHttpRequest();
	else if(typeof ActiveXObject != "undefined") //for older browsers
		this.search = new ActiveXObject("Microsoft.XMLHTTP");
	
	var temp;
	var i;
	
	//layer is a div, holds entries as div's
	this.layer = document.createElement("div");
	this.layer.className = "suggestionbox";
	
	//set layer left position, absolute position on screen
	temp = this.textbox;
	i = 0;
	while(temp.tagName != "BODY") {
		i += temp.offsetLeft;
		temp = temp.offsetParent;
	}
	this.xPos = i + TEXTBOX_OFFSET_X;
	this.layer.style.left = i + TEXTBOX_OFFSET_X;
	
	//set layer top position, absolute position on screen
	temp = this.textbox;
	i = 0;
	while(temp.tagName != "BODY") {
		i += temp.offsetTop;
		temp = temp.offsetParent;
	}
	this.yPos = i + this.textbox.offsetHeight + TEXTBOX_OFFSET_Y;
	this.layer.style.top = i + this.textbox.offsetHeight + TEXTBOX_OFFSET_Y;
}

//Show function
SuggestionBox.prototype.show = function() {
	if(!this.isVisible())
	{
		this.layer.style.visibility = "visible";
		document.body.appendChild(this.layer);
	}
}

//Hide function
SuggestionBox.prototype.hide = function() {
	if(this.isVisible())
	{
		this.layer.style.visibility = "hidden";
		document.body.removeChild(this.layer);
	}
}

SuggestionBox.prototype.getSelectedEntry = function() {
	var index = this.getSelectedIndex();
	return (index >= 0) ? this.entries[index] : this.textbox.value;	
}

//return 0: nothing clicked
//		 1: suggestion box clicked
//		 2: textbox clicked
SuggestionBox.prototype.checkMouse = function(x, y) {
	var result = 0; //this wasn't clicked
	
	if((x >= this.xPos) &&
	   (x <  this.xPos + this.layer.offsetWidth) &&
	   (y >= this.yPos) &&
	   (y <  this.yPos + this.layer.offsetHeight))
	   		result = 1; //suggestion box was clicked
	else if((x >= this.xPos) &&
	   (x <  this.xPos + this.textbox.offsetWidth - TEXTBOX_OFFSET_X) &&
	   (y >= this.yPos - this.textbox.offsetHeight - TEXTBOX_OFFSET_Y) &&
	   (y <  this.yPos))
	   		result = 2; //textbox was clicked
	
	return result;
}

SuggestionBox.prototype.getSelectedIndex = function() {
	var i = 0;
	while(i < this.entries.length && this.layer.childNodes[i].className != "selected")
		i++;
	if(i == this.entries.length)
		i = -1;
	return i;
}

SuggestionBox.prototype.update = function(updateNow) {
	if(updateNow)
		if(this.textbox.value.length > 0)
		{
			if(this.textbox.value != this.lastQuery)
			{	
				//compare query to previous query- saves a trip to the database
				if(this.entries.length < 10 && this.lastQuery !="")
				{		 
					var i=0;
					while(i<this.lastQuery.length &&
						this.lastQuery.charAt(i).toUpperCase() == this.textbox.value.charAt(i).toUpperCase())
							i++;
					if(i == this.lastQuery.length) //textbox starts with lastQuery
					{
						for(i=0; i<this.entries.length; i++) //remove nonmatching entries
							if(this.entries[i].substr(0, this.textbox.value.length).toUpperCase() != this.textbox.value.toUpperCase())
							{
								this.entries.splice(i, 1);
								i--;
							}
						this.updateList();
					}
					else
						this.getSuggestions(this, this.textbox.value.toUpperCase());
				}
				else
					this.getSuggestions(this, this.textbox.value.toUpperCase());
					
				this.lastQuery = this.textbox.value;
			}
			else if(this.entries.length > 0)
				this.show();
		}
		else
		{
			this.hide();
			this.lastQuery = "";
		}
	else {
		clearTimeout(this.currentTimeout);
		//get suggestions in .2 seconds (to avoid fast typers)
		var command = "onTimeout('" + this.textbox.name + "')";
		this.currentTimeout = setTimeout(command, 200);
	}
}

SuggestionBox.prototype.updateList = function() {
	this.tempvalue = "";
	
	//Reset the contents
	this.layer.innerHTML = "";
	
	//if no results, hide and return
	if(this.entries.length == 0) {
		this.hide();
		return;
	}
	
	this.show();
	
	//add suggestions
	for(var i = 0; i < this.entries.length; i++) {
        temp = document.createElement("div");
        temp.appendChild(document.createTextNode(this.entries[i]));
        temp.onmouseover = function() {
		    for(var i=0; i < this.parentNode.childNodes.length; i++)
				if(this.parentNode.childNodes[i].className == "selected")
					this.parentNode.childNodes[i].className = "";
        	this.className = "selected";
        };
        
        this.layer.appendChild(temp);
	}
}

//navigate up
SuggestionBox.prototype.up = function() {
	if(!this.isVisible())
		return;
	if(this.getSelectedIndex() >= 0)
	{
		var index = this.getSelectedIndex();
		this.layer.childNodes[index].className = "";
		if(this.tempvalue == "")
			this.tempvalue = this.textbox.value;
		if(index > 0)
		{
			this.layer.childNodes[index - 1].className = "selected";
			this.textbox.value = this.entries[index - 1];
		}
		else
		{
			this.textbox.value = this.tempvalue;
			this.tempvalue = "";
		}
	}
}

//navigate down
SuggestionBox.prototype.down = function() {
	if(!this.isVisible())
		return;
	if(this.getSelectedIndex() < this.entries.length - 1)
	{
		var index = this.getSelectedIndex();
		if(index >= 0)
		{
			this.layer.childNodes[index].className = "";
			if(this.tempvalue == "")
				this.tempvalue = this.textbox.value;
		}
		else
			this.tempvalue = this.textbox.value;
		this.layer.childNodes[index + 1].className = "selected";
		this.textbox.value = this.entries[index + 1];
	}
}

//get suggestions
// obj: reference to the current suggestion box
// str: string to search for
SuggestionBox.prototype.getSuggestions = function(obj, str) {
	if(this.search == null) //browser too old
		return;
	
	var request = this.search;

	if(request.readyState != 0)
	{
		request.abort(); //end any already pending queries
		this.entries = [];
	}
	
	request.open("get", "/SuggestBooks?" + encodeURIComponent(this.textbox.name)
		+ "=" + encodeURIComponent(str), true);
	//request.setRequestHeader("Cache-Control", "no-store");
	request.onreadystatechange = function() {
		if(request.readyState == 4 && request.status == 200) {
			obj.entries = eval(request.responseText);
			obj.updateList();
		}
	};
    request.send(null);
}
