(function ($) {
	var REGEX_HACK = '<>';

	$(function () {
		$('.searchable').each(function () {
			var searchBox = $('.searchbox', this);
			var items = $('.grouping > ul > li', this).addClass('result');
			var groupings = $('.grouping', this);

			var searchTerm = searchBox.val();

			function doSearch() {
				if (searchBox.val() != searchTerm) {
					// replace trims the string
					searchTerm = searchBox.val();

					var terms = [];
					var termsStrings = searchTerm.replace(/^\s+|\s+$/, '').split(/\s+/);

					for (var i = 0; i < termsStrings.length; i++) {
						if (termsStrings[i].length > 0) {
							terms.push({
								'simple': new RegExp(termsStrings[i], 'ig'),
								'replacer': new RegExp('\\b(' + termsStrings[i] + ')\\b(?=[^\>]*?\<)', 'ig')
							});
						}
					}

					items.each(function () {
						var item = $(this);
						var shouldHide = false;

						// Remove existing hightlights
						item.find('.search_highlight').each(function () {
							var highlight = $(this);
							highlight.after(highlight.html());
							highlight.remove();
						});

						for (var i = 0; i < terms.length; i++) {
							if (!item.text().match(terms[i]['simple'])) {
								shouldHide = true;
							} else {
								var newHTML = (item.html() + REGEX_HACK).replace(terms[i]['replacer'], '<span class="search_highlight">$1</span>');
								item.html(newHTML.substring(0, newHTML.length - REGEX_HACK.length));
							}
						}

						if (shouldHide) {
							item.removeClass('result');
							if (item.css('display') != 'none') {
								item.slideUp();
							}
						} else {
							item.addClass('result');
							if (item.css('display') == 'none') {
								if (item.parents('.grouping').css('display') == 'none') {
									item.show();
								} else {
									item.slideDown();
								}
							}
						}
					});

					// Show/hide groupings
					groupings.each(function () {
						var grouping = $(this);
						if (grouping.find('.result').size() == 0) {
							grouping.slideUp();
						} else {
							grouping.slideDown();
						}
					});
				}
			}

			var searchTimeout;

			searchBox.keyup(function () {
				clearTimeout(searchTimeout);
				searchTimeout = setTimeout(doSearch, 500);
			});
		});
	});
})(jQuery);
