TR.suggestions = function() {
    var id = "#nft";
    var sid = "#nfts";
    var bottomUp = true;

    var cache = [];

    function initSuggestions(x_bottomUp) {
	bottomUp = x_bottomUp;
	$(id)
	    // .focus()
            .focus(function() {	$(".shadow").hide(); })
	    .blur(function() { 	if ($(id).val().length == 0) { $(".shadow").show(); } })
	    .keypress(function(event) { return handleKeypress(event); })
	    .keyup(function(event) { return handleKeyup(event); })
	;

       $(".shadow")
	 // .hover(function() { $(id).focus(); }, function() {})
	 .click(function() { $(id).focus(); })
       ;

    }

    function findInCache(nft) {
	for (var i = 0; i < cache.length; i++) {
	    if (cache[i].nft == nft) {
		return cache[i];
	    }
	}
	return null;
    }
    
    function requestSuggestions() {
	var nft = $(id).val();
	if (nft.length < 3) {
	    makeInvisible();
	    return;
	}
	var result = findInCache(nft);
	if (result) {
	    displaySuggestions(result);
	}
	else {
	    var url = L("/suggestions/json/" + nft);
	    $.getJSON(url, {}, function(result) { handleSuggestions(result); });
	}
    }

    function handleSuggestions(result) {
	while (cache.length >= 50) {
	    cache.shift();
	}
	cache.push(result);
	displaySuggestions(result);
    }
	    
    function displaySuggestions(result) {
	var nfts = $(sid);
	$(nfts)
	    .empty()
	    .unbind("mousemove")
	;
	if (!result) {
	    return;
	}
	if (!$(id).val().match("^" + result.nft)) {
	    return;
	}
	var terms = result.terms;
	if (terms.length < 1) {
	    makeInvisible();
	    return;
	}

	makeVisible();
	for (var i = 0; i < terms.length; i++) {
	    // var text = terms[i];
	    var term = terms[i];
	    var text = term[0];
	    var count = term[1];

	    foo(nfts, 
		"<li class='sug'>" + 
		"<span class='text'>" + text + "</span>" + 
		"<span class='count'>" + count + " studies</span>" + 
		"</li>");
	}


	foo(nfts,
	    "<li class='close'>" + 
	    "<a href='#' onclick='TR.suggestions.close(); return false;'>close</a>" + 
	    "</li>");

	$(nfts)
	    .one("mousemove", function() {
		$("li", nfts)
		    .hover(
			function() { select(this); },
			function() {}
		    )
		;
		$(".sug", nfts)
		    .click(function() { use(); })
		;
	    })
	;
    }

    function foo(whom, what) {
	if (bottomUp) {
	    $(whom).prepend(what);
	}
	else {
	    $(whom).append(what);
	}
    }

    function handleKeypress(event) {
	var selected = $(sid + " .selected");
	if (event.keyCode == 13) { // enter
	    if (selected.size() > 0) {
		event.preventDefault();
    		if (selected.hasClass("close")) {
		    close();
		}
		else {
		    $(id).removeAttr("copy");
		    makeInvisible();
		    requestSuggestions();
		}
	    }
	}
	$(".shadow").hide();
    }

    function handleKeyup(event) {
	if (event.keyCode == 13) { // enter
	    // nothing, handled by keypress
	}
	else if (event.keyCode == 40) { // down arrow
	    copyValue();
	    if (isVisible()) {
		selectNext();
	    }
	    else {
		requestSuggestions();
	    }
	}
	else if (event.keyCode == 38) { // up arrow
	    copyValue();
	    if (isVisible()) {
		selectPrev();
	    }
	    else {
		requestSuggestions();
	    }
	}
	else if (event.keyCode == 27) { // escape
	    makeInvisible();
	    restoreValue();
	}
	else {
	    requestSuggestions();
	}
	/*
	if ($(id).val().length == 0) {
	    $(".shadow").show();
	}
        */
    }



    function close() {
	restoreValue();
	makeInvisible();
	$(id).focus();
    }

    function isVisible() {
	return $(sid).is(":visible");
    }
    
    function makeVisible() {
	$(sid).fadeIn(250);
    }
    
    function makeInvisible() {
	$(sid).fadeOut(250);
    }
    
    
    function copyValue() {
	if (typeof($(id).attr("copy")) == "undefined") {
	    $(id).attr("copy", $(id).val());
	}
    }
    
    function restoreValue() {
	if (typeof($(id).attr("copy")) != "undefined") {
	    $(id).val($(id).attr("copy"));
	    $(id).removeAttr("copy");
	}
    }

    function use() {
    	$(id).removeAttr("copy");
	$(id).val($(sid + " .selected .text").html());
	$(id).closest("form").submit();
	makeInvisible();
	requestSuggestions();
    }

    function select(target) {
	$(".sug", sid).removeClass("selected");
	$(target).addClass("selected");
    }

    function selectNext() {
	var selected = $(sid + " .selected");
	$(selected).removeClass("selected");
	var next = null;
	if (selected.size() > 0) {
	    next = $(selected).next("li");
	    if (next.size() == 0) {
		next = null;
	    }
	}
	if (!next) {
	    next = $(sid + " li:first")
	}
	next.addClass("selected");
	if (next.hasClass("close")) {
	    restoreValue();
	}
	else {
	    $(id).val($(sid + " .selected .text").html());
	}
    }
    
    function selectPrev() {
	var selected = $(sid + " .selected");
	$(selected).removeClass("selected");
	var prev = null;
	if (selected.size() > 0) {
	    prev = $(selected).prev("li");
	    if (prev.size() == 0) {
		prev = null;
	    }
	}
	if (!prev) {
	    prev = $(sid + " li:last");
	}
	prev.addClass("selected");	
	if (prev.hasClass("close")) {
	    restoreValue();
	}
	else {
	    $(id).val($(sid + " .selected .text").html());
	}
    }
    
    function dlog(text) {
	TR.utils.dlog(text);
    }

    return {
	init: function(bottomUp) { $(document).ready(function() { initSuggestions(bottomUp); }); }
	, close: close
    };
}();
