/*
 * inputAssistant - The search assistant for text input fields
 * Copyright (C) 2010 Ipportunities
 *
 * This is the integration file for JavaScript.
 *
 * It defines the inputAssistant class that can be used to create inputAssistant
 * instances in a HTML page in the client side.
 *
 * requires jquery
 * see http://www.jquery.com
 *
 */


// array to keep track of the input assistants
var assistants = new Array();

var userAgent = navigator.userAgent.toLowerCase();
var browser = {version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1], safari:/webkit/.test(userAgent), opera:/opera/.test(userAgent), msie:/msie/.test(userAgent)&&!/opera/.test(userAgent), mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};
//alert(browser.version);


/*
* creates an input assistant and binds it to the parent input element
*/
function bindAssistant(inputId, containerId, path)
{
	var assistant = new inputAssistant(inputId, containerId, path);

	if(! (document.getElementById(inputId) && document.getElementById(containerId)) )
	{
		return false;
	}
	
	var el = document.getElementById(inputId);
	var type = "keyup";
	//var handle = assistant.update;
	var handle = _updateInputAssistant;
	
	if(el.addEventListener)
	{
		el.addEventListener(type, handle, false);
	} else if(el.attachEvent)
	{
		el.attachEvent("on" + type, handle);
	}
	if(document.getElementById(inputId))
	{
		assistants[inputId] = assistant;
	}
}

/*
* keyup handler of the parent element
*/
function _updateInputAssistant(event)
{
	//alert(event);
	var el = event.target ? event.target : event.srcElement;
	
	var value = new String(el.value).replace(/^\s*/g, "");
	//alert('-'+value+'-');
	
	if(assistants[el.getAttribute("id")])
	{
		var assistant = assistants[el.getAttribute("id")];
		
		if(27 == event.keyCode)
		{
			assistant.close();
			return;
		}

		if(0 == new String(value).length)
		{
			assistant.close();
		} else
		{
			if(!assistant.isOpen())
			{
				var firstChar = new String(value).charAt(0);
				if(assistant.isLoaded(firstChar))
				{
					assistant.FirstChar = firstChar;
				} else
				{
					assistant.getInfo(firstChar);
				}
				assistant.open();
			}
			assistant.suggest(value);			

			if(assistant.isOpen())
			{
				assistant.proceedEvent(event);
			}
		}
	}
}


/*
* close all assistants if escape key is pressed
*/
var el = document;
var type = "keyup";
var handle = _escapeHandler;

if(el.addEventListener)
{
	el.addEventListener(type, handle, false);
} else if(el.attachEvent)
{
	el.attachEvent("on" + type, handle);
}

/*
* handles escape key to close the open assistants
*/
function _escapeHandler(event)
{
	if(27 == event.keyCode)
	{
		closeAssistants();
	}
}

/*
* closes all assistants
*/
function closeAssistants()
{
	for(var ia in assistants)
	{
		assistants[ia].close();
	}
}


/*
* selects value from the list
*/
function _ia_selectValue(id, value)
{
	document.getElementById(id).value = value;
	document.getElementById(id).focus();
	if(assistants)
	{
		if(assistants[id])
		{
			assistants[id].close();
		}
	}
}


/*
* gets actual offsets of the element
*/
function _getOffsets(el_id)
{
	var el = document.getElementById(el_id);
	
	var offsetLeft = 0;
	var offsetTop = 3;
	
	//if(el.offsetParent)
	//{
		do
		{
			offsetLeft += el.offsetLeft;
			offsetTop += el.offsetTop;
		}
		while(el = el.offsetParent);
		return [offsetLeft, offsetTop];
	//}
}



// inputAssistant Class
var inputAssistant = function(parentId, containerId, infoFile)
{
	// Properties
	this.ie = browser.msie;
	
	this.InfoFile = infoFile;
	
	this.ContainerId = containerId;
	this.ParentId = parentId;
	
	this.FirstChar = "";
	this.AllOptions = new Array();
	this.Options = new Array();
	
	this.LoadedChars = new Array();
	
	this.idPrefix = "_ia_" + parentId + "_";
	
	this.ClassTD = "input_assistant";
	this.ClassTDhover = "input_assistant_hover";
	
	this.MaxOptions = 8;
	
	this.RowHeight = 25;
	
	this.Width = 300;
	this.Height = 25;
		
	this.Top = 0;
	this.Left = 0;
	
	this.BorderWidth = 1;

	if(document.getElementById(this.ParentId))
	{
		var parent = document.getElementById(this.ParentId);
		//alert(parent.offsetHeight);

		this.Width = parent.offsetWidth - 2 - (this.ie ? 0 : (2 * this.BorderWidth));
		
		this.setPosition();
	}

	if(document.getElementById(this.ContainerId))
	{
		var container = document.getElementById(this.ContainerId);
		
		container.className = "input_assistant_container";
		
		container.style.width = this.Width;
		container.style.height = this.Height;
		
		container.style.borderWidth = this.BorderWidth;
	}

	this.SelectedIndex = null;

	this.isShown = false;

	this.Header = "<table border='0' cellspacing='0' cellpadding='0' style='width:" + this.Width + "px;'>";
	this.Footer = "</table>";
	this.Line = "<tr><td id='" + this.idPrefix + "%index%' class='" + this.ClassTD + "' onmouseover='this.className=\"" + this.ClassTDhover + "\"' onmouseout='this.className=\"" + this.ClassTD + "\"' onclick='_ia_selectValue(\"" + this.ParentId + "\", \"%option%\");' style='height:" + this.RowHeight + "px;'>%option%</td></tr>";	
}



/**
* sets the classes
*/
inputAssistant.prototype.setClasses = function(classTD, classTDhover)
{
	this.ClassTD = classTD || "input_assistant";
	this.ClassTDhover = classTDhover || "input_assistant_hover";
}

/**
* sets the maximal number of options
*/
inputAssistant.prototype.setMaxOptions = function(maxOptions)
{
	this.MaxOptions = maxOptions;
}


/**
* sets the position of the assistant
*/
inputAssistant.prototype.setPosition = function()
{
	var offsets = _getOffsets(this.ParentId);

	var parent = document.getElementById(this.ParentId);

	this.Top = parseInt(offsets[1]) + parent.offsetHeight;
	this.Left = parseInt(offsets[0]);
	
	if(document.getElementById(this.ContainerId))
	{
		var container = document.getElementById(this.ContainerId);
		
		container.style.top = this.Top + "px";
		container.style.left = this.Left + "px";
	}
}


/**
* opens the assistant
*/
inputAssistant.prototype.open = function()
{
	if(document.getElementById(this.ContainerId))
	{
		this.setPosition();
		this.isShown = true;
		document.getElementById(this.ContainerId).style.display = "block";
	}
}
/**
* closes the assistant
*/
inputAssistant.prototype.close = function()
{
	this.isShown = false;
	
	if(document.getElementById(this.ContainerId))
	{
		var container = document.getElementById(this.ContainerId);
		container.scrollTop = 0;
		container.style.display = "none";
		
		this.SelectedIndex = null;
	}
}

/**
* checks if the assistant is open
*/
inputAssistant.prototype.isOpen = function()
{
	return this.isShown;
}

/**
* checks if the list of suggestions for the given first letter is already loaded
*/
inputAssistant.prototype.isLoaded = function(firstChar)
{
	return this.LoadedChars[firstChar];
}


/**
* reads the info file
*/
inputAssistant.prototype.readInfoFile = function()
{
	var data;
	var query = "";

	$.ajax({
		type: "GET",
		url: this.InfoFile + this.FirstChar + ".cache?nd=" + new Date().getTime(),
		data: query,
		async: false,
		timeout: 5000,
		success: function(reply)
			{
				//alert(reply);
				data = reply;
			},
		error: function(e)
			{
				data = "";
				//alert(e);
			}
	});
	return data;
}

/**
* gets list of suggestions for the first letter
*/
inputAssistant.prototype.getInfo = function(firstChar)
{
	this.FirstChar = firstChar;
	var reply = this.readInfoFile();
	if("" == reply)
	{
		var options = new Array();
	} else
	{
		var options = new String(reply).split(",");
	}

	this.LoadedChars[this.FirstChar] = true;

	this.AllOptions[this.FirstChar] = options;
	this.setOptions(options);
}


/**
* sets options array to work with
*/
inputAssistant.prototype.setOptions = function(options)
{
	this.Options = options;

	if(document.getElementById(this.ContainerId))
	{
		var container = document.getElementById(this.ContainerId);
		
		var content = this.Header;
		for(var io = 0; ( (io < this.Options.length) && (io < this.MaxOptions) ); io ++)
		{
			var line = new String(this.Line).replace(/%option%/g, this.Options[io]).replace(/%index%/g, io);
			content += line;
		}
		content += this.Footer;
		
		container.innerHTML = content;
	}
}



/**
* processes a key event
*/
inputAssistant.prototype.proceedEvent = function(event)
{
	if(40 == event.keyCode)
	{
		this.next();
	}
	if(38 == event.keyCode)
	{
		this.prev();
	}
	if(13 == event.keyCode)
	{
		this.setValue();
	}
}


/**
* switches to the next option
*/
inputAssistant.prototype.next = function()
{
	if(0 == this.Options.length)
	{
		return false;
	}
	
	if(this.MaxOptions > this.Options.length)
	{
		var lastIndex = this.Options.length - 1;
	} else
	{
		var lastIndex = this.MaxOptions - 1;
	}

	if(null == this.SelectedIndex)
	{
		this.SelectedIndex = 0;
	} else
	{
		this.SelectedIndex ++;
		
		if(this.SelectedIndex > lastIndex)
		{
			this.SelectedIndex = 0;
		}
	}
	
	this.selectOption(this.SelectedIndex);
}

/**
* switches to the previous option
*/
inputAssistant.prototype.prev = function()
{
	if(0 == this.Options.length)
	{
		return false;
	}
	
	if(this.MaxOptions > this.Options.length)
	{
		var lastIndex = this.Options.length - 1;
	} else
	{
		var lastIndex = this.MaxOptions - 1;
	}
	//alert(lastIndex);
	if(null == this.SelectedIndex)
	{
		this.SelectedIndex = lastIndex;
	} else
	{
		this.SelectedIndex --;
		
		if(this.SelectedIndex < 0)
		{
			this.SelectedIndex = lastIndex;
		}
	}
	
	this.selectOption(this.SelectedIndex);
}

/**
* selects the given option based on index
*/
inputAssistant.prototype.selectOption = function(index)
{
	document.getElementById(this.idPrefix + index).className = this.ClassTDhover;
	document.getElementById(this.idPrefix + index).focus();
	
	if(document.getElementById(this.ContainerId))
	{
		var container = document.getElementById(this.ContainerId);
		container.scrollTop = (this.SelectedIndex - 1) * this.RowHeight;
	}
	var parent = document.getElementById(this.ParentId);
	parent.focus();
}

/**
* trims the selection based on input
*/
inputAssistant.prototype.suggest = function(input)
{
	var options = new Array();
	var count = 0;
	
	for(var io = 0; io < this.AllOptions[this.FirstChar].length; io ++)
	{
		if(input == new String(this.AllOptions[this.FirstChar][io]).substring(0, new String(input).length))
		{
			options[count++] = this.AllOptions[this.FirstChar][io];
		}
	}

	this.setOptions(options);
	
	if(document.getElementById(this.ContainerId))
	{
		var container = document.getElementById(this.ContainerId);
		//alert(parseInt(container.style.borderWidth));
		
		if(this.Options.length > this.MaxOptions)
		{
			var height = (this.RowHeight + (this.ie ? 4 : 0)) * this.MaxOptions;
		} else
		{
			var height = (this.RowHeight + (this.ie ? 4 : 0)) * this.Options.length;
		}
		//var newHeight = height + (this.ie ? (2 * parseInt(container.style.borderWidth)) : 0)
		//container.style.height = newHeight + "px";
		container.style.height = height + "px";
	}
	
	if(0 == this.Options.length)
	{
		this.close();
	}

}

/**
* sets value of the parent input field
*/
inputAssistant.prototype.setValue = function()
{
	if(document.getElementById(this.ParentId))
	{
		var parent = document.getElementById(this.ParentId);
		if(null != this.SelectedIndex)
		{
			parent.value = this.Options[this.SelectedIndex];
		}
		
		this.close();
		parent.focus();
	}
}

