/**
 * functions needed in TypeAheadSearch
 * 
 * @author sol
 */

// the minimum length of searchString defined in shop-config
var typeAheadMinLength; 
//the configured fields from shop-config
var typeAheadFields; 
//table to copy, better performance than creating a new one
var typeAheadSuggestionTable; 
//tr to copy as suggestion, better performance than creating new trs
var typeAheadSuggestionRow;
//td to copy as suggestion cell, better performance than creating new tds
var typeAheadSuggestionCell;
//hiddenField to store the article link
var typeAheadSuggestionLink;



/*******************************************************************************
 * 
 * Init function to initialize the TypeAhead functionality.
 * 
 ******************************************************************************/
function typeAheadInit() {
	TypeAheadFind.getTypeAheadFields(typeAheadFieldsInit);
	TypeAheadFind.getTypeAheadMinLength(typeAheadMinLengthInit);
	// table
	typeAheadSuggestionTable = document.createElement("table");
	// tr
	typeAheadSuggestionRow = document.createElement("tr");
	// addeventlistener doesn't work, if you later clone the node, the listener
	// is removed
	typeAheadSuggestionRow.setAttribute("onmouseover",
			"typeAheadSelectSuggestionByMouseOver(this,event)");
	typeAheadSuggestionRow.setAttribute("onclick",
			"typeAheadSelectedSuggestion(this,event)");
	// td
	typeAheadSuggestionCell = document.createElement("td");
	
	// direct link to article
	typeAheadSuggestionLink = document.createElement("a");
	typeAheadSuggestionLink.setAttribute("class", "typeAheadSuggestionLink");
	
}

/*******************************************************************************
 * 
 * Init function to set the configured fields. param: fields returned from
 * server
 * 
 ******************************************************************************/
function typeAheadFieldsInit(fields) {
	typeAheadFields = fields;
}

/*******************************************************************************
 * 
 * Init function to set the configured min length. param: min length returned
 * from server
 * 
 ******************************************************************************/
function typeAheadMinLengthInit(length) {
	typeAheadMinLength = length;
}

/*******************************************************************************
 * 
 * Test function to alert the returned text. param: text returned from server
 * 
 ******************************************************************************/
function testAlert(text) {
	alert(text);
}

/*******************************************************************************
 * 
 * OnKeyUp listener set on the input field. param: element (input field) / event
 * 
 ******************************************************************************/
function typeAheadKeyUp(element, event) {
	var typeAheadForm = element.form;
	var keyPressed = event.keyCode;

	switch (keyPressed) {
	case 13: // enter
		typeAheadEnterPress(element, event);
		break;
	case 32: // space
	case 17: // ctrl
	case 16: // shift
	case 37: // left down
	case 39: // right down
		break;
	case 40: // arrow down
		typeAheadSelectSuggestionByKey(element, event, 1);
		break;
	case 38: // arrow up
		typeAheadSelectSuggestionByKey(element, event, -1);
		break;
	case 8: // backspace
	case 46: // delete
	default:
		typeAheadSearch(element, event);
		break;
	}
}

/*******************************************************************************
 * 
 * Decides what to do if enter is pressed, depends on actual state param:
 * element (input field) / event
 * 
 ******************************************************************************/
function typeAheadEnterPress(element, event) {
	var typeAheadForm = element.form;
	var typeAheadSelectionIndex = getElementsByClassName(
			"typeAheadSelectionIndex", typeAheadForm)[0];
	var index = Number(typeAheadSelectionIndex.value);

	if (index == 0) {
		var typeAheadSubmit = getElementsByClassName("typeAheadSubmit",
				typeAheadForm)[0];
		// uses click() to make sure that all listeners are called
		typeAheadSubmit.click();
	} else {
		// get the selected row
		var typeAheadSuggestions = getElementsByClassName(
				"typeAheadSuggestions", typeAheadForm)[0];
		var table = getAllChildElementsByElement(typeAheadSuggestions, "TABLE")[0];
		// the table[0] is needed because an array is returned
        var selectedTr =  $(table).find("tr:nth-child(" + index + ")")[0];

		typeAheadSelectedSuggestion(selectedTr, event);
	}
}

/*******************************************************************************
 * 
 * Access the selected suggestion param: selectedTr / event
 * 
 ******************************************************************************/
function typeAheadSelectedSuggestion(selectedTr, event) {
	var typeAheadSuggestionLink = getElementsByClassName(
			"typeAheadSuggestionLink", selectedTr)[0];
	typeAheadSuggestionLink.click();
}

/*******************************************************************************
 * 
 * Selects one of the suggestions by pressing arrow up or down param: element
 * (input field) / event / direction (1=down,-1=up)
 * 
 ******************************************************************************/
function typeAheadSelectSuggestionByKey(element, event, direction) {
	var typeAheadForm = element.form;
	var typeAheadSelectionIndex = getElementsByClassName(
			"typeAheadSelectionIndex", typeAheadForm)[0];
	var typeAheadSuggestions = getElementsByClassName("typeAheadSuggestions",
			typeAheadForm)[0];
	var table = getAllChildElementsByElement(typeAheadSuggestions, "TABLE")[0];
	// the table[0] is needed because an array is returned

	// ie counts the tbody also as a level
	if (isBrowserIE()) {
		var trs = getAllChildElementsByElement(table.firstChild, "TR");
	}
	// ff doesn't
	else {
		var trs = getAllChildElementsByElement(table, "TR");
	}

	var index = Number(typeAheadSelectionIndex.value);

	if (direction == 1 && trs.length > index || direction == -1 && index != 0) {
		typeAheadSelectionIndex.value = index + direction;
	}
	typeAheadHighlightSuggestion(element, event);
}

/*******************************************************************************
 * 
 * Selects one of the suggestions by mouseover param: row / event
 * 
 ******************************************************************************/
function typeAheadSelectSuggestionByMouseOver(element, event) {
	var typeAheadForm = getParentElementByNodeName(element, "FORM");
	var typeAheadSelectionIndex = getElementsByClassName(
			"typeAheadSelectionIndex", typeAheadForm)[0];

	var actRow = element;
	var index = 1;
	// count the index of this tr element
	while (actRow.previousSibling != null) {
		index++;
		actRow = actRow.previousSibling;
	}

	// set the current index
	typeAheadSelectionIndex.value = index;

	// call the highlight function
	typeAheadHighlightSuggestion(element, event);
}

/*******************************************************************************
 * 
 * Highlights the selected suggestion param: element (any element in the form) /
 * event
 * 
 ******************************************************************************/
function typeAheadHighlightSuggestion(element, event) {
	var typeAheadForm = getParentElementByNodeName(element, "FORM");
	var typeAheadSelectionIndex = getElementsByClassName(
			"typeAheadSelectionIndex", typeAheadForm)[0];
	var typeAheadSuggestions = getElementsByClassName("typeAheadSuggestions",
			typeAheadForm)[0];
	var table = getAllChildElementsByElement(typeAheadSuggestions, "TABLE")[0];

	// ie counts the tbody also as a level
	if (isBrowserIE()) {
		var trs = getAllChildElementsByElement(table.firstChild, "TR");
	}
	// ff doesn't
	else {
		var trs = getAllChildElementsByElement(table, "TR");
	}

	// create a number from typeAheadSelectionIndex
	var index = Number(typeAheadSelectionIndex.value);

	typeAheadRemoveHighlighting(table, event);
	// if zero is set, no suggestion is selected
	if (index >= 1) {
		trs[index - 1].className = "highlight";
	}
}

/*******************************************************************************
 * 
 * Removes the highlighting from suggestions param: table (suggestionTable) /
 * event
 * 
 ******************************************************************************/
function typeAheadRemoveHighlighting(table, event) {
	var highlightEl = getElementsByClassName("highlight", table);

	// loop over all returned trs, it's more secure than to
	// assume that only one is selected
	for ( var i = 0; i < highlightEl.length; i++) {
		highlightEl[i].className = "";
	}
}

/*******************************************************************************
 * 
 * Deselect the highlighted suggestion param: table (suggestionTable) / event
 * 
 ******************************************************************************/
function typeAheadDeselectSuggestion(table, event) {
	if (table.nodeName == "TABLE") {
		var typeAheadForm = getParentElementByNodeName(table, "FORM");
		var typeAheadSelectionIndex = getElementsByClassName(
				"typeAheadSelectionIndex", typeAheadForm)[0];
		typeAheadRemoveHighlighting(table, event)
		typeAheadSelectionIndex.value = "0";
	}
}

/*******************************************************************************
 * 
 * Perform the server call to search for suggestions param: element / event
 * 
 ******************************************************************************/
function typeAheadSearch(element, event) {
	// typeAheadMinLength is defined in shop-config
	if (element.value.length > typeAheadMinLength) {
		// this closure is needed because in the target function
		// the actual element is required to place the result and
		// it's not possible to send the element in an other way.
		// the actual development version of dwr could handle this
		var callbackProxy = function(salesItems) {
			typeAheadDisplaySalesItems(salesItems, element);
		};
		TypeAheadFind.getTypeAheadHits(element.value, callbackProxy);
	} else {
		// if there are less or equals chars then configured
		// hide the suggestion layer
		typeAheadHideSuggestions(element, event);
	}
}

/*******************************************************************************
 * 
 * OnBlur listener set on the input field. The timeout is needed becouse
 * otherwise the onclick listener at the suggestion is to late. param: element
 * (input field) / event
 * 
 ******************************************************************************/
function typeAheadBlur(element, event) {
	// this closure is needed, because of the two params
	window.setTimeout( function() {
		typeAheadHideSuggestionsTimeout(element, event)
	}, 300);
}

/*******************************************************************************
 * 
 * Hides the suggestion layer if the focus leaves the input field. Called with a
 * timeout. param: element (input field) / event
 * 
 ******************************************************************************/
function typeAheadHideSuggestionsTimeout(element, event) {
	var typeAheadForm = element.form;
	var suggestions = getElementsByClassName("typeAheadSuggestions",
			typeAheadForm)[0];
	var table = suggestions.firstChild;
	typeAheadHideSuggestions(element, event);
	typeAheadDeselectSuggestion(table, event);
}

/*******************************************************************************
 * 
 * Hide suggestions layer param: element (input field) / event
 * 
 ******************************************************************************/
function typeAheadHideSuggestions(element, event) {
	var typeAheadForm = element.form;
	var typeAheadSuggestions = getElementsByClassName("typeAheadSuggestions",
			typeAheadForm)[0];
//	typeAheadSuggestions.style.display = "none";
	getElementsByClassName("autoCompletion",typeAheadForm)[0].style.display = "none";// TODO: reenable
}


/*******************************************************************************
 * 
 * The server calls this function and inserts the response objects in the first
 * param. This function updates the suggestion table. param: salesItems (from
 * server) / element (input field)
 * 
 ******************************************************************************/
function typeAheadDisplaySalesItems(salesItems, element) {
	var table = typeAheadSuggestionTable.cloneNode(false);
	table.setAttribute("id", "typeAheadSuggestionTable");

	// split all tokens to prepare regex for highlighting
	// the exact matches
    var cleanValue = element.value.replace(/[[\*\\\?\+\(\)\*]/g, '');
	var tokens = cleanValue.split(" ");
	var regexPrep = "(";
	for ( var l = 0; l < tokens.length; l++) {
		regexPrep += tokens[l];
		if (l < tokens.length - 1) {
			regexPrep += "|";
		}
	}
	var regex = new RegExp("(" + regexPrep + "))", "ig");

	// the following loop loops over all returned
	// salesitems and gets the configured attributes.
	for ( var i = 0; i < salesItems.length; i++) {
		var salesItem = salesItems[i];
		var attributes = salesItem.stringAttributes;
		// copy only the node, without children
		var tr = typeAheadSuggestionRow.cloneNode(false);
		// it's not possible to add the eventlistener before cloning the node
		// tr.addEventListener("mouseover",typeAheadSelectSuggestionByMouseOver,false);

		// loops over all needed fields
		for ( var j = 0; j < typeAheadFields.length; j++) {
			
			// loops over all string attributes of this salesitem
			for ( var k = 0; k < attributes.length; k++) {
				// check if the actual name matches the fieldname
				if (attributes[k].name == typeAheadFields[j]) {
					// create new cell and fill with actValue
					// copy only the node, without children
					var td = typeAheadSuggestionCell.cloneNode(false);
					var value = attributes[k].value;
					td.innerHTML = value;
				}
			}
			tr.appendChild(td);
			               
		}
		// store the article link
		articleLinktd = document.createElement("td");
		var articleLink = typeAheadSuggestionLink.cloneNode(false);
		articleLink.setAttribute("href", salesItem.reference);
		articleLinktd.appendChild(articleLink);
		tr.appendChild(articleLinktd);
//		var trClass = "odd";
//		if(i % 2 == 0)
//		{
//			trClass = "even";
//		}
//		tr.setAttribute("class", trClass);
		table.appendChild(tr);
	}
	

	// gets the correct table, updates it and makes it visible
	var typeAheadForm = element.form;
	var typeAheadSuggestions = getElementsByClassName("typeAheadSuggestions",
			typeAheadForm)[0];
//	typeAheadSuggestions.style.display = "block";
	
	getElementsByClassName("autoCompletion",typeAheadForm)[0].style.display = "block";

	// switch because ie is unable to append a child properly
	// and the ff doesn't know outerHTML
	if (isBrowserIE()) {
		typeAheadSuggestions.innerHTML = table.outerHTML;
	} else {
		typeAheadSuggestions.innerHTML = "";
		typeAheadSuggestions.appendChild(table);
	}

}

