var acXmlHTTP;
var acXmlHTTPUpdate;
var matchCache;
var m_intCount = 0;

var ie = (document.all && navigator.userAgent.toLowerCase().indexOf("msie")!=-1);

var dbHitAt = 3;

//var debugWin = window.open("/blank.htm", "same", "width=300, height=600, top = 0, left=0, scrollbars=1");

function GetCursorPos(win, textfield)
{
	if((typeof textfield.selectionEnd) != 'undefined')
	{
		return textfield.selectionEnd;	
	}
	else 
	{	
		try
		{
			textfield.createTextRange();
			var oldSel = win.document.selection.createRange();
			var sel = oldSel.duplicate();
			sel.moveToElementText(textfield);
			sel.setEndPoint("EndToStart",oldSel);
			return sel.text.length;
		} catch (e) {}
	}	
}

function SetCursorPos(win, textfield, pos)
{
	if((typeof textfield.selectionEnd) != 'undefined' && (typeof textfield.selectionStart) != 'undefined')
	{
		textfield.selectionStart=textfield.value.length;
		textfield.selectionEnd=textfield.value.length;
	}
	else 
	{
		if(win.document.selection && textfield.createTextRange)
		{
			var sel=textfield.createTextRange();
			sel.collapse(false);
			//sel.move("character",pos);
			sel.select();
		}
	}
}

function MatchCache(id, scopeId)
{
	matchCache = this;
	
	// Properties
	this.length = 0;
	this.scopeId = scopeId;
	this.ID = id;
	this.dbLookups = null;
	this.subscribers = null;
	this.copyUpdate = null;
	this.autoCompleteList = null;
		
	// Functions
	this.addItem = MatchCache_addItem;
	this.addItemVars = MatchCache_addItemVars;
	this.copy = MatchCache_copy;
	this.searchDB = MatchCache_searchDB;
	this.addDBLookup = MatchCache_addDBLookup;
	this.hasDBLookup = MatchCache_hasDBLookup;
	this.clearLookups = MatchCache_clearLookups;
	this.addSubscriber = MatchCache_addSubscriber;
	this.notifySubscribers = MatchCache_notifySubscibers;
	this.search = MatchCache_search;
	this.addAutoComplete = MatchCache_addAutoComplete;
	this.removeAutoComplete = MatchCache_removeAutoComplete;
}

function MatchCache_addAutoComplete(resultId)
{
	if (this.autoCompleteList == null)
		this.autoCompleteList = new Array();
		
	this.autoCompleteList.push(resultId);
}

function MatchCache_removeAutoComplete(resultId)
{
	if (this.autoCompleteList == null)
		return;
		
	for (var i = this.autoCompleteList.length - 1; i >= 0; i--)
		if (this.autoCompleteList[i] == resultId || !resultId)
			this.autoCompleteList.splice(i, 1);
}

function MatchCache_addSubscriber(matchList)
{
	if (this.subscribers == null)
		this.subscribers = new Array();
		
	this.subscribers.push(matchList);
}

function MatchCache_copy(matchCache, copyUpdate)
{
	for (var i = 0; i < matchCache.length; i++)
		this.addItem(new MatchItem(matchCache[i].resultId, matchCache[i].resultInfo, matchCache[i].isCached));

	if (matchCache.dbLookups != null)
	{
		for (var i = 0; i < matchCache.dbLookups.length; i++)
			this.addDBLookup(matchCache.dbLookups[i]);
	}

	this.copyUpdate = copyUpdate;

}

function MatchCache_notifySubscibers(query)
{
	if (this.subscribers != null)
	{
		for (var i = 0; i < this.subscribers.length; i++)
		{
		
			try
			{
				this.subscribers[i].notify(query);
			} 
			catch (e) 
			{}
		}
		
	}
}

function MatchCache_addItem(matchItem)
{
	// Make sure an item with the same id doesn't already exist.
	for (var i = 0; i < this.length; i++)
	{
		this[i].resultId = this[i].resultId;
		matchItem.resultId = matchItem.resultId;
		
		if (this[i].resultId == matchItem.resultId)
			return false;
		
		if (this[i].resultInfo.toLowerCase() == matchItem.resultInfo.toLowerCase())
			return false;
	}
	
	matchItem.matchCacheID = this.length;
	this[this.length] = matchItem;
	matchItem.parentCache = this;
	this.length += 1;
	
}

function MatchCache_addItemVars(resultId, resultInfo, isCached)
{
	// Make sure an item with the same id doesn't already exist.
	for (var i = 0; i < this.length; i++)
	{
		if (this[i].resultId == resultId)
			return false;
	}
	
	var matchItem = new MatchItem(resultId, resultInfo, isCached);
	
	matchItem.matchCacheID = this.length;
	this[this.length] = matchItem;
	matchItem.parentCache = this;
	this.length += 1;
	
}

function MatchCache_searchDB(lookupUrl, lookupQuery)
{
	if (!this.hasDBLookup(lookupQuery.toLowerCase()))
	{
		acXmlHTTP = createXmlHttp();
		cache = this;
		acXmlHTTP.onreadystatechange=function()
		{
			var lookupResults =null;
			var results=null;
			
			// Gets called by the acXmlHTTP callback
			if (acXmlHTTP.readyState == 4)
			{
				lookupResults = acXmlHTTP.responseText.split('|||');
				matchCache.addDBLookup(lookupResults[0].toLowerCase());

				if (lookupResults.length > 1)
					results = lookupResults[1].split('||');

				if (results != null)
				{
					var contact;

					if (results.length < 50)
						matchCache.addDBLookup(lookupResults[0]);
				
					for (var i = 0; i < results.length; i++)
					{
						contact = results[i].split('|');
						matchCache.addItem(new MatchItem(contact[0], contact[1], false));
					}

				}

				matchCache.notifySubscribers(lookupResults[0]);
			}			
		};
		
		XmlUtil.httpGet(acXmlHTTP, lookupUrl + '?scopeId=' + this.scopeId + '&query=' + lookupQuery);
	
		return true;
	}
	else
	{
		return false;
	}
}

function MatchCache_addDBLookup(lookupQuery)
{
	if (this.dbLookups == null)
		this.dbLookups = new Array();
	
	this.dbLookups.push(lookupQuery);
}

function MatchCache_hasDBLookup(lookupQuery)
{
	if (this.dbLookups != null)
	{
		for (var i = 0; i < this.dbLookups.length; i++)
		{
			if (this.dbLookups[i] == lookupQuery.toLowerCase())
				return true;
		}
	}
	
	return false;
}

function MatchCache_clearLookups()
{
	this.dbLookups = null;
}

function MatchCache_search(matchList)
{

	for (var i = 0; i < this.length; i++)
	{
		if (this[i].isMatch(matchList.matchQuery))
			matchList.addItem(this[i].copy());
	}
	
}

function MatchList(listID, queryUrl, queryInput, listDiv, cache)
{
	// Properties
	this.length = 0;
	this.cursorPos = 0;
	this.queryStart = 0;
	this.queryEnd = 0;
	this.selectedIndex = 0;
	this.ID = listID;
	this.queryUrl = queryUrl;
	this.queryInput = queryInput;
	queryInput.matchList = this;
	this.div = listDiv;
	this.matchCache = cache;
	this.lastMatchQuery = '';
	this.matchQuery = '';
	this.dbQuery = '';
	this.addComma = false;
	this.displayThreshold = 0;
	this.multiple = true;	
	
	// Functions
	this.addItem = MatchList_addItem;
	this.removeLast = MatchList_removeLast;
	this.removeAll = MatchList_removeAll;
	this.findMatches = MatchList_findMatches;
	this.handleKeyDown = MatchList_handleKeyDown;
	this.handleKeyUp = MatchList_handleKeyUp;
	this.handleBlur = MatchList_handleBlur;
	this.handleClick = MatchList_handleClick;
	this.displayMatches = MatchList_displayMatches;
	this.limitMatches = MatchList_limitMatches;
	this.parseQuery = MatchList_parseQuery;
	this.changeSelection = MatchList_changeSelection;
	this.notify = MatchList_notify;
	
	// Initialization
	this.matchCache.addSubscriber(this);
	this.queryInput.onkeydown=this.handleKeyDown;
	this.queryInput.onblur=this.handleBlur;
	this.queryInput.onclick=this.handleClick;
	//this.queryInput.onfocus=this.handleClick;
	if (!ie)
		this.queryInput.onkeyup=this.handleKeyUp;
		
}

function MatchList_handleKeyUp()
{
	if (this.value.search(/(.*)\n/gi) != -1)
		this.value = this.value.replace(/(.*)\n/gi, '$1 ');
}

function MatchList_notify(query)
{
	if (query == this.dbQuery)
	{
		this.removeAll();
		this.dbQuery = '';
		this.matchQuery='';
		this.findMatches();
	}
}

function MatchList_handleBlur()
{
	this.matchList.hasfocus = false;
	var blurCommand = 'if (!' + this.matchList.ID + '.hasfocus) { ' + this.matchList.ID + '.removeAll(); ' + this.matchList.ID + '.displayMatches(); }';
	setTimeout(blurCommand, 500);	
}

function MatchList_handleClick()
{
	this.matchList.matchQuery = '';
	setTimeout(this.matchList.ID + '.findMatches()', 0);
	this.matchList.hasfocus = true;
}

function MatchList_parseQuery()
{
	var commaPos;
	var semiPos;
	var allText = this.queryInput.value;
	this.cursorPos = GetCursorPos(window, this.queryInput);
	commaPos = allText.indexOf(',', this.cursorPos);
	semiPos = allText.indexOf(';', this.cursorPos);

	if ((commaPos < semiPos && commaPos != -1) || semiPos == -1)
		var queryEnd = commaPos;
	else
		var queryEnd = semiPos;

	if (queryEnd == -1)
		queryEnd = allText.length;

	this.queryEnd = queryEnd;

	commaPos = strrev(allText.substring(0, this.queryEnd)).indexOf(',');
	semiPos = strrev(allText.substring(0, this.queryEnd)).indexOf(';');

	if ((commaPos < semiPos && commaPos != -1) || semiPos == -1)
		var queryStart = commaPos;
	else
		var queryStart = semiPos;

	this.queryStart = (queryStart != -1) ? this.queryEnd - queryStart : 0;

	var query = trim(allText.substring(this.queryStart, this.queryEnd));

	return query;
}

function trim(s) 
{
	// Remove leading spaces and carriage returns
	while ((s.substring(0,1) == ' ') || (s.substring(0,1) == '\n') || (s.substring(0,1) == '\r'))
	{
		s = s.substring(1,s.length);
	}
	
	// Remove trailing spaces and carriage returns
	while ((s.substring(s.length-1,s.length) == ' ') || (s.substring(s.length-1,s.length) == '\n') || (s.substring(s.length-1,s.length) == '\r'))
	{
		s = s.substring(0,s.length-1);
	}
	
	return s;
}

function strrev(str) {
	if (!str) return '';
	var revstr='';
	for (i = str.length-1; i>=0; i--)
		revstr+=str.charAt(i)
	return revstr;
}


function MatchList_changeSelection(index)
{
	document.getElementById(this.ID + this.selectedIndex).className='autocomplete_LineItem_Unselected';
	document.getElementById(this.ID + index).className='autocomplete_LineItem_Selected';
	this.selectedIndex = index;
}

function MatchList_limitMatches()
{
	for (var i = 0; i < this.length; i++)
	{
		if (!this[i].isMatch(this.matchQuery))
		{
			this[i].remove();
			i -= 1;
		}
	}
	
}

function MatchList_handleKeyDown(e)
{	
	// Get a handle on the event
	e = e?e:window.event;

	var keyCode = ie?e.keyCode:e.which;
	
	// tab, return, comma, semicolon
	if (!e.shiftKey && !e.ctrlKey && !e.altKey && (keyCode == 188 || keyCode == 13 || keyCode == 9 || keyCode == 186))
	{
	
		if (this.matchList.length > 0)
		{
			this.matchList.addComma = true;
		
			this.matchList[this.matchList.selectedIndex].autoComplete();
			return false;
		} else {
			if (keyCode == 9)
			{
				if (this.value.charAt(this.value.length-1) == ',' || this.value.charAt(this.value.length-1) == ';')
				{
					this.value = this.value.substring(0, this.value.length-1);
				} 
				else if (this.value.charAt(this.value.length-1) == ' ' && (this.value.charAt(this.value.length-2) == ',' || this.value.charAt(this.value.length-2) == ';'))
				{
					this.value = this.value.substring(0, this.value.length - 2);
				}
			}
			
			return false;
		}
	}
	else if (keyCode == 27) // escape
	{
		this.matchList.removeAll();
		this.matchList.displayMatches();
		
		return false;
	}
	else if (keyCode == 40) // down
	{
		if (this.matchList.selectedIndex < this.matchList.length - 1)
		{
			this.matchList.changeSelection(this.matchList.selectedIndex + 1);
		}
	}
	else if (keyCode == 38) // up
	{
		if (this.matchList.selectedIndex > 0)
		{
			this.matchList.changeSelection(this.matchList.selectedIndex - 1);
		}
	}
	else 
	{
		setTimeout(this.matchList.ID + '.findMatches()', 0);	
	}	
}

function MatchList_removeAll()
{
	while (this.length > 0)
	{
		this.removeLast();
	}
}

function MatchList_findMatches()
{
	var query = this.parseQuery();
	
	// Escape all special regex chars.
	query = query.replace(/([^0-9A-Z])/gi, "\\$1").replace(/&/gi, '&amp;').replace(/"/gi, '&quot;').replace(/ /gi, '&nbsp;').replace(/</gi, '&lt;').replace(/>/gi, '&gt;');
		
	// If the query hasn't changed then attempt search.
	if (query != this.matchQuery)
	{
		this.lastMatchQuery = this.matchQuery;
		this.matchQuery = query;

		if (this.matchQuery.length > 0)
		{
			if (this.matchQuery.length == dbHitAt)
			{
				if (this.matchCache.searchDB(this.queryUrl, this.matchQuery))
					this.dbQuery = this.matchQuery;
			}
			else if (this.dbQuery != '' && (this.matchQuery.length < this.dbHitAt || this.matchQuery.substring(0, dbHitAt) != this.dbQuery))
			{
				this.dbQuery = '';
			}
		
			if (this.length > 0 && this.lastMatchQuery == this.matchQuery.substring(0, this.matchQuery.length-1))
			{
				// Limit match list
				this.limitMatches();
			} 
			else 
			{
				// Clear all records from this matchlist
				this.removeAll();

				// Search cache
				this.matchCache.search(this);
				
			}
		} else {
			this.removeAll();
		}

	}

	this.displayMatches();
	
}

function MatchList_displayMatches()
{

	var innerTable = '';
	var resultInfo;
	var selectedClass;
	var unselectedClass;
	var extraStyle;
	
	this.selectedIndex = 0;
	
	if (this.length > 0 || this.dbQuery != '')
	{
		innerTable += '<table border="0" cellpadding="0" cellspacing="1" bgcolor="#000000"><tr bgcolor="#DDDDDD"><td><table border="0" bgcolor="#00EE00" cellpadding="0" cellspacing="0">';

		for (var i = 0; i < this.length; i++)
		{
			if (this.selectedIndex == i)
			{
				selectedClass = 'autocomplete_LineItem_Selected';
				unselectedClass = 'autocomplete_LineItem_Unselected';
			}
			else
			{
				selectedClass = 'autocomplete_LineItem_Unselected';
				unselectedClass = 'autocomplete_LineItem_Selected';
			}
			resultInfo = this[i].formattedResultInfo;
			
			innerTable += '<tr><td id="' + this.ID + i + '" onclick="' + this.ID + '[' + i + '].autoComplete();" nowrap class="' + selectedClass + '" style="cursor: default; font-family: arial,helvetica; font-size: 12px;" onmouseover="' + this.ID + '.changeSelection(' + i + ');" id="matched' + i + '">&nbsp;&nbsp;' + resultInfo + '&nbsp;&nbsp;</td></tr>';
		}
		
		if (this.dbQuery != '')
			innerTable += '<tr><td nowrap align="left" class="autocomplete_LineItem_Unselected" style="cursor: default; font-family: arial,helvetica; font-size: 12px;">&nbsp;&nbsp;<B>[</B>&nbsp;Searching...&nbsp;<B>]</B>&nbsp;&nbsp;</td></tr>';

		innerTable += '</table></td></tr></table>';

		this.div.className = 'autocomplete_Enabled';

	} else {
		this.div.className = 'autocomplete_Disabled';
	}

	this.div.innerHTML = innerTable;
}

function MatchList_addItem(matchItem)
{
	matchItem.matchListID = this.length;
	this[this.length] = matchItem;
	matchItem.parentList = this;
	this.length += 1;
}

function MatchList_removeLast()
{
	this.length -= 1;
	this[this.length] = null;
}

function MatchItem(resultId, resultInfo, isCached)
{
	// Properties
	this.matchListID = 0;
	this.parentList = null;
	this.parentCache = null;
	this.resultId = resultId;
	this.resultInfo = resultInfo;
	this.formattedResultInfo = resultInfo;
	this.isCached = isCached;
	
	// Functions
	this.isMatch = MatchItem_isMatch;
	this.copy = MatchItem_copy;
	this.autoComplete = MatchItem_autoComplete;
	this.remove = MatchItem_remove;
}

function MatchItem_copy()
{
	var copy = new MatchItem(this.resultId, this.resultInfo, this.isCached);
	copy.formattedResultInfo = this.formattedResultInfo;
	
	return copy;
}

function MatchItem_autoComplete()
{
	
	this.parentList.dbQuery = '';

	var resultInfo = this.resultInfo.replace(/&quot;/gi, '"').replace(/&lt;/gi, '<').replace(/&gt;/gi, '>').replace(/&nbsp;/gi, ' ').replace(/&amp;/gi, '&');
	var curValue = this.parentList.queryInput.value;
	
	var addComma = curValue.charAt(this.parentList.queryEnd) == ',' ? '' : ', ';

	addComma = this.parentList.addComma ? addComma : '';
	addComma = ie ? addComma : '';

	this.parentList.addComma = false;
	
	if (this.parentList.multiple){
		this.parentList.queryInput.value = curValue.substring(0, this.parentList.queryStart) + (this.parentList.queryStart > 0 ? ' ' : '') + resultInfo + curValue.substring(this.parentList.queryEnd, curValue.length) + addComma;
	}
	else{
		this.parentList.queryInput.value = resultInfo;
		this.parentList.matchCache.removeAutoComplete();
	}
		
	this.parentList.queryInput.focus();
	SetCursorPos(window, this.parentList.queryInput, this.queryStart);

	this.parentList.lastMatchQuery = this.parentList.matchQuery;
	this.parentList.matchQuery = '';
	this.parentList.removeAll();
	this.parentList.displayMatches();
	this.parentList.matchCache.addAutoComplete(this.resultId);

}

function MatchItem_remove()
{
	this.parentList[this.matchListID] = null;
	
	for (var i = this.matchListID; i < this.parentList.length - 1; i++)
	{
		this.parentList[i] = this.parentList[i + 1];
		this.parentList[i].matchListID -= 1;
	}
	
	this.parentList.length -= 1;
}

function MatchItem_isMatch(query)
{
    query = query.replace(/&quot;/gi, '"').replace(/&nbsp;/gi, ' ').replace(/&amp;/gi, '&');
	this.formattedResultInfo = this.resultInfo.replace(eval('/(' + query + ')/gi'), '<b>$1</b>');
	
	if (this.resultInfo != this.formattedResultInfo)
		return true;
	else
		return false;
}