"use strict";

/*
*	This static class resembles a factory class for Typeahead inputs.
*	It can be used to create a new TypeAhead input along with its HTML element, or attach said functionality to an existing input field.
*/

function TypeAheadManager() {
	return new Error("Static class, can't be instantiated.");
}

/*
* public
*
* Creates a text input element with typeahead functionality, adds it to the HTML source and returns it.
* arrTables should contain the tables in which the internal dictionary should query.
* The element will be attached as a child of elParent.
* objCallbacks MUST have the following callbacks defined:
*  query - 4 parameters - callback, user id, query string, collapse type
*   should be able to call a "SHOW COLUMNS FROM *" query and a "SELECT * FROM *" query.
*   return of both should be an array with the needed values
*  search - 6 parameters - callback, user id, keywords, tables, columns, collapse type
*   should return an object containing a 'rows' property
*   the 'rows' property should be an object with table columns as keys and unique value arrays as values
*  error - 1 parameter - error object
*   it handles the exception object in case of an error/exception
* it CAN also have the following callbacks:
*  matchResults - 1 parameter - dataset
*   returns a function which matches input with dataset to provide autocomplete suggestions
*  buildSuggestions - variable paramters
*   called by matchResults to build suggestions depending on the current input state
*   (good for multiple data sources)
*  fillDataSet - 1 parameter - dataset
*   fills internal class dataset with data from the parameter
*  replaceWithSuggestion - 2 parameters - error, suggestion
*   defines what happens to the input when a suggestion is selected
*  eventHandler - 1 parameter - event
*   a callback which the class will bind to the click, keydown and keyup events
* 
* objInitialAttributes can contain any number of the following properties:
*  id : element id
*  class : element class
*  placeholder : element placeholder text
*
* objStyleClasses defines the style classes of the input element.
* It can contain any number of the following properties:
*  input - Added to input that's initialized into a typeahead. Defaults to tt-input.
*  hint - Added to hint input. Defaults to tt-hint.
*  menu - Added to menu element. Defaults to tt-menu.
*  dataset - Added to dataset elements. to Defaults to tt-dataset.
*  suggestion - Added to suggestion elements. Defaults to tt-suggestion.
*  empty - Added to menu element when it contains no content. Defaults to tt-empty.
*  open - Added to menu element when it is opened. Defaults to tt-open.
*  cursor - Added to suggestion element when menu cursor moves to said suggestion. Defaults to tt-cursor.
*  highlight - Added to the element that wraps highlighted text. Defaults to tt-highlight.
*
* mxUserID is the user ID corresponding to the currently logged in user of objClient.
*
* @param array arrTables.
* @param element elParent.
* @param object objCallbacks.
* @param object objInitialAttributes
*
* @return element
*/
TypeAheadManager.addInputElement = function(arrTables, elParent, objCallbacks, objInitialAttributes, objStyleClasses, mxUserID) {

	// if no parent was given, add element as child of body
	elParent = elParent || document.body;
	objInitialAttributes = objInitialAttributes || {};

	// check if provided callbacks are indeed functions
	TypeAheadManager._checkCallbacksValidity(objCallbacks);

	// build element
	var elInputElement = document.createElement("input");
	elInputElement.setAttribute("type", "text");
	elInputElement.setAttribute("class", objInitialAttributes["class"] || "typeahead");
	elInputElement.setAttribute("placeholder", objInitialAttributes["placeholder"] || "Type here...");
	elInputElement.setAttribute("id", objInitialAttributes["id"] || "typeaheadinput" + TypeAheadManager._idGenerator++);

	// append it to HTML and attach typeahead functionality
	elParent.appendChild(elInputElement);
	var objTypeAhead = new TypeAheadInput(elInputElement, arrTables, objCallbacks, mxUserID, objStyleClasses);

	return elInputElement;
}

/*
* public
* Attaches typeahead functionality to the element given as the first parameter, and returns it
*
* @param element elInput.
* @param array arrTables.
*
* @return element
*/
TypeAheadManager.attachToElement = function(elInput, arrTables, objCallbacks, mxUserID) {

	elInput.classList.add("typeahead");
	var objTypeAhead = new TypeAheadInput(elInput, arrTables, objCallbacks, mxUserID, {});

	return elInput;
}


/*
* public 
* Reverts an input element to its initial state; i.e. destroys autocomplete functionality
*
* @param element elInput.
*
* @return element
*/
TypeAheadManager.revertElement = function(elInput) {
	$(elInput).typeahead("destroy");
	return elInput;
}

/*
* protected
* Checks if objCallbacks contains objects of the desired type and format
*
* @param object objCallbacks.
*
* @return element
*/
TypeAheadManager._checkCallbacksValidity = function(objCallbacks) {

	for (var fnCallback in ["error", "query", "search"]) {
		if (typeof objCallbacks[fnCallback] !== "function")
			throw new Error(objCallbacks[fnCallback] + " must be of type function");
	}
}

/*
* private
* A static counter to generate different IDs
*/
TypeAheadManager._idGenerator = 0;