function AutoComplete(data) {
	this.restoreHandlers = null;
	this.currentControl = null;
	this.depth = data.depth;
	this.phrases = data.phrases;
	this.words = data.words;
	this.map = data.map;
	if (typeof(this.map) == 'undefined')
		this.map = null;

	if (TextHighlight.wordRegex == null)
		TextHighlight.staticFieldInit();
}

AutoComplete.prototype.getPhrases = function(phrase) {
	if (typeof(phrase) != 'string' || phrase.length == 0 || this.map == null)
		return [];
	phrase = phrase.trim();
	var i = 0, ch, wordre = TextHighlight.wordRegex, word = '', lastLetterIndex = null, l = this.map, lastKey;
	for (i = 0; i < phrase.length; ++i) {
		ch = '' + phrase.charAt(i);
		if (wordre.test(ch))
			break;
	}
	if (i > 0)
		phrase = phrase.substring(i);
	if (phrase.length == 0)
		return [];
	phrase = phrase.toLowerCase();
	for (i = 0; i < phrase.length; ++i) {
		ch = '' + phrase.charAt(i);
		if (wordre.test(ch))
			word += ch;
		else
			break;
	}
	for(i = 0; i < word.length && l != null; ++i) {
		ch = '' + word.charAt(i);
		if (typeof(l[ch]) != 'undefined' && l[ch] != null) {
			lastLetterIndex = l[ch];
			l = lastLetterIndex.l;
			if (typeof(l) == 'undefined')
				l = null;
		} else {
			return [];
		}
	}
	if (lastLetterIndex == null)
		return [];
	var phrases = null;
	if (i == word.length) {
		phrases = [];
		if (typeof(lastLetterIndex.p) != 'undefined' && lastLetterIndex.p != null) {
			for(i = 0; i < lastLetterIndex.p.length; ++i)
				phrases.push(lastLetterIndex.p[i]);
		}
		AutoComplete._collectPhrases(lastLetterIndex.l, phrases);
	} else {
		var words = [];
		if (typeof(lastLetterIndex.w) != 'undefined' && lastLetterIndex.w != null) {
			for(i = 0; i < lastLetterIndex.w.length; ++i)
				words.push(lastLetterIndex.w[i]);
		}
		AutoComplete._collectWords(lastLetterIndex.l, words);
		phrases = [];
		if (words.length > 0) {
			words.sort();
			lastKey = words[0];
			for(i = 1; i < words.length; ++i) {
				if (lastKey == words[i]) {
					words.splice(i, 1);
					--i;
				} else {
					lastKey = words[i];
				}
			}
			for(i = 0; i < words.length; ++i) {
				var wi = words[i] * 2;
				if (this.words[wi].indexOf(word) == 0) {
					var pa = this.words[wi + 1];
					for(var j = 0; j < pa.length; ++j) {
						phrases.push(pa[j]);
					}
				}
			}
		}
	}
	if (phrases.length > 0) {
		phrases.sort();
		lastKey = phrases[0];
		for(i = 1; i < phrases.length; ++i) {
			if (lastKey == phrases[i]) {
				phrases.splice(i, 1);
				--i;
			} else {
				lastKey = phrases[i];
			}
		}
		for(i = 0; i < phrases.length; ++i) {
			phrases[i] = this.phrases[phrases[i]];
		}
		if (word.length != phrase.length) {
			var validPhrases = [];
			for(i = 0; i < phrases.length; ++i) {
				if (phrases[i].toLowerCase().indexOf(phrase) == 0) {
					validPhrases.push(phrases[i]);
				}
			}
			phrases = validPhrases;
		}
	}
	return phrases;
}

AutoComplete._collectPhrases = function(l, p) {
	if (typeof(l) == 'undefined' || l == null)
		return;
	for (var k in l) {
		var c = l[k];
		if (typeof(c.p) != 'undefined' && c.p != null) {
			for(var i = 0; i < c.p.length; ++i)
				p.push(c.p[i]);
		}
		AutoComplete._collectPhrases(c.l, p);
	}
}

AutoComplete._collectWords = function(l, w) {
	if (typeof(l) == 'undefined' || l == null)
		return;
	for (var k in l) {
		var c = l[k];
		if (typeof(c.w) != 'undefined' && c.w != null) {
			for(var i = 0; i < c.w.length; ++i)
				p.push(c.w[i]);
		}
		AutoComplete._collectWords(c.l, w);
	}
}


AutoComplete.onPhraseChange = function(sourceControl, listElement, acObject) {
	if (typeof(sourceControl) == 'string')
		sourceControl = gsdlGetElement(sourceControl);
	if (typeof(listElement) == 'string')
		listElement = gsdlGetElement(listElement);

	var result = acObject.getPhrases(gsdlGetValue(sourceControl));
	if (result.length == 0) {
		AutoComplete.__hideList(listElement, acObject);
	} else {
		if (acObject.currentControl != sourceControl) {
			if (acObject.restoreHandlers != null) {
				acObject.restoreHandlers();
			}
			acObject.currentControl = sourceControl;
			AutoComplete.__setHandlers(sourceControl, listElement, acObject);
		} else if (acObject.restoreHandlers == null) {
			AutoComplete.__setHandlers(sourceControl, listElement, acObject);
		}
		var theBody = gsdlGetElement('theBody', listElement.contentWindow.document);
		listElement.style.top = (gsdlGetTop(sourceControl) + sourceControl.offsetHeight) + 'px';
		listElement.style.left = gsdlGetLeft(sourceControl) + 'px';
		listElement.style.width = (sourceControl.offsetWidth - 2) + 'px';
		listElement.style.display = 'block';

		var str = '<ul class="test">';
		for(var i = 0; i < result.length; ++i) {
			str += '<li>' + result[i] + '</li>';
		}
		str += '</ul>';
		AutoComplete.__setContent(listElement, str);
		var elements = gsdlGetElementsByTagName('li', theBody);
		if (elements != null && elements.length > 0) {
			for(var i = 0; i < elements.length; ++i) {
				AutoComplete.__setListItemEvents(elements[i], sourceControl, listElement, acObject);
			}
		}
		var ulElement;
		if (theBody.firstChild)
			ulElement = theBody.firstChild;
		else
			ulElement = theBody.children[0];
		if (ulElement.offsetHeight < 300)
			listElement.style.height = (ulElement.offsetHeight + 2) + 'px';
		else
			listElement.style.height = '302px';
	}
}

AutoComplete.__setContent = function(listElement, value) {
	var theBody = gsdlGetElement('theBody', listElement.contentWindow.document);
	theBody.innerHTML = value;
}

AutoComplete.__hideList = function(listElement, acObject) {
	listElement.style.display = 'none';
		AutoComplete.__setContent(listElement, '');
	if (acObject.restoreHandlers != null) {
		acObject.restoreHandlers();
	}
}

AutoComplete.__setHandlers = function(sourceControl, listElement, acObject) {
	var oldOnClickHandler = document.onclick;
	document.onclick = function(evt) {
		AutoComplete.__hideList(listElement, acObject);
		return cancelEvent(evt);
	}
	var oldOnBlurHandler = sourceControl.onblur;
	sourceControl.onblur = function(evt) {
		window.setTimeout(function() { AutoComplete.__hideList(listElement, acObject); }, 150);
		return cancelEvent(evt);
	}
	acObject.restoreHandlers = function() {
		document.onclick = oldOnClickHandler;
		sourceControl.onblur = oldOnBlurHandler;
		acObject.restoreHandlers = null;
	}
}

AutoComplete.__setListItemEvents = function(element, sourceControl, listElement, acObject) {
	element.onclick = function(evt) {
		if (element.textContent)
			gsdlInitValue(sourceControl, element.textContent);
		else
			gsdlInitValue(sourceControl, element.innerText);
		AutoComplete.__hideList(listElement, acObject);
		sourceControl.focus();
		return cancelEvent(evt);
	}
	element.onmouseenter = function(evt) {
		element.className = 'acliactive';
	}
	element.onmouseleave = function(evt) {
		element.className = 'aclinormal';
	}
}
