function McxInstanceBrowser(parentElement)
{
	this.ParentElement = parentElement;
	this.HiddenElement = this.ParentElement.children[1];
	this.TextBoxElement = this.ParentElement.children[2];
	this.ListElement = this.ParentElement.children[3];
	this.SearchResultsElement = this.ParentElement.children[4];
	this.SearchResultsMenuElement = this.SearchResultsElement.children[0];
	this.SearchResultsSpinnerElement = this.SearchResultsElement.children[1];
	this.SearchResultsPlaceholderElement = this.SearchResultsElement.children[2];

	this.__timeout = null;
	this.TextBoxElement.NativeObject = this;
	this.TextBoxElement.addEventListener("focus", function(e)
	{
		this.NativeObject.search(this.NativeObject.TextBoxElement.value);
		this.NativeObject.setEditing(true);
	});
	this.ParentElement.addEventListener("blur", function(e)
	{
		console.log(e.relatedTarget);
		this.NativeObject.setEditing(false);
	});

	this.setEditing = function(value)
	{
		if (value)
		{
			System.ClassList.Add(this.ParentElement, "mcx-editing");
		}
		else
		{
			System.ClassList.Remove(this.ParentElement, "mcx-editing");
		}
	};

	this.SearchResultsElement.NativeObject = this;
	this.SearchResultsElement.addEventListener("mousemove", function(e)
	{
		var searchResultsElements = this.NativeObject.SearchResultsMenuElement.children;
		for (var i = 0; i < searchResultsElements.length; i++)
		{
			System.ClassList.Remove(searchResultsElements[i], "uwt-highlight");
		}
		System.ClassList.Add(e.target, "uwt-highlight");
	});
	this.SearchResultsElement.addEventListener("keydown", function(e)
	{
		if (e.keyCode == KeyboardKeys.Tab)
		{
			// we are tabbing out of the search results, forward
			this.NativeObject.setEditing(false);
		}
	});

	this.buildSearchResult = function(searchResult)
	{
		var li = document.createElement("li");
		/*
		var a = document.createElement("a");
		a.href = System.ExpandRelativePath("~/" + System.TenantName + "/d/inst/" + searchResult.iid + ".htmld");
		a.setAttribute("data-instance-id", searchResult.iid);
		a.innerText = searchResult.title;
		li.appendChild(a);
		*/
		var a = McxMoniker.create(searchResult.instanceId, searchResult.text, searchResult.viewTask);
		li.appendChild(a);

		a = document.createElement("a");
		a.className = "uwt-delete-button";
		a.NativeObject = this;
		a.Index = this.ListElement.children.length;
		a.addEventListener("click", function()
		{
			this.NativeObject.removeAt(this.Index);
		});
		li.appendChild(a);

		return li;
	};

	this.getSelectedInstanceKeysString = function()
	{
		var str = "";
		for (var i = 0; i < this.ListElement.children.length; i++)
		{
			var iid = this.ListElement.children[i].children[0].getAttribute("data-instance-id");
			str += iid;
			if (i < this.ListElement.children.length - 1)
			{
				str += ",";
			}
		}
		return str;
	};

	this.setPlaceholderText = function(value)
	{
		this.SearchResultsPlaceholderElement.innerText = value;
	};

	this.clearSearchResults = function()
	{
		while(this.SearchResultsMenuElement.children.length > 0)
		{
			this.SearchResultsMenuElement.children[0].remove();
		}
	};
	this.clearSelectedItems = function()
	{
		while (this.ListElement.children.length > 0)
		{
			this.ListElement.children[0].remove();
		}
	};
	this.getSelectedItems = function()
	{
		var items = [];
		var strbps = this.HiddenElement.value;
		if (strbps === "")
			return items;
		
		var strbpa = strbps.split(",");
		for (var i = 0; i < strbpa.length; i++)
		{
			items.push(InstanceKey.parse(strbpa[i]));
		}
		return items;
	};
	this.activateSearchResult = function(searchResult)
	{
		// `this` refers to the McxInstanceBrowser
		if (!System.ClassList.Contains(this.ParentElement, "mcx-multiselect"))
		{
			this.clearSelectedItems();
		}

		this.ListElement.appendChild(this.buildSearchResult(searchResult));
		this.TextBoxElement.value = "";
		this.HiddenElement.value = this.getSelectedInstanceKeysString();
		this.ParentElement.setAttribute("data-instance-ids", this.getSelectedInstanceKeysString());
		return true;
	};
	this.search = function(query)
	{
		if (typeof(query) === 'undefined')
		{
			query = this.TextBoxElement.value;
		}

		System.ClassList.Add(this.SearchResultsElement, "uwt-loading");
		this.clearSearchResults();
		this.setPlaceholderText("type to search the list");
		if (query === "")
		{
			System.ClassList.Add(this.SearchResultsElement, "mcx-placeholder-visible");
		}
		else
		{
			System.ClassList.Remove(this.SearchResultsElement, "mcx-placeholder-visible");
		}

		var xhr = new XMLHttpRequest();
		xhr.NativeObject = this;
		var url = System.ExpandRelativePath("~/" + System.TenantName + "/prompt/c0/" + this.ParentElement.getAttribute("data-ecid") + ".htmld");
		xhr.open("POST", url);
		var h = {
			"_flowExecutionKey": "e0s1",
			"_eventId_prompt": this.ParentElement.getAttribute("data-ecid"),
			"sessionSecureToken": "7733ad40-edf6-4dc9-aa90-85bcf93cc8f0",
			"clientRequestID" : "9af7ce5bc51348a6981539a98b267072",
			"q" : query
		};
		xhr.onreadystatechange = function()
		{
			if (this.readyState === 4)
			{
				if (this.status == 200)
				{
					var json = JSON.parse(this.responseText);

					this.NativeObject.clearSearchResults();
					System.ClassList.Remove(this.NativeObject.SearchResultsElement, "mcx-placeholder-visible");

					for (var i = 0; i < json.items.length; i++)
					{
						var li = document.createElement("li");
						li.className = "uwt-menu-item uwt-menu-item-command uwt-visible";
						li.searchResult = json.items[i];
						li.NativeObject = this.NativeObject;
						li.addEventListener("click", function()
						{
							if (this.NativeObject.activateSearchResult(this.searchResult))
							{
								this.NativeObject.setEditing(false);
							}
						});

						var moniker = McxMoniker.create(json.items[i].instanceId, json.items[i].text);
						/*
						var span = document.createElement("span");
						span.className = "uwt-title uwt-description-empty";
						span.innerText = json.items[i].title;
						li.appendChild(span);
						*/
						li.appendChild(moniker);

						this.NativeObject.SearchResultsMenuElement.appendChild(li);
					}

					System.ClassList.Remove(this.NativeObject.SearchResultsElement, "uwt-loading");
				}
				else
				{
					if (json.responseCode === 403)
					{
						Alert.show("Please log in to continue", "Not Authorized", "uwt-color-danger");
					}
					else
					{
						System.ClassList.Add(this.NativeObject.SearchResultsElement, "mcx-placeholder-visible");
						this.NativeObject.setPlaceholderText("Too many results. Please refine your search.");
					}
					System.ClassList.Remove(this.NativeObject.SearchResultsElement, "uwt-loading");
				}
			}
		};
		xhr.send(JSON.stringify(h));
	};

	this.TextBoxElement.addEventListener("keydown", function(e)
	{
		if (e.keyCode == 13)
		{
			if (this.NativeObject.SearchResultsMenuElement.children.length === 1)
			{
				if (this.NativeObject.activateSearchResult(this.NativeObject.SearchResultsMenuElement.children[0].searchResult))
				{
					this.NativeObject.setEditing(false);
				}
			}
			else
			{
				if (this.NativeObject.__timeout !== null)
				{
					window.clearTimeout(this.NativeObject.__timeout);
				}
				this.NativeObject.search();

				window.setTimeout(function(thiss)
				{
					if (thiss.NativeObject.SearchResultsMenuElement.children.length === 1)
					{
						if (thiss.NativeObject.activateSearchResult(thiss.NativeObject.SearchResultsMenuElement.children[0].searchResult))
						{
							thiss.NativeObject.setEditing(false);
						}
					}
				}, 100, this);
			}
			e.preventDefault();
			e.stopPropagation();
			return false;
		}
		if (e.keyCode == 37)
		{
			return;
		}
		else if (e.keyCode == 38)
		{
			return;
		}
		else if (e.keyCode == 39)
		{
			return;
		}
		else if (e.keyCode == 40)
		{
			return;
		}
		else if (e.keyCode == 16 || e.keyCode == 17 || e.keyCode == 18)
		{
			return;
		}

		console.log(e.keyCode);

		System.ClassList.Add(this.NativeObject.SearchResultsElement, "uwt-loading");
		if (this.NativeObject.__timeout !== null)
		{
			window.clearTimeout(this.NativeObject.__timeout);
		}
		this.NativeObject.__timeout = window.setTimeout(function(thiss)
		{
			thiss.search(thiss.TextBoxElement.value);
		}, 1000, this.NativeObject);
		
		if (e.keyCode == KeyboardKeys.Tab && e.shiftKey)
		{
			// we are tabbing out of the input element, backward
			this.NativeObject.setEditing(false);
			return true;
		}
		if (e.keyCode == KeyboardKeys.Enter)
		{
			e.preventDefault();
			e.stopPropagation();
			return false;
		}
		else if (e.keyCode == KeyboardKeys.Escape)
		{
			System.ClassList.Remove(this.NativeObject.ParentElement, "mcx-editing");
		}
		else if (e.keyCode == KeyboardKeys.ArrowUp)
		{
			var searchResultsElements = this.NativeObject.SearchResultsMenuElement.children;
			if (searchResultsElements.length > 0)
			{
				var i = searchResultsElements.length - 1;
				var currentIndex = -1;
				while (i >= 0)
				{
					if (System.ClassList.Contains(searchResultsElements[i], "uwt-highlight"))
					{
						currentIndex = i;
					}
					System.ClassList.Remove(searchResultsElements[i], "uwt-highlight");
					i--;
				}
				if (currentIndex > 0)
				{
					System.ClassList.Add(searchResultsElements[currentIndex - 1], "uwt-highlight");
				}
				else
				{
					System.ClassList.Add(searchResultsElements[searchResultsElements.length - 1], "uwt-highlight");
				}
			}
		}
		else if (e.keyCode == KeyboardKeys.ArrowDown)
		{
			var searchResultsElements = this.NativeObject.SearchResultsMenuElement.children;
			if (searchResultsElements.length > 0)
			{
				var i = 0;
				var currentIndex = -1;
				while (i < searchResultsElements.length)
				{
					if (System.ClassList.Contains(searchResultsElements[i], "uwt-highlight"))
					{
						currentIndex = i;
					}
					System.ClassList.Remove(searchResultsElements[i], "uwt-highlight");
					i++;
				}
				if (currentIndex < searchResultsElements.length - 1)
				{
					System.ClassList.Add(searchResultsElements[currentIndex + 1], "uwt-highlight");
				}
				else
				{
					System.ClassList.Add(searchResultsElements[0], "uwt-highlight");
				}
			}
		}
	});

	this.removeAt = function(index)
	{
		console.log(this.HiddenElement);

		var strbps = this.HiddenElement.value;
		var strbpa = strbps.split(",");
		var strbpn = [ ];
		for (var i = 0; i < strbpa.length; i++)
		{
			if (i !== index)
			{
				strbpn.push(strbpa[i]);
			}
		}

		this.ListElement.children[index].remove();

		this.HiddenElement.value = strbpn.join(",");
	};

	for (var i = 0; i < this.ListElement.children.length; i++)
	{
		var delete_btn = this.ListElement.children[i].children[1];
		delete_btn.NativeObject = this;
		delete_btn.addEventListener("click", function()
		{
			var index = Array.prototype.indexOf.call(this.NativeObject.ListElement.children, this.parentElement);
			this.NativeObject.removeAt(index);
		});
	}
}

McxInstanceBrowser.create = function(parms)
{
	var div = document.createElement("DIV");
	div.className = "mcx-instancebrowser mcx-editable";

	if (parms.multiselect === true)
	{
		System.ClassList.Add(div, "mcx-multiselect");
	}

	var value = null;
	if (parms.ecid)
	{
		div.setAttribute("data-ecid", parms.ecid);
	}
	if (typeof(parms.selectedInstanceIds) === "object")
	{
		value = parms.selectedInstanceIds.join(";");
		div.setAttribute("data-instance-ids", value);
	}
	if (typeof(parms.validClassIds) === "object")
	{
		div.setAttribute("data-valid-class-ids", parms.validClassIds.join(";"));
	}
	if (parms.autocompleteUrl)
	{
		div.setAttribute("data-autocomplete-url", parms.autocompleteUrl);
	}

	var divTitle = document.createElement("DIV");
	if (parms.title)
	{
		divTitle.innerHTML = title;
	}
	div.appendChild(divTitle);

	var inputHidden = document.createElement("INPUT");
	inputHidden.type = "hidden";
	inputHidden.name = "ec_" + parms.fullyQualifiedECID;
	if (value !== null)
	{
		inputHidden.value = value;
	}
	div.appendChild(inputHidden);

	var input = document.createElement("INPUT");
	input.type = "text";
	div.appendChild(input);

	var ul = document.createElement("UL");
	ul.className = "mcx-selected-items";
	div.appendChild(ul);

	var divSearchResults = document.createElement("DIV");
	divSearchResults.className = "uwt-popup mcx-search-results";

	var ulSearchResults = document.createElement("UL");
	ulSearchResults.className = "uwt-menu uwt-multiselect uwt-highlight";
	divSearchResults.appendChild(ulSearchResults);
	
	var divSpinner = document.createElement("DIV");
	divSpinner.className = "uwt-spinner";
	divSearchResults.appendChild(divSpinner);

	var divPlaceholder = document.createElement("DIV");
	divPlaceholder.className = "uwt-placeholder";
	divPlaceholder.innerText = "type to search the list";
	divSearchResults.appendChild(divPlaceholder);

	div.appendChild(divSearchResults);

	new McxInstanceBrowser(div);

	return div;
};

window.addEventListener("load", function()
{
	var items = document.getElementsByClassName("mcx-instancebrowser");
	for (var i = 0; i < items.length; i++)
	{
		items[i].NativeObject = new McxInstanceBrowser(items[i]);
	}
});

window.addEventListener("click", function(e)
{
	var ibs = document.getElementsByClassName("mcx-instancebrowser");
	for (var i = 0; i < ibs.length; i++)
	{
		if (!System.CheckIfSenderIsInside(e.target, ibs[i]))
		{
			ibs[i].NativeObject.setEditing(false);
		}
	}
});