(function ($) {
	var ShoppingAutoComplete = function (ele, opts) {
		this.ele = $(ele);

		this.config = $.extend({
			url: "/tlookup/AddressSearch.ashx",
			//url: "/Handlers/AddressSearch.ashx",
			allowZipOnly: 1,
			showWarning: 0,
			showWarningIfEmpty: 1,
			liTemplate: "<li datatoken='${datatoken}' tdu='${tdu}' streetnum='${streetnum}' streetname='${streetname}' unitnum='${unitnum}' cityname='${cityname}' zipcode='${zipcode}'>${displaytext}</li>",
			waitTime: 1000,
			hoverClass: "hover",
			loadingClass: "loading",
			matchedClass: "match",
			dataTokenField: "",
			tduField: "",
			streetNumField: "",
			streetNameField: "",
			unitNumField: "",
			cityNameField: "",
			zipCodeField: "",
			numResultsField: "",
			apartmentYesField: "span.apartmentYes input",
			apartmentNoField: "span.apartmentNo input",
			changeListenSelector: ".autoCompleteChangeListen",
			changeEventName: "changed.autoComplete"
		}, opts, this.ele.ParseClass(true));
		this.container = this.ele.wrap('<span class="shoppingAutoCompleteContainer"></span>').parent();
		this.ul = $("<ul></ul>").appendTo('body');
		this.optionsList = this.ul.wrap('<div class="shoppingAutoCompleteOptions"></div>').parent();
		this.dataTokenField = $(this.config.dataTokenField);
		this.tduField = $(this.config.tduField);
		this.streetNumField = $(this.config.streetNumField);
		this.streetNameField = $(this.config.streetNameField);
		this.unitNumField = $(this.config.unitNumField);
		this.zipCodeField = $(this.config.zipCodeField);
		this.cityNameField = $(this.config.cityNameField);
		this.numResultsField = $(this.config.numResultsField);

		// [remove]
		/*$('input[type="hidden"]').each(function() {
		this.type = 'text';
		});*/

		this.closeTimer = this.cancelKeyUp = this.currentCall = this.timer = false;

		this.ele.attr("autocomplete", "off");

		this.ele
		.keydown($.proxy(this._onKeyDown, this))
		.keyup($.proxy(this._onKeyUp, this))
		.focus($.proxy(this._onFocus, this))
		.blur($.proxy(this._onBlur, this));

		this.ul.mousedown($.proxy(this._onULClick, this));

		this.callCache = {};

		if (this.config.autoOpen == true) {
			this.dataOut(this.ele.val());
		}

		return this;
	};
	$.extend(ShoppingAutoComplete.prototype, {
		_onKeyDown: function (e) {
			this.cancelKeyUp = true;
			switch (e.keyCode) {
				case 13:
					//enter key pressed
					this._onEnterKey();
					return false;
				case 27:
					//esc key pressed
					this.close();
					return false;
				case 38:
					//up arrow pressed
					this.highlightOption(-1);
					return false;
				case 40:
					//down arrow pressed
					this.highlightOption(1);
					return false;
				case 37:
				case 39:
					break;
				default:
					this.cancelKeyUp = false;
					break;
			}
		},
		_onKeyUp: function (e) {
			if (!this.cancelKeyUp) {
				this.resetValues();
				this.ele.removeClass(this.config.matchedClass);
				this.dataOut(this.ele.val());
			}
		},
		_onULClick: function (e) {
			this.cancelClose();

			var li = $(e.target);
			if (!li.is("li")) li.parents("li:first");
			if (!li.is("li")) return;

			//select the li
			this.selectOption(li);
		},
		_onFocus: function (e) {
			this.cancelClose();
		},
		_onBlur: function (e) {
			this.close();
			this._toggleWarningMessage();
		},
		_onEnterKey: function (e) {
			var current = $("li." + this.config.hoverClass, this.ul);
			if (current.length != 0) {
				this.selectOption(current);
			}
		},
		_queueCall: function (call) {
			this._cancelQueue();
			this._triggerQueue = $.proxy(function () {
				if (this.currentCall) {
					this.currentCall.abort();
					this.currentCall = false;
				}
				this.dataOut(call);
			}, this);
			this.timer = setTimeout(this._triggerQueue, this.config.waitTime);
		},
		_cancelQueue: function () {
			clearTimeout(this.timer);
			this._triggerQueue = false;
		},
		_toggleWarningMessage: function () {
			if (this.config.showWarning == 1) {
				var parentItem = this.ele.parents("div.item");
				if(!this.config.showWarningIfEmpty && (this.ele.val() == "")) {
					parentItem.removeClass("warning");
					$("div.note").hide();
					return;
				}
				if (!this.ele.hasClass(this.config.matchedClass)) {
					parentItem.addClass("warning");
					$("div.note").show();
				} else {
					parentItem.removeClass("warning");
					$("div.note").hide();
				}
			}
		},
		open: function () {
			if (!this.isOpen()) {
				this.cancelClose();
				this.container.addClass("open");
				this.optionsList.addClass("open");
				this.ul.find("li").removeClass(this.config.hoverClass);
				//this.dataOut(this.ele.val());

				this.positionList();
			}
		},
		close: function () {
			this.closeTimer = setTimeout($.proxy(function () {
				this.container.removeClass("open");
				this.optionsList.removeClass("open");
				//this._toggleWarningMessage();
			}, this), 10);
		},
		cancelClose: function () {
			clearTimeout(this.closeTimer);
		},
		isOpen: function () {
			return this.container.hasClass("open");
		},
		positionList: function () {
			var pos = this.ele.offset();
			this.optionsList.css({
				'top': pos.top + this.ele.outerHeight(),
				'left': pos.left,
				'width': this.ele.outerWidth()
			});
		},
		dataOut: function (q) {
			if ($.trim(q) == "") {
				if (this.currentCall) {
					this.currentCall.abort();
					this.currentCall = false;
				}
				this.ul.html("");
				return;
			}

			this.ele.addClass(this.config.loadingClass);

			this._cancelQueue();

			if (!this.currentCall) {
				if (this.callCache[q]) {
					this.dataIn(this.callCache[q]);
					return;
				}
				this.currentCall = $.getJSON(this.config.url, { q: q, zip: this.config.allowZipOnly }, $.proxy(function (data) {
					if (data && data.results) {
						this.callCache[q] = data;
						this.dataIn(data);
					}
				}, this));
			} else {
				this._queueCall(q);
			}
		},
		dataIn: function (data) {
			this.currentCall = false;

			this.ele.removeClass(this.config.loadingClass);
			this.open();
			this.ul.html("");
			for (var i = 0, result; result = data.results[i]; i++) {

				result.DataToken = result.DataToken || '';
				result.Tdu = result.Tdu || '';
				result.HouseNumber = result.HouseNumber || '';
				result.Street = result.Street || '';
				result.Unit = result.Unit || '';
				result.City = result.City || '';
				result.State = result.State || 'TX';

				$(this.config.liTemplate.replace("${displaytext}", result.DisplayText).replace("${datatoken}", result.DataToken).replace("${tdu}", result.Tdu).replace("${streetnum}", result.HouseNumber).replace("${streetname}", result.Street).replace("${unitnum}", result.Unit).replace("${cityname}", result.City).replace("${zipcode}", result.Zip))
				.appendTo(this.ul);
			}

			this.numResultsField.val(data.results.length);

			var item = (data.results.length == 1) ? this.ul.find("li") : null;
			this.selectOption(item, true);

			if (this.queuedCall !== false && this._triggerQueue) {
				this._triggerQueue();
			}
		},
		highlightOption: function (diff) {
			if (!this.isOpen()) {
				this.open();
			}
			current = this.ul.find("li." + this.config.hoverClass)[(diff == 1) ? "next" : "prev"]();
			if (!current.is("li")) {
				current = this.ul.find("li:" + ((diff == 1) ? "first" : "last"));
			}
			this.ul.find("li").removeClass(this.config.hoverClass);
			current.addClass(this.config.hoverClass);
			return false;
		},
		selectOption: function (item, autoSelected) {
			if (item != null) {
				if (autoSelected !== true) {
					this.ele.val(item.text());
				}
				this.ele.addClass(this.config.matchedClass);

				this.dataTokenField.val(item.attr("datatoken"));
				this.tduField.val(item.attr("tdu"));
				this.streetNumField.val(item.attr("streetnum"));
				this.streetNameField.val(item.attr("streetname"));
				this.unitNumField.val(item.attr("unitnum"));
				this.cityNameField.val(item.attr("cityname"));
				this.zipCodeField.val(item.attr("zipcode"));
				this.numResultsField.val("1");
				if (item.attr("unitnum")) {
					$(this.config.apartmentYesField).attr("checked", true);
				} else {
					$(this.config.apartmentNoField).attr("checked", true);
				}
				$(this.config.changeListenSelector).trigger(this.config.changeEventName);
			} else {
				this.resetValues(false);
				this.ele.removeClass(this.config.matchedClass);
			}

			if (autoSelected !== true) {
				this.ul.html("");
				this.close();
				this._toggleWarningMessage();
			}

		},
		resetValues: function (resetCount) {
			this.dataTokenField.val('');
			this.tduField.val('');
			this.streetNumField.val('');
			this.streetNameField.val('');
			this.unitNumField.val('');
			this.cityNameField.val('');
			this.zipCodeField.val('');
			if (resetCount != false) {
				this.numResultsField.val('');
			}
		}
	});

	$.fn.extend({
		ShoppingAutoComplete: function (opts) {
			var $this = this.not(function (i) {
				return $.data(this, "ShoppingAutoCompleteObj");
			}).each(function () {
				$.data(this, "ShoppingAutoCompleteObj", new ShoppingAutoComplete(this, opts));
			});
			return this;
		}
	});
	$.ShoppingAutoComplete = {
		init: function (sel) {
			$(sel || "input.shoppingAutoComplete").ShoppingAutoComplete();
		}
	};
	$(function () {
		$.ShoppingAutoComplete.init();
	});
})(jQuery);

