// TODO: Capture arrow keys

var SAYT = function() { /*namespace*/
	// Private
	var _initialised = false;
	
	var _whereAmI = null;
	var _whereConfig = null;
	
	var _lastAjax = null;
	var _lastVal = null;
	var _lastSrcEl = null;
	var _hideHdl = null;
	
	function _gotSAYT(success, data, arg, hash)
	{
		if (_lastAjax != hash)
			return;
		_lastAjax = null;
		if (!success)
		{
			_hideSaytLayer();
			return;
		}
		
		arg.srcEl.focus();
		
		var lines = data.toString().split("\n");
		lines[0] = lines[0].trim();
		if (lines.length < 1)
			lines = new Array('-99', 'Failed to get data');
		else if (lines.length == 1 && lines[0] != '0')
			lines = new Array('-98', 'Invalid data');
		
		if (lines[0] < 0)
		{
			results = '<table id="sayt_error"><tr><td>Error ' + -lines[0] + (lines.length > 1 ? ': ' + lines[1] : '') + '</td></tr></table>';
		}
		else
		{
			results = '<table id="sayt_results"><tbody>';
			var count = 0;
			for (var i = 1; i < lines.length; ++i)
			{
				var parts = lines[i].split("\t");
				if (parts.length > 1)
				{
					var display = parts[1];
					if (parts.length > 2)
						display = parts[2];
					
					if (parts[0].length == 0)
						parts[0] = 'javascript:document.getElementById(\'' + arg.srcEl.id + '\').value = \'' + parts[1] + '\';void(0);';
					if (display.substring(0, 3).toLowerCase() != '<a ')
						display = '<a href="' + parts[0] + '">' + display.trim() + '</a>';
					results += '<tr value="' + parts[1] + '"><td>' + display.trim() + '</td></tr>';
					++count;
				}
			}
			results += '</tbody><tfoot><tr><td>'
			
			var args = 'null';
			if (typeof arg.args != 'undefined' && arg.args != null)
				args = JSON.stringify(arg.args).replace(/"/g, '\'');
			if (arg.offset > 0)
				results += '<a href="javascript:void(0);" onclick="SAYT.Run(document.getElementById(\'' + arg.srcEl.id + '\'), \'' + arg.resultSource + '\', ' + args + ', \'' + arg.value + '\', ' + (arg.offset - count) + ');">&lt;</a>&nbsp;';
			results += '<strong>' + (count > 0 ? (arg.offset + 1) + ' to ' : '') + (arg.offset + count) + ' of ' + lines[0] + ' result' + (lines[0] != 1 ? 's' : '') + '</strong>'
			if (arg.offset + count < lines[0])
				results += '&nbsp;<a href="javascript:void(0);" onclick="SAYT.Run(document.getElementById(\'' + arg.srcEl.id + '\'), \'' + arg.resultSource + '\', ' + args + ', \'' + arg.value + '\', ' + (arg.offset + count) + ');">&gt;</a>';
			
			results += '</td></tr></tfoot></table>';
			
			if (lines[0] <= 0)
				_hideSaytLayer(1000);
		}
		
		var elUid = _showSaytLayer(arg.srcEl, results, arg.resultSource);
		arg.srcEl.onfocus = function(ev) { _showSaytLayer(arg.srcEl); arg.srcEl.onfocus = null; if (arg.srcEl.attributes['onfocus']) { eval('ev.target.onfocus = function(ev2) { ' + arg.srcEl.attributes['onfocus'].value + '; };'); arg.srcEl.onfocus(); } };
		return elUid;
	}

	function _loadingSayt(srcEl)
	{
		// If currently visible, maintain size
		var resEl = document.getElementById('sayt_layer');
		var dim = { w: -1, h: -1};
		if (resEl != null && resEl.style.display != 'none')
			dim = { w: resEl.clientWidth, h: resEl.clientHeight };
		_lastVal = null;
		
		// Show loading
		var elUid = _showSaytLayer(srcEl, '<table id="sayt_loading"><tr>'
			+ (SAYT.LoadingImage != null ? '<td><img src="' + SAYT.LoadingImage + '" alt="O" id="sayt_loading_image" /></td>' : '')
			+ '<td>Searching...</td></tr></table>');
		if (srcEl.attributes['onfocus'])
			eval('srcEl.onfocus = function(ev) { ' + srcEl.attributes['onfocus'].value + '; };');
		
		if (dim.w > -1)
			resEl.style.width = dim.w + 'px';
		if (dim.h > -1)
			resEl.style.height = dim.h + 'px';
		return elUid;
	}
	
	function _showSaytLayer(srcEl, html, className)
	{
		// Show loading
		var resEl = document.getElementById('sayt_layer');
		if (resEl == null)
		{
			resEl = document.createElement('div');
			resEl.id = 'sayt_layer';
			document.body.appendChild(resEl);
		}

		resEl.className = '';
		if (typeof className != 'undefined')
			resEl.className = 'sayt_' + className;
		
		resEl.uid = Math.random();
		
		var pos = offsetPos(srcEl); // TODO: Dependency
		resEl.style.left = pos.X + 'px';
		resEl.style.top = (pos.Y + srcEl.offsetHeight) + 'px';
		resEl.style.height = '';
		resEl.style.width = '';
		if (typeof html != 'undefined')
			resEl.innerHTML = html;
		resEl.style.display = 'block';
		if (resEl.clientWidth < srcEl.clientWidth)
			resEl.style.width = srcEl.clientWidth + 'px';
		fadeElement(resEl, 100, 1);
		
		_lastSrcEl = srcEl;
		_hotkeysOn();
		
		srcEl.onblur = function(ev) { _hideSaytLayer(resEl.uid, 100); srcEl.onblur = null; if (srcEl.attributes['onblur']) { eval('ev.target.onblur = function(ev2) { ' + srcEl.attributes['onblur'].value + '; };'); srcEl.onblur(); } };
		
		return resEl.uid;
	}

	function _hideSaytLayer(elUid, delay)
	{
		var resEl = document.getElementById('sayt_layer');
		if (resEl == null)
			return;
		if (resEl.uid != elUid)
			return;
		resEl.uid = Math.random();
		
		if (delay && delay > 0)
		{
			_hideHdl = setTimeout(function() { _hideSaytLayer(resEl.uid); }, delay);
			return;
		}
		
		fadeElement(resEl, 0, 500); // TODO: Dependency
		_lastAjax = null;
		_hotkeysOff();
		_lastSrcEl = null;
	}
	
	function _hotkeysOn()
	{
		if (_lastSrcEl == null)
			return;
		if (window.navigator.userAgent.toLowerCase().indexOf("msie") != -1)
			document.body.onkeydown = _hotkeyEvent;
		else
			window.onkeydown = _hotkeyEvent;
	}
	function _hotkeysOff()
	{
		if (window.navigator.userAgent.toLowerCase().indexOf("msie") != -1)
			document.body.onkeydown = null;
		else
			window.onkeydown = null;
	}
	function _hotkeyEvent(e)
	{
		if (_lastSrcEl == null)
		{
			_hotkeysOff();
			return true;
		}
		
		var keycode;
		if (window.event)
			keycode = window.event.keyCode;
		else if (e.which)
			keycode = e.which;
		else
			return true;
		if (keycode != 13 && keycode != 38 && keycode != 40)
			return true;
		
		var target = null;
		if (e && e.target)
			target = e.target;
		else if (window.event && window.event.srcElement)
			target = window.event.srcElement;
		else
			return true;
		if (target != _lastSrcEl)
			return true;
		
		// Decide current index
		var selEl = document.getElementById('sayt_result_selected');
		var sel_idx = -1;
		if (selEl != null)
		{
			var node = selEl;
			sel_idx = 0;
			while (node.previousSibling != null)
			{
				++sel_idx;
				node = node.previousSibling;
			}
		}
		
		var new_sel_idx = -1;
		switch (keycode)
		{
			case 13:
				if (selEl.attributes['value'])
					_lastSrcEl.value = selEl.attributes['value'].value;
				return false;
			case 38:
				if (sel_idx >= -1)
					new_sel_idx = sel_idx - 1;
				break;
			case 40:
				new_sel_idx = sel_idx + 1;
				break;
		}
		
		// Select
		if (selEl)
			selEl.id = '';
		if (new_sel_idx > -1)
		{
			var table = document.getElementById('sayt_results');
			var node = table.firstChild;
			if (node.nodeName.toLowerCase() == 'thead')
				node = node.nextSibling;
			if (node.nodeName.toLowerCase() == 'tbody')
				node = node.firstChild;
			var idx = 0;
			while (node.nodeName.toLowerCase() == 'tr')
			{
				if (idx == new_sel_idx || node.nextSibling == null)
				{
					node.id = 'sayt_result_selected';
					break;
				}
				++idx;
				node = node.nextSibling;
			}
		}
		
		return false;
	}
	
	// Public
	return {
		LoadingImage: null,
		
		Initialise: function(scriptPath, configPath)
		{
			if (typeof scriptPath == 'undefined')
				throw 'SAYT: You must pass scriptPath on Initialise';
			if (typeof configPath == 'undefined')
				throw 'SAYT: You must pass configPath on Initialise';
			_initialised = true;
			_whereAmI = scriptPath;
			_whereConfig = configPath;
		},

		// @srcEl - the element that called SAYT
		// @resultSource - The name of the type of result to return
		// @args - Optional. JavaScript object to be sent to the SAYT processor and returned
		// @value - Optional. A value to send to the SAYT processor, if not srcEl.value
		// @offest - Optional. The number of items to remove from the beginning. Used during page changing
		Run: function(srcEl, resultSource, args, value, offset)
		{
			if (!_initialised)
				return false;
			
			srcEl.focus();
			if (_hideHdl != null)
			{
				clearTimeout(_hideHdl);
				_hideHdl = null;
			}
			var resEl = document.getElementById('sayt_layer');
			if (resEl != null)
				resEl.uid = Math.random();
			
			// Use srcEl value by default
			if (typeof value == 'undefined')
				value = srcEl.value;
			
			// Must be able to refer to srcEl later
			if (typeof srcEl.id == 'undefined' || srcEl.id.length == 0)
				srcEl.id = 'el_' + Math.random();
			
			if (value.length > 0)
			{
				if (_lastVal != resultSource + '::' + value || typeof offset != 'undefined')
				{
					// Build query
					if (typeof args == 'undefined')
						args = { srcEl_id: srcEl.id };
					else
						args.srcEl_id = srcEl.id;
					var query = 'src=' + urlencode(resultSource) + '&args=' + urlencode(JSON.stringify(args));
					if (typeof offset == 'undefined' || isNaN(offset) || offset <= 0)
						offset = 0;
					else
						query += '&off=' + offset;
					
					_loadingSayt(srcEl);
					_lastAjax = PerformRemoteAction(_gotSAYT, _whereAmI + 'runSAYT.js.php', query, 'val=' + urlencode(value) + '&config=' + urlencode(_whereConfig), { srcEl: srcEl, resultSource: resultSource, args: args, value: value, offset: offset }); // TODO: Dependency
					_lastVal = resultSource + '::' + value;
				}
				else
				{
					var resEl = document.getElementById('sayt_layer');
					if (resEl != null)
						_showSaytLayer(srcEl);
				}
			}
			else
			{
				_hideSaytLayer();
			}
		},
		
		TestLoading: function(srcEl)
		{
			_loadingSayt(srcEl);
		},
		
		TestResults: function(srcEl, offset)
		{
			if (typeof offset == 'undefined' || isNaN(offset) || offset < 0)
				offset = 0;
			var page = 5;
			var total = (page * 3);
			
			test = '<table id="sayt_results"><tbody>';
			for (var i = offset; i < total && i < offset + page; ++i)
				test += '<tr><td><a href="javascript:alert(\'You clicked item ' + (i + 1) + '\');void(0);">Test Item ' + (i + 1) + '</a></td></tr>';
			test += '</tbody><tfoot>';
			if (offset > 0)
				test += '<a href="javascript:void(0);" onclick="SAYT.TestResults(document.getElementById(\'' + srcEl.id + '\'), ' + (offset - page) + ');">&lt;</a>&nbsp;';
			test += '<strong>' + (page > 0 ? (offset + 1) + ' to ' : '') + (offset + page) + ' of ' + total + ' result' + (total != 1 ? 's' : '') + '</strong>'
			if (offset + page < total)
				test += '&nbsp;<a href="javascript:void(0);" onclick="SAYT.TestResults(document.getElementById(\'' + srcEl.id + '\'), ' + (offset + page) + ');">&gt;</a>';
			test += '</tfoot></table>';
			
			_showSaytLayer(srcEl, test);
		}
	};
}();