$(function(){
	$('input[data-widget="input-suggestions"]')
	.each(function(){
		this.Sug = new Suggestions(this);
	})
	.keypress(function(e){
		var Sug = this.Sug;
		if (Sug) {
			switch (e.keyCode) {
				case 38:	//up
					Sug.registerEvent('selectPrev');
					break;

				case 40:	//down
					Sug.registerEvent('selectNext');
					break;

				default:
					break;
			}
		}
	})
	.keyup(function(e){
		var Sug = this.Sug;
		if (Sug && !(e.keyCode==38 || e.keyCode==40 || e.keyCode==13 || e.keyCode==8)) {
			Sug.suggest(this.value);
		}
	});
});


function Suggestions(master){
	master.setAttribute('autocomplete', 'off');
	this.masterNode = master;
	this.masterValue = master.value;
	this.queryUrl = master.getAttribute('data-src');

	this.itemsNode = document.getElementById(this.masterNode.id + '_suggestions');
	if (!this.itemsNode) {
		this.itemsNode = document.createElement('ul');
		this.itemsNode.id = this.masterNode.id + '_suggestions';
		this.itemsNode.className = 'suggestions';
		this.itemsNode.style.display = 'none';
		this.masterNode.parentNode.insertBefore(this.itemsNode, this.masterNode.nextSibling);
	}

	this.registerEvent('hideOnBlur');
	this.registerEvent('showOnFocus');
}

Suggestions.prototype.queryUrl;	//Url to data
Suggestions.prototype.masterNode;	//master element
Suggestions.prototype.masterValue;	//user entered value
Suggestions.prototype.itemsNode;	//container for suggestion items
Suggestions.prototype.selectedItem;	//selected item
Suggestions.prototype.timer;
Suggestions.prototype.timeout = 300;

Suggestions.prototype.registerEvent = function (type) {
	switch (type) {
		case 'selectNext':
			var item = (this.selectedItem) ? this.selectedItem.nextSibling : this.itemsNode.firstChild;
			this.select(item, true);
			break;

		case 'selectPrev':
			var item = (this.selectedItem) ? this.selectedItem.previousSibling : this.itemsNode.lastChild;
			this.select(item, true);
			break;

		case 'hideOnBlur':
			var _this = this;
			_this.masterNode.onblur = function () {
				clearTimeout(_this.timer);
				_this.timer = setTimeout(function(){
					_this.itemsNode.style.display = 'none';
				}, 150);
			}
			break;

		case 'showOnFocus':
			var suggestions = this.itemsNode;
			this.masterNode.onfocus = function () {
				if (suggestions.children.length>0) {
					suggestions.style.display = 'block';
				}
			}
			break;

		default:
			break;
	}
}

Suggestions.prototype.suggest = function (keyword) {
	var queryUrl = this.queryUrl;
	var _this = this;

	if (!keyword || !queryUrl || keyword.length<1) {
		_this.itemsNode.style.display = 'none';
		_this.clear();
	}
	else if (this.masterValue != keyword) {
		this.masterValue = keyword;

		clearTimeout(this.timer);
		this.timer = setTimeout(function() {
			var jItemsNode = $(_this.itemsNode);
			jItemsNode.addClass('loading');
			$.getJSON(queryUrl, {q:keyword}, function(data){
				_this.clear();

				for (var i=0; i<data.length; i++) {
					_this.add(data[i]);
				}

				jItemsNode.removeClass('loading');
				_this.itemsNode.style.display = _this.itemsNode.children.length>0 ? 'block' : 'none';
			});
		}, this.timeout);
	}
}

Suggestions.prototype.select = function (item, set_master_value) {
	var str_selected = ' selected';

	if (this.selectedItem) {
		this.selectedItem.className = this.selectedItem.className.substr(0, this.selectedItem.className.indexOf(str_selected));
	}

	this.selectedItem = item;

	if (this.selectedItem) {
		this.selectedItem.className += str_selected;
	}

	if (set_master_value) {
		this.masterNode.value = (this.selectedItem) ? this.selectedItem.getAttribute('data-value') : this.masterValue;
	}
}

Suggestions.prototype.add = function (suggestion_value) {
	var suggestion = document.createElement('li');
	suggestion.setAttribute('data-value', suggestion_value);
	suggestion.className = 'suggestion';


	var suggestion_part_start = suggestion_value.toLowerCase().indexOf(this.masterValue.toLowerCase());
	var suggestion_part_end = suggestion_part_start + this.masterValue.length;
	var suggestion_parts = new Array();
	suggestion_parts[0] = suggestion_value.substr(0, suggestion_part_start);
	suggestion_parts[1] = suggestion_value.substr(suggestion_part_start, this.masterValue.length);
	suggestion_parts[2] = suggestion_value.substr(suggestion_part_end);

	for (var i=0; i<suggestion_parts.length; i++) {
		if (i==1) {
			var suggestion_label = document.createElement('em');
			suggestion_label.appendChild(document.createTextNode(suggestion_parts[i]));
			suggestion.appendChild(suggestion_label);
		}
		else {
			suggestion.appendChild(document.createTextNode(suggestion_parts[i]));
		}
	}


	_this = this;
	suggestion.onmouseover = function () {
		_this.select(this);
	}
	suggestion.onclick = function () {
		_this.select(this, true);
	}

	_this.itemsNode.appendChild(suggestion);
}

Suggestions.prototype.clear = function () {
	while (this.itemsNode.firstChild) this.itemsNode.removeChild(this.itemsNode.firstChild);	//clear children
}
