	//전역변수
	var oldVal = "", caretPos="", tagword="";
	var	timer=false; // setTimeOut함수를 호출해야 할지 하지 않아야 할지를 결정하는 변수이다. 타임아웃함수의 호출은 후보태그레이어가 보여지는 상태에서만 호출되야 한다.
	var curCandiSel = null; // 후보태그중 현재 선택되어 있는 태그(div 엘리먼트이다)
	var keydownCaretPos = new CaretPosition(); // 후보태그 레이어가 보여지는 시점의 캐럿의 위치를 저장하고 있는 변수이다.
	var isLock=false; // 후보태그 레이어를 재구성할 것인지, 하지 말아야 할것인지를 결정하는 변수


	function viewCandidateTag(tag)
	{
		if(tag.length == 0)
		{
			hiddenCandidateLayer();
			return;
		}

		if(tag.length == 1 && tag.charAt(0) == '#')
		{
			$('candidateLayer').innerHTML = '<div>태그를 입력해주세요.</div>';
			showCandidateLayer();
			return;
		}

		if(tag.charAt(0) == '#')
		{
			tag = tag.substring(1, tag.length);
		
			var requestUrl = g_contextPath + '/servlet/CandidateTag?reqkey=' + g_reqKey + '&tagword=' + encodeURIComponent(tag) + '&count=5';
			new Ajax.Request(requestUrl, {
				'method': 'get',
				onCreate: function(transport) {
					//centerPosition($('wait'));
					//$('wait').show();
				},
				onSuccess: function(transport) {					
					if (200 == transport.status) {
						//$('wait').hide();
						resultProcess(transport.responseXML);
					}
				},
				onFailure: function(transport) {
					//$('wait').hide();
					alert('오류가 발생했습니다. 상태코드는 다음과 같습니다.' + transport.status);
				}
			});
		}
	}

	function resultProcess(xmlObj)
	{
		var list_container = $('candidateLayer');
		removeAllChildren(list_container);
		
		var dataItems = xmlObj.getElementsByTagName("candidate");
		var i;

		if(dataItems.length > 0)
		{
			for (i = 0; i < dataItems.length; i++) {
				var dataItem = nodeToJSON(dataItems[i]);
		
				var candiateDiv = new Element('div').update("#" + dataItem.tag + " (" + dataItem.cnt + ")");
				Event.observe(candiateDiv, 'mouseover', candidateMouseOver.bindAsEventListener(candiateDiv, candiateDiv));
				Event.observe(candiateDiv, 'mouseout', candidateMouseOut.bindAsEventListener(candiateDiv, candiateDiv));
				Event.observe(candiateDiv, 'click', candidateMouseClick.bindAsEventListener(candiateDiv, candiateDiv));
		
		
				list_container.appendChild(candiateDiv);
			}
		}
		else
		{
			$('candidateLayer').innerHTML = '<div>태그를 찾을 수 없습니다.</div>';
		}
		
		showCandidateLayer('default');
	}

	function candidateMouseOver(obj, obj2)
	{
		if(curCandiSel != null)
			curCandiSel.style.backgroundColor = "#ffffff";
			
		obj2.style.backgroundColor = "#f7fdf5";
		curCandiSel = obj2;

		
	}

	function replaceCandidateTag()
	{
		// 선택된 것으로 태그내용을 바꾸는.
		var tagString = curCandiSel.innerHTML;
		tagString = tagString.substring(0, tagString.indexOf(" "));

		if(tagString.length < 1 || tagString.charAt(0) != '#')
			return;

		// 팝업이 호출되었던 시점의 캐럿위치에 존재하는 태그워드의 전체 선택영역을 얻는다. 
		// #민|주  상태라면 '#민'이라는 단어로 팝업이 구성되어 나타나게 되고, '#민주'를 선택하는 선택영역을 구하게 된다.
		
		// keydownCaretPos에 팝업이 호출되었던 시점의 캐럿위치가 저장되어 있다.
		// keydownCaretPos에서 1씩 값을 감소시켜가면서 '#'을 만날때까지 진행한다.
		
		
		// 선택 시작위치를 찾는다.
		var startPos = keydownCaretPos.start;
		var currentMessage = $('messageBox').value;
		while(1)
		{
			if(currentMessage.charAt(startPos-1) == '#')
			{
				startPos--;
				break;
			}

			startPos--;

			//먼가 잘못된 경우 그냥 리턴한다.
			if(startPos == 0)
				return;
		}

		// 선택 종료위치를 찾는다.
		var endPos = keydownCaretPos.start;
		while(1)
		{
			//alert("흠 :" + currentMessage.length + ":" + endPos);
			if(currentMessage.length == endPos || currentMessage.charAt(endPos) == ' ' || currentMessage.charAt(endPos) == '\n' || currentMessage.charAt(endPos) == '\r')
			{
				//if(currentMessage.charAt(endPos) == '\n' || currentMessage.charAt(endPos) == '\r')
				//	alert(endPos);
				break;
			}

			//alert(endPos);
			endPos++;

			//먼가 잘못된 경우 그냥 리턴한다.
			if(endPos > currentMessage.length)
			{
				endPos = currentMessage.length;
				break;
			}
		}

		//alert(startPos + " : " +endPos);
		
		// 선택영역을 현재 선택되어 있는 태그로 치환하고, 캐럿을 원위치 시킨다.
		// 태그 부분을 선택한다.
		setCaretPosition($('messageBox'), startPos, endPos - startPos);

		// 선택된 태그부분을 replaceStr을 이용하여 교체한다.
		insertText($('messageBox'), tagString, false);	

		// 캐럿을 원위치 시킨다.
		//setCaretPosition($('messageBox'), keydownCaretPos.start, 0);
		
	}
	
	function candidateMouseOut(obj, obj2)
	{
		obj2.style.backgroundColor = "#ffffff";
	}
	
	function candidateMouseClick(obj, obj2)
	{
		//alert(obj2.innerHTML);
		replaceCandidateTag();
		insertText($('messageBox'), " ", false);
		
		hiddenCandidateLayer();
	}

	function hiddenCandidateLayer()
	{
		$('candidateLayer').style.display = 'none';
		curCandiSel = null; // 후보리스트에서 현재 선택된 것을 null로 만든다.
		timer = false; // 무한 타이머의 작동을 중지시킨다.
		isLock = false;
	}

	function showCandidateLayer()
	{
		$('candidateLayer').style.display = '';
		keydownCaretPos = getCaretPosition($('messageBox'));
		$('candidateLayer').clonePosition($('messageBox'), {'setHeight': false, 'offsetLeft': 0, 'offsetTop': 62});
		//$('trace3').innerHTML = keydownCaretPos.start;
		timer = true; // 무한 타이머의 작동을 시작한다.
	}

	function messageBoxKeyDown(e)
	{
		var keyCode = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;

		if((keyCode == 38 || keyCode == 40) && timer) //40 : 아래화살표, 38 : 윗화살표
		{
			isLock = true;
		}
		else
		{
			isLock = false;
		}
	}

	function messageBoxKeyPress(e)
	{
		var keyCode = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;

		if(keyCode == 13)
		{

			if(e.preventDefault)
			{//비IE
				e.preventDefault();
				e.stopPropagation();

				insertText($('messageBox'), " ", false);// 현재 캐럿 위치에 공백문자를 넣어준다.
			}
			else
			{//IE

				e.keyCode = 32; // 공백이 눌린것 처럼.
				//e.returnValue = false;
	            //e.cancelBubble = true;
			}
			
			return false;
		}
		else
		{
			if(e.preventDefault)
			{//비IE
				timeObj = window.setTimeout("getCaretText($('messageBox'))", 50);
				timer = true;
			}
		}
	}

	var timeObj = "";
	function getCaretText(oField, e)
	{
		if(e != null)
		{
			var keyCode = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;

			if(keyCode == 40 && timer) //40 : 아래화살표, 38 : 윗화살표
			{
				isLock = true;
				setCaretPosition(oField, keydownCaretPos.start, 0);
				if(curCandiSel == null)
				{
					candidateMouseOver($('candidateLayer').firstChild,$('candidateLayer').firstChild);
				}
				else
				{
					if(curCandiSel.nextSibling == null)
					{
						candidateMouseOut(curCandiSel,curCandiSel);
						candidateMouseOver($('candidateLayer').firstChild,$('candidateLayer').firstChild);
					}
					else
					{
						candidateMouseOut(curCandiSel,curCandiSel);
						candidateMouseOver(curCandiSel.nextSibling,curCandiSel.nextSibling);
					}
				}
				replaceCandidateTag();
				return;
			}
			else if(keyCode == 38 && timer)
			{
				isLock=true;
				setCaretPosition(oField, keydownCaretPos.start, 0);
				if(curCandiSel == null)
				{
					candidateMouseOver($('candidateLayer').lastChild,$('candidateLayer').lastChild);
				}
				else
				{
					if(curCandiSel.previousSibling == null)
					{
						candidateMouseOut(curCandiSel,curCandiSel);
						candidateMouseOver($('candidateLayer').lastChild,$('candidateLayer').lastChild);
					}
					else
					{
						candidateMouseOut(curCandiSel,curCandiSel);
						candidateMouseOver(curCandiSel.previousSibling,curCandiSel.previousSibling);
					}
				}
				replaceCandidateTag();
				return;
			}
			else
			{
				isLock=false;
			}
		}

		if(!isLock)
		{

			// ajax로 서버에 전달할 태그워드를 얻는 역할.
			var oCaretPos = getCaretPosition(oField);
			
			if (caretPos != oCaretPos.start || oldVal != oField.value)
			{
				
				var textVal = oField.value;
				var restLen = 140 - textVal.length;
				$('restLength').innerHTML = restLen;
				if(restLen < 0)
				{
					$('confirm').disabled = true;
				}
				else
				{
					$('confirm').disabled = false;
				}
		
				if(oCaretPos.start > 0)
				{
					var ch;
					var cnt = 1;
					tagword = "";
					while(1)
					{
						if(oCaretPos.start - cnt < 0)
						{
							break;
						}
		
						ch = textVal.charAt(oCaretPos.start - cnt);
						
						if(ch == '\n' || ch == ' ' || ch == '\r')
						{
							break;
						}
						
						tagword = ch + tagword;
						cnt++;
					}
				}
				else
				{
					tagword = "";
				}
				
				oldVal = oField.value; 
				caretPos = oCaretPos.start;
	
				//var date = new Date();
				//$('trace2').innerHTML = oldVal + ":" + oField.value + ":" + date.toString();
				viewCandidateTag(tagword);
			}
			else {
				// nothing
			}

		}

		if(timer)
		{
			if(document.selection == null) // IE가 아닐때만 타이머를 실행하도록한다.
				timeObj = window.setTimeout("getCaretText($('messageBox'))", 50);
		}
		//if(e.preventDefault)
		//{//비IE
		//	window.setTimeout("getCaretText($('messageBox'))", 1);
		//}
		

		//var date = new Date();
		//$('trace').innerHTML = caretPos + ":" + oCaretPos.start + ":" + keydownCaretPos.start + ":" + date.toString();
	}
	
	
	document.observe("dom:loaded", function() {
		$('candidateLayer').clonePosition($('messageBox'), {'setHeight': false, 'offsetLeft': 0, 'offsetTop': 62});
	});
