﻿/// <reference path="../jquery-1.7.1-vsdoc.js" />

(function ($) {
	$.fn.intializeTypeAhead = function (options) {
		return this.each(function () {
			initialize($(this), options);
		});
	};

	$.fn.setTypeAheadValues = function (display, id) {
		return this.each(function () {
			getTypeAheadDisplayContext($(this)).val(display).change();

			if (id == undefined) return;
			var idContext = getTypeAheadIdContext($(this));
			if (idContext != null) idContext.val(id).change();
		});
	};

	$.fn.getTypeAheadDisplay = function () {
		return getTypeAheadDisplayContext($(this)).val();
	};

	$.fn.getTypeAheadId = function () {
		var idContext = getTypeAheadIdContext($(this));
		return (idContext != null) ? idContext.val() : '';
	};

	function getTypeAheadDisplayContext(context) {
		var displayContext = context;
		if (!context.is(".typeAhead")) {
			displayContext = context.children(":text");
		}
		return displayContext;
	}

	function getTypeAheadIdContext(context) {
		var idContext = null;
		if (!context.is(".typeAhead")) {
			idContext = context.children(":hidden");
		}
		return idContext;
	}

	$.getTypeAheadOptions = function () {
		return TypeAheadOptions;
	};

	$.expr[':'].textEquals = function (a, i, m) {
		return $(a).text().match("^" + m[3] + "$");
	};

	function initialize(textBox, options) {

		var acOptions = {
			minLength: options.minLength,
			delay: options.delay,
			source: options.source,
			selectFirst: options.selectFirst,
			open: function (event, ui) {
				var widget = $(this).autocomplete("widget");
				widget.find("ui-menu-item-alternate")
						.removeClass("ui-menu-item-alternate")
					.end()
					.find("li.ui-menu-item:odd")
						.addClass("ui-menu-item-alternate");
			},
			select: function (event, ui) {
				var item = ui.item;
				if (item.isReadOnly) {
					return false;
				}
				options.itemSelected(item.data);
			}
		};
		textBox.click(function () { $(this).focus(); $(this).select(); });

		textBox.autocomplete(acOptions).data("autocomplete")._suggest = function (items) {
			if (!(textBox.hasFocus())) return false;

			var ul = this.menu.element.empty()
                                .zIndex(this.element.zIndex() + 1),
                        menuWidth,
                        textWidth;
			this._renderMenu(ul, items);

			this.menu.deactivate();
			this.menu.refresh();
			this.menu.element.show().position({
				my: "left top",
				at: "left bottom",
				of: this.element,
				collision: "none"
			});

			menuWidth = ul.width("").width();
			textWidth = this.element.width();

			var userWidth = (typeof options.width == "function") ? options.width(items) : options.width;
			ul.width(userWidth || Math.max(menuWidth, textWidth));

			var userHeight = (typeof options.height == "function") ? options.height(items) : options.height;
			ul.height(userHeight || ((items.length > 10) ? "10em" : "auto"));
		};

		textBox.autocomplete(acOptions)
			.unbind("blur.autocomplete")
			.data("autocomplete")._renderItem = function (ul, item) {
				var listItem = $("<li></li>").data("item.autocomplete", item);
				if (item.isReadOnly) {
					listItem.addClass("ui-menu-item-label")
						.append(item.label);
				}
				else {
					listItem.append("<a>" + options.formatItem(item) + "</a>");
				}
				return listItem.appendTo(ul);
			};

		textBox.keydown(function (e) {
			var keyCode = e.keyCode || e.which;
			if (keyCode >= 255) return;

			var availCodes = $.ui.keyCode;

			if (options.selectFirst) {
				if ((keyCode == availCodes.TAB || keyCode == availCodes.RETURN)) {
					var autocomplete = $(this).data("autocomplete"),
						menu = autocomplete.menu;

					if (!autocomplete.options.selectFirst) {
						return;
					}

					var currentVal = $.trim(textBox.val());
					var menuElement = menu.element;
					var isNotSelected = autocomplete.selectedItem == null &&
									 menuElement.children().filter(function () {
									 	return currentVal == $(this).text();
									 }).length == 0;

					if (isNotSelected && menuElement.children().length > 0) {
						menu.activate($.Event({ type: "mouseenter" }), menuElement.children().first());
					}
					return (keyCode == availCodes.TAB);
				}
			}
			else {
				if (keyCode == availCodes.TAB) {
					textBox.autocomplete("close");
				}
			}
		});


		if (options.isComboBox && textBox.siblings(".ui-autocomplete-button").length == 0) {
			textBox.addClass("ui-corner-left").addClass("ui-widget ui-widget-content").addClass("block").addClass("alignLeft");
			textBox.parent().addClass("ui-autocomplete-combobox");

			$("<button type='button'>&nbsp;</button>")
				.addClass("block")
				.attr("tabIndex", -1)
				.attr("title", "Show All Items")
				.insertAfter(textBox)
				.button({
					icons: { primary: "ui-icon-triangle-1-s" },
					text: false
				})
				.removeClass("ui-corner-all")
				.addClass("ui-corner-right ui-button-icon ui-autocomplete-button")
				.click(function () {
					// close if already visible
					if (textBox.autocomplete("widget").is(":visible")) {
						textBox.autocomplete("close");
						return false;
					}
					// close any other open typeaheads
					$(".ui-autocomplete-input").filter(function () {
						return $(this).autocomplete("widget").is(":visible");
					}).autocomplete("close");

					// pass empty string as value to search for, displaying all results
					textBox.focus();
					textBox.autocomplete("search", "");
					

					return false;
				});


		}

		if (typeof options.onClearSelection == "function") {
			textBox.keydown(function (e) {
				var code = (e.keyCode || e.which);
				if ((code == 8) || ((code > 31) && (code < 126)) || (code > 128))
					options.onClearSelection();
			});
		}

		$("body:not(.ui-autocomplete)").live('click', function () {
			textBox.autocomplete("close");
		});
	}

	var TypeAheadOptions = {
		getTextHighlighter: function (searchTerm) {

			var highlightFunction = function (text) { return text; };
			if ($.trim(searchTerm) != "") {
				var re = $.ui.autocomplete.escapeRegex(searchTerm);
				var matcher = new RegExp("(" + re + ")", "gi");
				highlightFunction = function (text) {
					return text.replace(matcher, "<span class='ta-highlight'>$1</span>");
				};
			}

			return {
				highlightSearchTerm: highlightFunction
			};
		},

		getDefaultClientOptions: function () {
			return TypeAheadOptions._baseClientOptions;
		},

		getDefaultServerOptions: function () {
			return TypeAheadOptions._baseServerOptions;
		},

		getCustomServerOptions: function (controllerName, actionName) {
			var serverOptions = {
				source: '/' + controllerName + '/' + actionName
			};

			return TypeAheadOptions.extendBaseServerOptions(serverOptions);
		},

		extendBaseServerOptions: function (customOptions) {
			var baseServerOptions = {
				minLength: 1,
				delay: 200,
				isComboBox: false,
				matchSubset: false,
				mustMatch: false,
				selectFirst: false,
				noDataMessage: "No matching items available.",
				formatItem: function (item) {
					return item.label;
				},
				itemSelected: function (data) {

				},
				buildSourceUrlData: function () {
					return {};
				},
				sourceUrl: "",
				parseItem: function (item, highlighter) {
					return item;
				}
			};

			var updatedOptions = TypeAheadOptions._mergeObjects(baseServerOptions, customOptions);

			if (updatedOptions.parse == null) {
				updatedOptions.parse = function (data, request) {
					var results = [];
					var items = data.Items;
					var highlighter = TypeAheadOptions.getTextHighlighter(request.term);
					for (var i = 0; i < items.length; i++) {
						results[results.length] = updatedOptions.parseItem(items[i], highlighter);
					}
					return results;
				};
			}

			updatedOptions.source = function (request, response) {

				var baseData = { term: request.term };
				var extendedData = updatedOptions.buildSourceUrlData();
				var sourceData = TypeAheadOptions._mergeObjects(baseData, extendedData);

				$.ajax({
					url: updatedOptions.sourceUrl,
					dataType: "json",
					data: sourceData,
					success: function (data) {
						var results = [];

						if (!(data.HasResults)) {
							msg = updatedOptions.noDataMessage;
						} else {
							results = updatedOptions.parse(data, request);

							var msg = "";
							if (data.MoreAvailable) {
								msg = "More results available. Keep typing to refine search.";
							}
						}

						if (msg != "") {
							results[results.length] = {
								data: {},
								value: "",
								label: msg,
								isReadOnly: true
							};
						}
						response(results);
					}
				});
			};
			return updatedOptions;
		},

		extendBaseClientOptions: function (customOptions) {
			var baseClientOptions = {
				formatItem: function (item) {
					return item.label;
				},
				itemSelected: function (data) {

				},
				parseItem: function (item, highlighter) {
					return item;
				}
			};
			var updatedOptions = TypeAheadOptions._mergeObjects(baseClientOptions, customOptions);

			if (updatedOptions.parse == null) {
				updatedOptions.parse = function (data, request) {
					var results = [];
					var items = data;
					var highlighter = TypeAheadOptions.getTextHighlighter(request.term);
					for (var i = 0; i < items.length; i++) {
						results[results.length] = updatedOptions.parseItem(items[i], highlighter);
					}
					return results;
				};
			}

			if (updatedOptions.source == null) {
				updatedOptions.source = function (request, response) {
					var data = updatedOptions.data(request.term);

					var results = [];
					if (data.length == 0) {
						results[results.length] = {
							data: {},
							value: "",
							label: updatedOptions.noDataMessage,
							isReadOnly: true
						};
					} else {
						results = updatedOptions.parse(data, request);
					}
					response(results);
				};
			}
			return updatedOptions;
		},

		addTypeAheadOptions: function (customOptions) {
			$.extend(TypeAheadOptions, customOptions);
		},

		_mergeObjects: function (baseObject, secondObject) {
			var merged = {};
			$.extend(merged, baseObject, secondObject);
			return merged;
		}
	};
})(jQuery);
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

