jQuery(function($){
	var selTimer;
	var selLi = -1;
	var isMSIE//@cc_on=1;

	var ksInt = 500; // number of milliseconds ajaxcall waits for more keyboard input before actually executing ajax calls

	function getFragment(){
		clearSelTimer();
		if(arguments.length > 0){
			var inp = $("#tags").get(0);
			// calculate where the cursor is (in number of characters)
			if(document.selection){
				var yourrange = inp.createTextRange();
				yourrange.setEndPoint("EndToStart", document.selection.createRange());
				var pos = yourrange.text.length;
			}
			else if(inp.selectionStart || inp.selectionStart == 0){
				var pos = inp.selectionStart;
			}
			// get number of characters in the textbox
			var l = inp.value.length;
			// only do ajax-calls if cursor is at the end of the string in the box
			if(l==pos){
				var frag = inp.value.split(' ').pop().trim();
				if(frag!=""){
					// hideHints();
					getTags(frag);
				}
			}
		}
		else {
			selTimer = setTimeout(function(){getFragment(true);}, ksInt);
		}
	}

	function clearSelTimer(){
		clearTimeout(selTimer);
	}

	function getTags(frag){
		var u = $("#xhrsearch").attr('value');
		var ajaxRequest = new AjaxRequest(u);
		ajaxRequest.addNameValuePair("wordfragment", frag);
		ajaxRequest.setPostRequest(showHints);
		ajaxRequest.sendRequest();
	}

	var handleKey = function(e){
		var kc = e.keyCode;
		var ok = false;
		if(e.ctrlKey || e.altKey || e.metaKey) return;
		switch(kc){
			case 27: // ESCAPE
			case 32: // SPACE
				hideHints();
				clearSelTimer();
				break;
			case 13: // ENTER
				selectListItem();
				break;
			case 38: // ARROW UP
				selectListItem('up');
				break;
			case 40: // ARROW DOWN
				selectListItem('down');
				break;
			case 33: //
			case 34: // "
			case 35: // #
			case 36: //
			case 37: //
			case 39: // '
				break;
			case 46: // DEL
				$("#tags").val( $("#tags").val().trim() );
				// don't break out we allow this keystroke
			case 8:  // backspace
			case 43: // cursor left
			case 45: // cursor right
			case 95:
				ok = true;
				// set allowed flag
			default:
				if(kc>=48 && kc<=57 || kc >=65 && kc<=91 || kc >=97 && kc<123 || ok){
					// pass through numbers, characters or ascii-codes that have set ok=true
					// do the ajax call
					getFragment();
				}
				else {
					// cancel keystroke
					e.preventDefault;
				}
		}
	}

	function selectListItem(direction){
		// handles cursor up and down
		var lis = $("#knowntags li"); // all li's
		switch(direction){
			case "down":
				if(selLi>=0){
					lis.eq(selLi).removeClass("selected");
				}
				selLi++;
				if(selLi>=lis.length){
					selLi = 0;
				}
				lis.eq(selLi).addClass("selected");
				fixScroll(lis.get(selLi));
				break;
			case "up":
				if(selLi>=0){
					lis.eq(selLi).removeClass("selected");
				}
				selLi--;
				if(selLi<0){
					hideHints();
				}
				else{
					lis.eq(selLi).addClass("selected");
					fixScroll(lis.get(selLi));
				}
				break;
			default:
				if(selLi>=0 && selLi<lis.length){
					var v = $("#tags").val().trim(); // get trimmed textbox value
					var t = v.split(' '); // split text in box on space into an array
					t.pop(); // remove the last (we are completing this word)
					t.push(lis.eq(selLi).text()); // add value of list-item to array
					$("#tags").val(t.join(" ")); // place new array's text value back in the box
					hideHints(); // hide the hints
				}
		}
	}

	// fix scroll top
	function fixScroll(li){
		$("#knowntags").get(0).scrollTop = li.offsetTop;
	}

	function hideHints(){
		selLi = -1;
		$("#knowntags").addClass("hidden");
	}

	function showHints(){
		selLi = -1;
		var lis = $("#knowntags li");
		if(lis.length!=0){
			$("#knowntags").removeClass("hidden");
		}
		else {
			hideHints();
		}
	}

	function fixIEKeyPress(e){
		var kc = e.keyCode;
		if(kc==13){
			selectListItem();
		}
	}

	$("#tags").keydown(handleKey);
});
