function AutoCompleter(id, suggestId, displayNum, submitForm, file, appSettings) {
	var defaults = {
		lang: null,
		useSE: null,
		delegator: null,
		dividerText: null,
		dividerType: null,
		textColor: '#000000',
		highlightTextColor: '#000000',
		backgroundColor: 'transparent',
		highlightColor: '#C4C4C4',
		minTypedChars: 1,
		ajaxurl: 'http://www.yellowpages.ca/tools/autosuggestlist.html'
	};

	var settings = jQuery.extend(defaults, appSettings);

	this.settings = settings;
	this.source = [];
	this.file = file;
	this.id = id;
	this.inputNode = document.getElementById(id);
	this.submitForm = submitForm;
	this.suggestId = suggestId;
	this.suggestNode = document.getElementById(suggestId);
	this.displayNum = displayNum;
	this.field = (id.indexOf('What') > -1) || (id.indexOf('BusName') > -1) ? 'WHAT' : 'WHERE';
	this.useSE = settings.useSE;
	this.lang = settings.lang;
	this.delegator = settings.delegator;
	this.suggestionIndex = -1;
	this.suggestedItems = null;
	if ('fr' === this.lang) {
		this.settings.ajaxurl = 'http://www.pagesjaunes.ca/tools/autosuggestlist.html';
	}
	this.inputNode.onkeydown = this.keydown;
	this.inputNode.onkeyup = this.keyup;
	this.inputNode.suggest = this; //pointer to AutoCompleter Object
	this.inputNode.suggestbox = this.suggestNode;
	this.inputNode.onblur = function() { this.suggest.hide(); };
	this.suggestNode.onmousedown = this.mousedown;
	this.suggestNode.inbox = this.inputNode;
	this.suggestNode.suggestbox = this;
	this.suggestNode.value = '';
	this.inprogress = false;
	this.navigating = false;
}

AutoCompleter.prototype.getdatasource = function() {
	var thisAS = this; // save away this AutoCompleter object as the meaning of "this" inside Ajax.Request object changes to point to the Ajax.Request object

	var userInput = this.inputNode.value;
	if (userInput.length < this.settings.minTypedChars) { 
		this.source = [];
		this.hide();
		return;
	}

	if (this.inprogress 
	|| (null === this.inputNode)) {
		return;
	}

	this.inprogress = true;
	jQuery.ajax ( {
		url: this.settings.ajaxurl,
		dataType: 'jsonp', 
		data: {f: this.file, t: userInput, c: thisAS.inputNode.name, lang: this.lang, fld: this.field, SE: this.useSE},
		success: function(result) {
			thisAS.source = result;
			thisAS.suggest();
		},
		complete: function(request, status) { // both will be undefined
			thisAS.inprogress = false;
		}
	} );
};

AutoCompleter.prototype.keyup = function(event) {
	event = event || window.event;
	var keyValue = (event.keyCode) ? event.keyCode : (event.which) ? event.which : null;
	switch(keyValue) {
		case 38: //up arrow
			this.suggest.moveup();
			break;
		case 40: //down arrow
			this.suggest.movedown(event);
			break;
		default:
			if (13 !== keyValue) {
				this.suggest.getdatasource();
			}
			break;
	}
};

AutoCompleter.prototype.keydown = function(event) {
	event = event || window.event;
	var keyValue = (event.keyCode) ? event.keyCode : (event.which) ? event.which : null;

	if (13 === keyValue) {
		this.suggest.hide();
		var wasNavigating = this.suggest.navigating;
		this.suggest.navigating = false;
		return !wasNavigating;
	}
};

AutoCompleter.prototype.moveup = function() {
	this.navigating = true;
	if (0 < this.suggestionIndex) {
		this.suggestedItems.eq(this.suggestionIndex).css('background-color',this.settings.backgroundColor);
		this.suggestedItems.eq(this.suggestionIndex).css('color',this.settings.textColor);
		this.suggestionIndex--;

		this.suggestedItems.eq(this.suggestionIndex).css('background-color',this.settings.highlightColor);
		this.suggestedItems.eq(this.suggestionIndex).css('color',this.settings.highlightTextColor);
		this.inputNode.value = this.suggestedItems.eq(this.suggestionIndex).text();
	}
};

AutoCompleter.prototype.movedown = function() {
	this.navigating = true;
	if (this.suggestionIndex < this.suggestedItems.size() - 1) {
		if (0 <= this.suggestionIndex) {
			this.suggestedItems.eq(this.suggestionIndex).css('background-color',this.settings.backgroundColor);
			this.suggestedItems.eq(this.suggestionIndex).css('color',this.settings.textColor);
		}

		this.suggestionIndex++;
		this.suggestedItems.eq(this.suggestionIndex).css('background-color',this.settings.highlightColor);
		this.suggestedItems.eq(this.suggestionIndex).css('color',this.settings.highlightTextColor);
		this.inputNode.value = this.suggestedItems.eq(this.suggestionIndex).text();
	}
};

AutoCompleter.prototype.mousedown = function(event) {
	event = event || window.event;
	var clickedItem = (event.srcElement) ? event.srcElement : event.target;

	if ('asItem' === clickedItem.className) {
		var text = clickedItem.firstChild.nodeValue;
		this.inbox.value = text;
		this.suggestbox.hide();
		this.inbox.focus();
	} else {
		return false;
	}
};

AutoCompleter.prototype.suggest = function() {

	var displayDividerAdded = false;
	var input = this.inputNode.value;
	if (!input 
	|| ('' === input)) {
		this.hide();
	} else {
		if (0 === this.source.length) {
			this.hide();
		} else {
			var suggestions = '';
			for (i = 0; i < this.source.length; i++) {
				if (i >= this.displayNum) {
					break;
				}
				if ((this.settings.dividerText !== null)
				&& (this.settings.dividerText !== null)
				&& (!displayDividerAdded)
				&& (this.settings.dividerType !== null)
				&& (this.source[i].type === this.settings.dividerType)) {
					suggestions += '<div class="asCachedSuggest"><div class="asDividerMarker">' + this.settings.dividerText + '</div>';
					displayDividerAdded = true;
				}
				suggestions += '<div class="asItem">' + this.source[i].value + '</div>';
			}
			if (displayDividerAdded) {
				suggestions += '</div>';
			}
			this.show(suggestions);
			this.suggestedItems = jQuery('#' + this.suggestId + ' .asItem');// update suggested list
		}
	}
};

AutoCompleter.prototype.hide = function() {
	this.suggestNode.style.display = 'none';
	this.suggestionIndex = -1;
};

AutoCompleter.prototype.show = function(suggestions) {
	this.suggestNode.style.display = 'block';
	this.suggestNode.innerHTML = suggestions;
};

