// Extension of jquery autocomplete for styling purposes
$.Autocompleter.Select = function (options, input, select, config) {
	var CLASSES = {
		ACTIVE: 'ac_over'
	};
	var listItems,
		active = -1,
		data,
		term = '',
		needsInit = true,
		element,
		list;

	// Create results
	function init() {
		if (!needsInit)
			return;
		
		// Set correct language title
		var langProducts = 'Producten';
		if (jQuery('body').hasClass('lang-en'))
		{
			langProducts = 'Products';
		}
		else if (jQuery('body').hasClass('lang-fr'))
		{
			langProducts = 'Produits';
		}
		
		element = jQuery('<div><p>'+langProducts+':</p></div>')
			.hide()
			.addClass(options.resultsClass)
			.css('position', 'absolute')
			.appendTo(document.body);

		list = jQuery('<ul/>').appendTo(element).mouseover(function(event) {
			if (target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
				active = jQuery('li', list).removeClass(CLASSES.ACTIVE).index(target(event));
				jQuery(target(event)).addClass(CLASSES.ACTIVE);
			}
		}).click(function(event) {
			jQuery(target(event)).addClass(CLASSES.ACTIVE);
			select();
			// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
			input.focus();
			return false;
		}).mousedown(function() {
			config.mouseDownOnSelect = true;
		}).mouseup(function() {
			config.mouseDownOnSelect = false;
		});

		if (options.width > 0)
			element.css('width', options.width);

		needsInit = false;
	}

	function target(event) {
		var element = event.target;
		while (element && element.tagName != 'LI')
			element = element.parentNode;
		// more fun with IE, sometimes event.target is empty, just ignore it then
		if (!element)
			return [];
		return element;
	}

	function moveSelect(step) {
		listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
		movePosition(step);
		var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
		if(options.scroll) {
			var offset = 0;
			listItems.slice(0, active).each(function() {
				offset += this.offsetHeight;
			});
			if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
				list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
			} else if(offset < list.scrollTop()) {
				list.scrollTop(offset);
			}
		}
	};

	function movePosition(step) {
		active += step;
		if (active < 0) {
			active = listItems.size() - 1;
		} else if (active >= listItems.size()) {
			active = 0;
		}
	}

	function limitNumberOfItems(available) {
		return (options.max && options.max < available) ? options.max : available;
	}

	function fillList() {
		list.empty();
		var max = limitNumberOfItems(data.length);
		for (var i = 0; i < max; i++) {
			if (!data[i])
				continue;
			var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
			if ( formatted === false )
				continue;
			var li = jQuery('<li/>').html(options.highlight(formatted, term))
				.addClass(i % 2 == 0 ? 'ac_even' : 'ac_odd')
				.appendTo(list)[0];
			jQuery.data(li, 'ac_data', data[i]);
		}
		listItems = list.find('li');
		if ( options.selectFirst ) {
			listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
			active = 0;
		}
		// apply bgiframe if available
		if ( jQuery.fn.bgiframe )
			list.bgiframe();
	}

	return {
		display: function(d, q) {
			init();
			data = d;
			term = q;
			fillList();
		},
		next: function() {
			moveSelect(1);
		},
		prev: function() {
			moveSelect(-1);
		},
		pageUp: function() {
			if (active != 0 && active - 8 < 0) {
				moveSelect( -active );
			} else {
				moveSelect(-8);
			}
		},
		pageDown: function() {
			if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
				moveSelect( listItems.size() - 1 - active );
			} else {
				moveSelect(8);
			}
		},
		hide: function() {
			element && element.hide();
			listItems && listItems.removeClass(CLASSES.ACTIVE);
			active = -1;
		},
		visible : function() {
			return element && element.is(':visible');
		},
		current: function() {
			return this.visible() && (listItems.filter('.' + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
		},
		show: function() {
			var offset = jQuery(input).offset();
			element.css({
				width: typeof options.width == 'string' || options.width > 0 ? options.width : jQuery(input).width(),
				top: offset.top + input.offsetHeight + options.topOffset,
				left: offset.left + options.leftOffset
			}).show();
			if (options.scroll) {
				list.scrollTop(0);
				list.css({
					maxHeight: options.scrollHeight,
					overflow: 'auto'
				});

				if (jQuery.browser.msie && typeof document.body.style.maxHeight === 'undefined') {
					var listHeight = 0;
					listItems.each(function() {
						listHeight += this.offsetHeight;
					});
					var scrollbarsVisible = listHeight > options.scrollHeight;
					list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
					if (!scrollbarsVisible) {
						// IE doesn't recalculate width when scrollbar disappears
						listItems.width( list.width() - parseInt(listItems.css('padding-left')) - parseInt(listItems.css('padding-right')));
					}
				}
			}
		},
		selected: function() {
			var selected = listItems && listItems.filter('.' + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
			return selected && selected.length && jQuery.data(selected[0], 'ac_data');
		},
		emptyList: function () {
			list && list.empty();
		},
		unbind: function() {
			element && element.remove();
		}
	};
};
