 //DEFINITELY CAN BE SAFELY COMPRESSED WITH http://dynamic-tools.net/toolbox/javascript_compressor/

//TODO:
//1] DON'T auto-select the first element (so that enter can be hit) and the form submitted even if the list pops up
//2] can't, at present, tinker about with the list box and then click the submit button. (button doesn't work)
//(Is the above [2] fixed??!??)

//Rules for text inputs that are classed as "autocomplete"
var autocompleteRules =
{
	'.autocomplete' : function(element)
	{
		//Need to track "in a form or not" because ENTER key will submit a form (when in one of that form's controls)
		if(document.getElementsBySelector('form > #' + element.id))
		{
			element.setAttribute('isInAForm', 'yes');
		}
		
		else
		{
			element.setAttribute('isInAForm', 'no');
		}
		
		//Do it here because it isn't really valid XHTML (Opera tends to ignore it wherever it appears though)
		element.setAttribute('autocomplete', 'off');
				
		var ajaxFunction = element.className.split(' ')[1];	//So must always say class="autocomplete whatever" ('whatever' being the ajax function of choice)
		
		var keyboardEvent = 'onkeyup';	//or onkeydown or what?
		if(window.opera)	//Opera's keyboard event stuff is cheesed...
		{
			keyboardEvent = 'onkeyup';	//or onkeydown or what?
		}
		
		element.onblur = function(event)
		{
			//alert(event.screenX);
			hideElement(element.id + '_autocomplete_box');
			
			if(element.getAttribute('isInAForm') == 'yes')
			{
				//enableParentFormsOnsubmit(element.id);
			}
		};
		
		//Is this thing actually working? It *appears* to...
		element.onkeydown = function(event)	//Ensure that pressing ENTER doesn't submit the form (which we may or may not have) if the autocomplete box is open
		{
			var theEvent = event || window.event;
			
			if(theEvent.keyCode == 13 && element.getAttribute('isInAForm') == 'yes')
			{
				return false;
			}
		};
		
		element[keyboardEvent] = function(event)
		{
			var theEvent = event || window.event;
			
			if(element.getAttribute('isInAForm') == 'yes')
			{
				//disableParentFormsOnsubmit(element.id);
			}
			
			
			switch(theEvent.keyCode.toString())	//Need toString() and quotes on the following case numbers only for crunchobfuscation!
			{
				
				case '27':	//ESC
					hideElement(element.id + '_autocomplete_box');
					return false;	//Need?
					break;
					
				case '38':	//UPARROW
					//selectUp(element.id + '_autocomplete_box');
					if(document.getElementById(element.id + '_autocomplete_box') && document.getElementById(element.id + '_autocomplete_box').getAttribute('hidden') == 'no')
					{
						selectUp(element.id);
					}
					//return;
					break;
					
				case '40':	//DOWNARROW
					//selectDown(element.id + '_autocomplete_box');
					if(document.getElementById(element.id + '_autocomplete_box') && document.getElementById(element.id + '_autocomplete_box').getAttribute('hidden') == 'no')
					{
						selectDown(element.id);
					}
					//return;
					break;
				
				case '13':	//ENTER
					
					//alert(element.getAttribute('isInAForm'));
					//alert('enter');
					
					
					
					
					var returnVal = acceptSelectedItem(element.id);
					
					
					
					
					if(returnVal == false)	//Autocomplete box is open--------
					{
						//disableParentFormsOnsubmit(element.id);
						//alert('autocomplete box is open');
					}
					
					else	//Autocomplete box is NOT visible or has not been created yet--------
					{
						
						//alert('autocomplete box is hidden/not extant');
						
						if(element.getAttribute('isInAForm') == 'yes')
						{
							//enableParentFormsOnsubmit(element.id);
							
							var parentForm = getFirstParentNode(element, 'form'); 
							if(typeof parentForm.onsubmit == 'function')
							{
								parentForm.onsubmit.call();	//form.submit() does not, in Firefox at least, appear to trigger any onsubmit functions!
							}
							parentForm.submit();
						}



						//alert('restoring onsubmit');
						
						//
						//
						//
						//
					
						//return true;
						
						//alert('autocomplete box is NOT open');
						
						
					}
					
					
					return returnVal;
					//return false;
					//return;
					break;
					
				default:
					makeAutocompleteBoxIfAppropriate(element.id);
					a.jax({job:ajaxFunction, responseType:'text', reaction:autocompleteReaction, start:element.value, autocompleteBoxId:element.id + '_autocomplete_box'});
					//return;
					break;
			}
		};
	},
	
	'.autocompleteitem' : function(element)
	{
		//Not getting called? (NO! that was an "onblur of textbox" type problem...)
		element.onclick = function()
		{
			var textboxId = element.id.replace(/_autocomplete_box_\d{1,}$/i, '');
			
			
			
			acceptSelectedItem(textboxId);
			
			enableTextboxOnblur(textboxId);
			document.getElementById(textboxId).focus();
			
			return false;	//cancel actual mouseclick event so that the onblur of the textbox doesn't trigger
		};
		
		element.onmouseover = function()
		{
			//this.innerHTML = "BLAH!";
			
			//id of an autocompleteitem is: textbox.id + '_autocomplete_box_' + index	
			
			//Bomb out if element.className.contains('unselectable')
			if(element.className.match(/unselectable/i))
			{
				return;
			}	
			
			
			
			var textboxId = element.id.replace(/_autocomplete_box_\d{1,}$/i, '');
			
			disableTextboxOnblur(textboxId);
			
			unselectCurrentlySelectedItem(textboxId + '_autocomplete_box');
			selectSpecificItem(textboxId, element.id, false);
			
		};
		
		element.onmouseout = function()
		{
			var textboxId = element.id.replace(/_autocomplete_box_\d{1,}$/i, '');
			enableTextboxOnblur(textboxId);
		};
		/*,*/
		
		
	}
};

Behaviour.register(autocompleteRules);

//
function autocompleteReaction(responseText)
{
	var parts = responseText.split('//');
	var boxId = parts[0];
	var matchesText = parts[1];
	
	document.getElementById(boxId).innerHTML = '';
	
	if(matchesText == '')
	{
		hideElement(boxId);
		
		//Reset hidden ID box value
		var textboxId = boxId.replace(/_autocomplete_box$/, '');
		var hiddenIdBoxId = textboxId + '_id';
		var idBox = document.getElementById(hiddenIdBoxId);
		if(idBox)
		{
			idBox.value = '';
		}
		
		return;
	}

	
	showElement(boxId);
	
	//alert(responseText);
	var matches = matchesText.split('|');
	
	var setSelected = false;
	var matchesLength = matches.length;
	for(var loop = 0; loop < matchesLength; loop++)
	{
		var parts = matches[loop].split('}');
		
		var entityId = parts[0];
		
		var fulltext = matches[loop];
		var text = parts[1];
		
		var theClass = '';
		var selected = '';
		var alt = '';
		
		if(loop % 2 == 1)
		{
			alt = ' alt';
		}
		
		if(fulltext == 'UNSELECTABLE')
		{
			text = '<em>Did you mean?</em>';
			theClass = ' unselectable';
		}
		
		else
		{
			if(!setSelected)
			{
				selected = ' selected';
				setSelected = true;
			}
			
		}
		
		
		
		
		
		var matchLine = '<div class="autocompleteitem' + selected + theClass + alt + '" id="' + boxId + '_' + loop + '" rawvalue="' + text + '" entityid="' + entityId + '">' + text + '</div>';
		//document.getElementById(boxId).innerHTML += matches[loop] + '<br/>';
		document.getElementById(boxId).innerHTML += matchLine;
	}
}

//Make it initially hidden
function makeAutocompleteBoxIfAppropriate(textboxId)
{
	if(!document.getElementById(textboxId + '_autocomplete_box'))
	{
		var textbox = document.getElementById(textboxId);
		
		var autocompleteBox = document.createElement('div');
		autocompleteBox.id = textboxId + '_autocomplete_box';
		
		//var textboxWidth = Element.getWidth(textbox);
		var coords = Position.cumulativeOffset(textbox);	//PROTOTYPE
		var textboxBottomLeftX = coords[0];
		var textboxBottomLeftY = coords[1] + Element.getHeight(textbox);	//PROTOTYPE
		
		autocompleteBox.className = 'autocompletebox';
		
		autocompleteBox.style.position = "absolute";
		autocompleteBox.style.left = textboxBottomLeftX + 'px';
		autocompleteBox.style.top = textboxBottomLeftY + 'px';
		//autocompleteBox.style.width = textboxWidth + 'px';
		autocompleteBox.style.display = 'none';
		
		autocompleteBox.setAttribute('hidden', 'yes');
				
		document.body.appendChild(autocompleteBox);
	}
}

//
function hideElement(elementId)
{
	var el = document.getElementById(elementId);
	
	if(!el){return;}
	
	el.style.display = 'none';
	el.setAttribute('hidden', 'yes');
}

//
function showElement(elementId)
{
	var el = document.getElementById(elementId);
	
	if(!el){return;}
	
	el.style.display = 'block';	//Or remember previous setting and use that?
	el.setAttribute('hidden', 'no');
}

//
function selectUp(textboxId)
{
	var autocompleteBoxId = textboxId + '_autocomplete_box';
	
	var autocompleteBox = document.getElementById(autocompleteBoxId);
	
	var selectedSpan = document.getElementsBySelector('div#' + autocompleteBoxId  + ' .selected')[0];
	
	//var allSpans = document.getElementsBySelector('div#' + autocompleteBoxId  + ' .autocompleteitem');
	
	var selectedIndex = selectedSpan.id.split('_');
	selectedIndex = parseInt(selectedIndex[selectedIndex.length - 1], 10);
	
	var newIndex = selectedIndex - 1;
	
	//Max out at top
	if(selectedIndex == 0)
	{
		return;
	}
	
	var newItemId = autocompleteBoxId + '_' + newIndex;
	
	
	//Bomb out if newItem.className.contains('unselectable')
	if(document.getElementById(newItemId).className.match(/unselectable/i))
	{
		return;
	}	
	
	
	
	//Unselect current one
	//selectedSpan.className = 'autocompleteitem';
	selectedSpan.className = selectedSpan.className.replace(/selected/i, '');
	

	//Select above one
	/*
	var aboveSpan = document.getElementById(autocompleteBoxId + '_' + newIndex);
	
	aboveSpan.className = 'autocompleteitem selected';
	
	document.getElementById(textboxId).value = aboveSpan.innerHTML;
	*/
		
	selectSpecificItem(textboxId, newItemId);
}

//
function selectDown(textboxId)
{
	var autocompleteBoxId = textboxId + '_autocomplete_box';
	
	var autocompleteBox = document.getElementById(autocompleteBoxId);
	
	var selectedSpan = document.getElementsBySelector('div#' + autocompleteBoxId  + ' .selected')[0];
	
	//var allSpans = document.getElementsBySelector('div#' + autocompleteBoxId  + ' .autocompleteitem');
	
	var selectedIndex = selectedSpan.id.split('_');
	selectedIndex = parseInt(selectedIndex[selectedIndex.length - 1], 10);
	
	var newIndex = selectedIndex + 1;
	
	//Max out at bottom
	if(!document.getElementById(autocompleteBoxId + '_' + newIndex))
	{
		return;
	}
	
	var newItemId = autocompleteBoxId + '_' + newIndex;
	
	//Bomb out if newItem.className.contains('unselectable')
	if(document.getElementById(newItemId).className.match(/unselectable/i))
	{
		return;
	}
	
	//Unselect current one
	//selectedSpan.className = 'autocompleteitem';
	selectedSpan.className = selectedSpan.className.replace(/selected/i, '');
	
	//Select below one
	/*
	var belowSpan = document.getElementById(autocompleteBoxId + '_' + newIndex);
	
	belowSpan.className = 'autocompleteitem selected';
	
	document.getElementById(textboxId).value = belowSpan.innerHTML;
	*/
	
	selectSpecificItem(textboxId, newItemId);
}

//
function unselectCurrentlySelectedItem(autocompleteBoxId)
{
	var currentlySelectedItem = document.getElementsBySelector('div#' + autocompleteBoxId  + ' .selected')[0];
	//currentlySelectedItem.className = 'autocompleteitem';
	currentlySelectedItem.className = currentlySelectedItem.className.replace(/selected/i, '');
}

//
function selectSpecificItem(textboxId, itemId, reflectInTextbox)	//reflectInTextbox is optional
{
	var item = document.getElementById(itemId);
	
	//item.className = 'autocompleteitem selected';
	item.className += ' selected';
	
	if(reflectInTextbox != false)
	{
		//document.getElementById(textboxId).value = item.innerHTML;	//Using innerHTML reproduces ampersands as "&amp;" (and etc)
		document.getElementById(textboxId).value = item.getAttribute('rawvalue');
	}
}

//Put the currently selected item into the initial textbox
function acceptSelectedItem(textboxId)
{
	var autocompleteBoxId = textboxId + '_autocomplete_box';
	var autocompleteBox = document.getElementById(autocompleteBoxId);
	
	//Surreptitiously stash the entity ID. Heeheehee!! (^O^)/
	var hiddenIdBoxId = textboxId + '_id';
	var idBox = document.getElementById(hiddenIdBoxId);
	
	
	//alert(autocompleteBox.getAttribute('hidden'));
	
	//Accept the selected item only if the autocompletebox is currently visible
	if(autocompleteBox && autocompleteBox.getAttribute('hidden') == 'no')
	{
		var selectedSpan = document.getElementsBySelector('div#' + autocompleteBoxId  + ' .selected')[0];
		
		//document.getElementById(textboxId).value = selectedSpan.innerHTML;	//&/&amp; problem
		document.getElementById(textboxId).value = selectedSpan.getAttribute('rawvalue');	//&/&amp; problem
		
		if(idBox)
		{
			idBox.value = selectedSpan.getAttribute('entityid');
		}
		
		hideElement(autocompleteBoxId);
		
		
		return false;	//DON'T follow through with actual event
	}
	
	return true;	//DO follow through with actual event
}

//
function disableParentFormsOnsubmit(textboxId)
{
	var parentForm = getFirstParentNode(document.getElementById(textboxId), 'form');
	
	
	if(!parentForm.originalOnsubmit)
	{
		parentForm.originalOnsubmit = parentForm.onsubmit;
	}
	
	parentForm.onsubmit = function(){return false;};
}

//
function enableParentFormsOnsubmit(textboxId)
{
	var parentForm = getFirstParentNode(document.getElementById(textboxId), 'form');
	
	parentForm.onsubmit = parentForm.originalOnsubmit || parentForm.onsubmit;
}

//
function disableTextboxOnblur(textboxId)
{
	var textbox = document.getElementById(textboxId);
	
	if(!textbox.originalOnblur)
	{
		textbox.originalOnblur = textbox.onblur;
	}
	
	textbox.onblur = null;
}

//
function enableTextboxOnblur(textboxId)
{
	var textbox = document.getElementById(textboxId);
	
	textbox.onblur = textbox.originalOnblur || textbox.onblur;
}


//Needs to go in a "library.js" type file
//Cheese!
function getFirstParentNode(element, parentTagName)
{
	var done = false;
	var currentNode = element.parentNode;
	var matchingNode;
	
	while(!done)
	{
		if(currentNode.tagName.toUpperCase() == parentTagName.toUpperCase())
		{
			done = true;
			matchingNode = currentNode;
		}
		
		else
		{
			currentNode = currentNode.parentNode;
		}
	}
	
	return matchingNode;
}