var AutoComplete = Class.create();
AutoComplete.instances = {};
AutoComplete.gBeginAutoTag = function(textId,token,alias) {
	AutoComplete.instances[textId].beginAutoTag(token,alias);
};
AutoComplete.gSelectAutoTag = function(textId, item) {
	AutoComplete.instances[textId].selectAutoTag(item);
};
AutoComplete.gSelectTag = function(textId) {
	AutoComplete.instances[textId].selectTag();
};
AutoComplete.gLoadCallback = function(textId, response) {
	AutoComplete.instances[textId].loadCallback(response);
};
/*
 * options:
 * noPrefix: no colocar el prefijo al autocompletar
 * noAliases: colocar el tag principal cuando se autocomplete un alias
 */
AutoComplete.prototype = {
	initialize: function(textId, autoId, action, options) {
		this.textId = textId;
		this.autoId = autoId;
		this.action = action;
		this.options = options==null?{}:options;
	    this.textArea = $(textId);
	    this.autoArea = $(autoId);
	    this.initAuto = false;
	    this.tagList = null;
	    this.loadResponse = null;
	    this.tagsTimer = null;
	    this.currentTags = null;
	    this.lastLoad = null;
	    this.lastFilter = null;
	    AutoComplete.instances[textId] = this;
  	},
  	initAutoTagsArea: function() {
		if (!this.initAuto) {
			this.initAuto = true;
			var ul = document.createElement("ul");
			this.autoArea.appendChild(ul);
		
			var pos = findPos(this.textArea);
			this.autoArea.style.top = (pos[1] + this.textArea.offsetHeight) + "px";
			if (!this.options.rightAlign) {
				this.autoArea.style.left = pos[0] + "px";
			} else {
				this.autoArea.style.visibility = "hidden";
				this.autoArea.style.display = "";
				var l = this.autoArea.style.left = pos[0] + this.textArea.offsetWidth - this.autoArea.offsetWidth;
				this.autoArea.style.left = l + "px";
				this.autoArea.style.visibility = "";
			}
			
			this.autoArea.style.display = "none";
			
			if (this.options.clearOnFocus) {
				this.textArea.value = "";
			}
		}
  	},

  	selectAutoTag: function(item) {
		var lis = $$("#"+this.autoId+" ul li.selected");
		for(var i=0; i!= lis.length; i++) {
			lis[i].removeClassName("selected");
		}
		item.addClassName("selected");
	},
	onKeyPressAutoTags: function(event) {
		switch(event.keyCode) {
		case 38: //arrow up
			this.moveSelection(true);
			return false;
		case 40: //arrow down
			this.moveSelection(false);
			return false;
		case 13: //enter
			this.selectTag();
			return false;
		case 9: //tab
			//prepareAutoTag();
			return false;
		}
	},
	onKeyUpAutoTags: function(event) {	
		//flechas
		switch(event.keyCode) {
		case 38: //arrow up
		case 40: //arrow down
		case 13: //enter
		case 9: //tab
			return false;
		
		case 188: //,
			this.cancelLoad()
			this.endAutoTag();
			return true; 
			
		default:
			this.cancelLoad()
			this.prepareAutoTag();
			return true;
		}
	},
	cancelLoad: function() {
		if (this.tagsTimer) {
			window.clearTimeout(this.tagsTimer);
			this.tagsTimer = null;
		}
	},
	cancel: function() {
		this.cancelLoad();
		this.endAutoTag();
	},
	prepareAutoTag: function() {
		var caret = getCaret(this.textArea);
		var text = this.textArea.value;
		//log("| " + textArea + " - " + text);
		if (text != "" && caret != 0) {
			var i = 0;
			var alias = false;
			for (i=caret-1; i!=0; i--) {
				var c = text.charAt(i);
				if (c == ',') {
					i++;
					break;
				} else if (c == '>' || c == '=') {
					i++;
					alias = true;
					break;
				}
			}
			//log(i + " , " + caret);
			var token = text.substring(i,caret);
			token = token.trim();
			//log("token: " + token);
			if (token.match(/[a-z0-9]/i)) {
				//beginAutoTag(token,alias);
				this.tagsTimer = window.setTimeout("AutoComplete.gBeginAutoTag('"+this.textId+"','"+token+"',"+alias+")",250);
			} else {
				this.endAutoTag();
			}
		} else {
			this.endAutoTag();
		}
	},
	beginAutoTag: function(token,alias) {
		//clean
		ul = $$("#"+this.autoId+" ul")[0];
		ul.innerHTML = "";
		this.autoArea.style.display = "";
		var type = null;
		var firstChar = token.charAt(0);
		switch(firstChar) {
		case "@":
			type = "PERSON";
			break;
		case "#":
			type = "TOPIC";
			break;
		case "*":
			type = "OTHER";
			break;
		}
		if (type != null) {
			token = token.substring(1);
		}
		this.loadTags(type,token,alias);
	},
	loadTags: function(type, token, alias) {
		var prefix = token.split(/[^A-Za-z0-9]+/)[0].toLowerCase();
		this.lastFilter = {type:type, token:token, alias:alias, prefix:prefix};
		
		if (this.lastLoad != null) {
			if (prefix.match(new RegExp("\\b"+this.lastLoad.prefix))) {
				if (this.tagsList != null) {
					this.displayTags(type, token, alias);
					return;
				} else {
					return;
				}
			}
		}
		
		this.lastLoad = {type:type, token:token, alias:alias, prefix:prefix};
		this.tagsList = null;
		
		var func = null;
		eval("func = function(response) { AutoComplete.gLoadCallback('"+this.textId+"',response); }");
		
		new Ajax.Request(this.action,{
			parameters: {prefix: prefix, showAll: (this.options.onlyActive?"false":"true")},
			//onSuccess: this.loadCallback
			onSuccess: func 
		});
	},
	loadCallback: function(response) {
		var json = null;
		eval("json="+response.responseText+";");
		loadResponse = json;
		this.tagsList = loadResponse.tags;
		this.displayTags(this.lastFilter.type, this.lastFilter.token, this.lastFilter.alias);
	},
	displayTags: function(type, token, alias) {
		var ul = $$("#"+this.autoId+" ul")[0];
		var tags = [];
		var exp = new RegExp("\\b"+token.gsub(/\./, '\\.'),"i");
		for (var i=0; i!=this.tagsList.length; i++) {
			var tag = this.tagsList[i];
			if (tag.tag.match(exp) && (type == null || type == tag.type) && (!alias || !tag.target)) {
				tags[tags.length] = tag;
			}
		}
		if (tags.length > 0) {
			tags.sortBy(function(item) { return item.tag.toLowerCase().indexOf(token.toLowerCase()); });
			for (var i=0; i!=tags.length; i++) {
				var tag = tags[i];
				var li = document.createElement("li");
				if (i==0) {
					li.addClassName("selected");
				}
				var text = tag.target ? tag.tag + " &gt; " + tag.target : tag.tag;
				var index = text.search(exp);
					//text.toLowerCase().indexOf(token.toLowerCase());
				var length = token.length;
				var htmlText = text.substring(0,index) + "<b>" + text.substring(index,index+length) + "</b>" + text.substring(index+length,text.length);
				htmlText = htmlText.sub("&gt;"," <i>alias of</i> ");
				li.innerHTML = htmlText; 
				//li.onmouseover = selectAutoTag;
				li.onmouseover = new Function("AutoComplete.gSelectAutoTag('"+this.textId+"',this)");
				//li.onclick = selectTag;
				li.onclick = new Function("AutoComplete.gSelectTag('"+this.textId+"')");
				li.addClassName(tag.type);
				ul.appendChild(li);
			}
		} else {
			var li = document.createElement("li");
			li.innerHTML = "No matches";
			ul.appendChild(li);
		}
		this.currentTags = tags;
	},
	selectTag: function() {
		var lis = $$("#"+this.autoId+" ul li");
		for(var i=0; i!= lis.length; i++) {
			var li = lis[i];
			if (li.hasClassName("selected")) {
				var tag = this.currentTags[i];
				this.endAutoTag();
				
				var caret = getCaret(this.textArea);
				var text = this.textArea.value;
				var i = 0;
				if (caret > 0) {
					for (i=caret-1; i!=0; i--) {
						var c = text.charAt(i);
						if (c == ',') {
							i++;
							break;
						} else if (c == '>') {
							i++;
							break;
						}
					}
				}
				beginToken = i;
				for (i=caret; i!=text.length; i++) {
					var c = text.charAt(i);
					if (c == ',') {
						i++;
						break;
					}
				}
				endToken = i;
				var newToken = "";
				if (beginToken != 0) {
					newToken += " ";
				}
				
				var tokenPrefix = "";
				if (!this.options.noPrefix) {
					tokenPrefix = this.getChar(tag.type);
				}
				
				if (this.options.noAliases) {
					newToken += (tag.target ? tokenPrefix + tag.target : tokenPrefix + tag.tag);
				} else {
					newToken += (tag.target ? tag.tag + " > " + tokenPrefix + tag.target : tokenPrefix + tag.tag);
				}
				if (!this.options.noComa) {
					newToken += ", ";
				}
				var newText = text.substring(0,beginToken) + newToken + text.substring(endToken,text.length);
				this.textArea.value = newText;
				
				if (this.options.onSelectTag) {
					this.options.onSelectTag(newToken);
				}
				
				return;
			}
		}
	},
	getChar: function(type) {
		switch (type) {
		case 'PERSON':
			return '@';
		case 'TOPIC':
			return '#';
		case 'OTHER':
			return '*';
		default:
			return '?';
		}
	},
	endAutoTag: function() {
		$$("#"+this.autoId+" ul")[0].innerHTML = "";
		this.autoArea.style.display = "none";
		this.currentTags = null;
	},
	moveSelection: function(up) {
		var lis = $$("#"+this.autoId+" ul li");
		for(var i=0; i!= lis.length; i++) {
			var li = lis[i];
			//log(i+"/"+lis.length+" selected="+li.hasClassName("selected"));
			if (li.hasClassName("selected")) {
				if (up && i>0) {
					li.removeClassName("selected");
					lis[i-1].addClassName("selected");
				} else if (!up && i<lis.length-1) {
					li.removeClassName("selected");
					lis[i+1].addClassName("selected");
				}
				break;
			}
		}
	}
};

function findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft;
		curtop = obj.offsetTop;
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		}
	}
	return [curleft,curtop];
}

function getCaret(el) { 
  if (el.selectionStart) { 
    return el.selectionStart; 
  } else if (document.selection) { 
    el.focus(); 

    var r = document.selection.createRange(); 
    if (r == null) { 
      return 0; 
    } 

    var re = el.createTextRange(), 
        rc = re.duplicate(); 
    re.moveToBookmark(r.getBookmark()); 
    rc.setEndPoint('EndToStart', re); 

    return rc.text.length; 
  }  
  return 0; 
}
