if(typeof(gjs)=='undefined' || !gjs) gjs={};
if(typeof(addEvent)!='function') addEvent=function(node, evnt, handler){if(node.addEventListener){node.addEventListener(evnt, handler, false);return true;}else if(node.attachEvent){var r=node.attachEvent("on"+evnt, handler);return r;}else{return false;}}
function _$(node){if(typeof(node) == 'string'){var elm = document.getElementById(node);if(!elm){elm = document.getElementsByName(node);if(elm.length == 0) elm = null;else elm = elm[0];}return elm;}else if(typeof(node)=='object')return node;else return null;}
function loadJS(j){node=document.getElementById("ScriptContainer"),n=document.createElement("script");n.src=j;node.innerHTML="";node.appendChild(n);}
function hasClass(ele,cls){return _$(ele).className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));}
function addClass(ele,cls){ele=_$(ele);if(!hasClass(ele,cls)){ ele.className = cls+" "+ele.className;}}
function removeClass(ele,cls){ele=_$(ele);if(hasClass(ele,cls)){var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');ele.className=ele.className.replace(reg,' ');}}
function findRB(e){l=0;b=Math.floor((e.offsetHeight+e.clientHeight)/2);if(e.offsetParent) do{l+=e.offsetLeft;b+=e.offsetTop;}while(e=e.offsetParent);return {"x":l,"y":b};}
// AC Constructor
gjs.AutoCompleter=function(args){
	var target = args["target"]||"quote";
	var source = args["source"]||"ac.php?q=";
	this._selectionHandler_ = args["selectionHandler"]||function(){return;}
	this._clearHandler_ = args["clearHandler"]||function(){return;}
	this._timerDelay_ = args["timerDelay"]||1;
	this._count_ = args["count"]||10;

	this._id_ = "ac_"+Math.floor(Math.random()*10000000);
	gjs.AutoCompleter.AC_Map[this._id_] = this;
	this.init(target,source);
};

// Static Members
gjs.AutoCompleter.searchCache = {};
gjs.AutoCompleter.AC_Map = {};
gjs.AutoCompleter.Node_Map = {};
gjs.AutoCompleter.complete = function(options,target,q){
	var ac = gjs.AutoCompleter.AC_Map[target];
	if(!!ac && typeof(ac.complete)=='function') ac.complete(options,q);
};

// Actual Class
gjs.AutoCompleter.prototype={
	_index:-1,
	init:function(target,source){
		this._target_ = document.getElementById(target);
		this._source_ = source;
		this._target_._ac = this;
		this._active = false;
		gjs.AutoCompleter.Node_Map[target] = this;
		
		// Option Table
		var pos = findRB(this._target_);
		this._optTable_ = document.createElement("ol");
		this._optTable_.style.position = "absolute";
		this._optTable_.style.top = pos.y;
		this._optTable_.style.left = pos.x;
		this._optTable_.style.display = 'none';
		this._optTable_.style.width = this._target_.clientWidth+"px";
		addClass(this._optTable_,"gjsAC");
		this._target_.setAttribute('autocomplete','off');
		
		this._target_.parentNode.insertBefore(this._optTable_,this._target_);
		this._target_.parentNode.insertBefore(this._target_,this._optTable_);
		
		// Add Keyboard Events
		addEvent(this._target_,"keyup",this._key_up);
		addEvent(this._target_,"keydown",this._key_down);
		addEvent(this._target_,"keypress",this._key_press);
		addEvent(this._target_,"blur",this._blur);		
	},
	// Default Renderder
	_renderer:function(str,obj){},
	
	// Clear Handler
	_clear:function(){
		var inst = this._optTable_;
		setTimeout(function(){
			inst.style.display = 'none';
		},100);
		this._active = false;
	},
	
	// Request Thread
	_request:function(){
		var q = this._target_.value;
		var options = gjs.AutoCompleter.searchCache[q];
		if(typeof(options)!='undefined') this._process(options,q);
		else {
			this._optTable_.innerHTML = '';
			this._index = -1;
			if(typeof(this._source_)=='object' && this._source_ instanceof Array)
				this._filter(q);
			else if(typeof(this._source_)=='string' && q.length > 1)
				loadJS(this._source_+q+"&t="+this._id_+"&c="+this._count_);
		}
	},
	
	_select:function(index){
		this._target_.value = this._lastResults[index][1];
		//this._clear();
		if(typeof(this._selectionHandler_)=='function') 
			this._selectionHandler_.apply(this,[this._lastResults[index]]); 
	},
	
	_highlight:function(dontSelect){
		var optArr = this._optTable_.getElementsByTagName("li");
		if(this._index > optArr.length-1) this._index = optArr.length-1;
		if(this._index < 0) this._index = 0;
		for(var i=optArr.length-1;i>-1;i--)
			removeClass(optArr[i],"selected");
		if(this._index > -1 && this._index < optArr.length)
			addClass(optArr[this._index],"selected");
		if(typeof(dontSelect)=='undefined') this._select(this._index);
	},
	
	// Completion Handler
	complete:function(options,q){
		gjs.AutoCompleter.searchCache[q] = options;
		this._process(options,q);
	},
	_filter:function(q){
		var options = {};
		var r = new RegExp("^"+q);
		for(var i=0,c=0,l=this._source_.length;i<l && c<10;i++){
			if(!!this._source_[i].toLowerCase().match(r)){
				options[i]=[this._source_[i]];
				c++;
			}
		}
		this._process(options,q);
	},
	_process:function(options,q){
		this._lastResults = [];
		this._optTable_.innerHTML = '';
		i=0;
		for(opt in options){
			var l = document.createElement("li");
			if(typeof(options[opt][0])=="undefined") return;
			var label = options[opt][0];
			s = label.toLowerCase().indexOf(q.toLowerCase());
	  		m = label.substr(s,q.length);
	  		l.innerHTML = label.replace(m,m.bold());			
			this._optTable_.appendChild(l);
			l.setAttribute("class",(i%2==0)?"even":"odd");
			var id = this._target_.getAttribute("id")+"_li"+i;
			l.setAttribute("id",id);
			gjs.AutoCompleter.Node_Map[id] = this;

			this._lastResults[i] = [opt].concat(options[opt]);
			i++;
						
			// Add Mouse Events
			addEvent(l,"click",this._m_click);
			addEvent(l,"mouseover",this._m_over);
			addEvent(l,"mouseout",this._m_out);
		}
		this._active = true;
		this._optTable_.style.display = 'block';
	},
	
	// Keyboard Handlers
	_key_up:function(e){
		if(!e&&window.event) e = window.event;
		var node = (!!document.all)?e.srcElement:this;
		var inst = gjs.AutoCompleter.Node_Map[node.getAttribute("id")];
		if(typeof(inst._timer)!='undefined' && inst._timer != null){
			clearTimeout(inst._timer);
			delete(inst._timer);
		}
		switch(inst._key_){
			case 9:	// Tab
			case 13:// Enter
			case 27:// Esc
				inst._clear();
			case 37:// Left
			//case 38:// Up
			case 39:// Right
			//case 40:// Down
				return;
			case 38:// Up
				inst._index--;
				break;
			case 40:// Down
				inst._index++;
				break;
			default:
				if(inst._key_ > 32 || inst._key_ == 8){
					inst._timer = setTimeout(function(){inst._request.apply(inst,[]);},inst._timerDelay_);
					if(typeof(inst._clearHandler_)=='function') 
						inst._clearHandler_.apply(inst,[]);
				}
				return;
		}
		if(inst._active) inst._highlight();		
	},
	_key_press:function(e){
/*		if(!e&&window.event) e = window.event;
		var node = (!!document.all)?e.srcElement:this;
		var inst = gjs.AutoCompleter.Node_Map[node.getAttribute("id")];
		switch(inst._key_){
			case 38:// Up
				inst._index--;
				break;
			case 40:// Down
				inst._index++;
				break;
			default:
				return;
		}
		if(inst._active) inst._highlight();
*/
	},
	_key_down:function(e){
		if(!e&&window.event) e = window.event;
		var node = (!!document.all)?e.srcElement:this;
		var inst = gjs.AutoCompleter.Node_Map[node.getAttribute("id")];

		if(e) inst._key_ = e.keyCode;
		else  inst._key_ = e.which;
		switch(inst._key_){
			case 9:	// Tab
			case 13:// Enter
				setTimeout(function(){inst._target_.focus();},10);
		}		
	},
	_blur:function(e){
		var node = (!!document.all)?e.srcElement:this;
		var inst = gjs.AutoCompleter.Node_Map[node.getAttribute("id")];		
		setTimeout(function(){inst._clear();},10);
	},
	
	// Mouse Handlers
	_m_click:function(e){
		var node = (!!document.all)?e.srcElement:this;
		if(!node.tagName.toLowerCase().match("li")) return;
		var inst = gjs.AutoCompleter.Node_Map[node.getAttribute("id")];
		var index = node.getAttribute("id").indexOf("_li")+3;
		index=parseInt(node.getAttribute("id").substr(index));
		inst._select(index);
		
	},
	_m_over:function(e){
		var node = (!!document.all)?e.srcElement:this;
		//alert(node.tagName.toLowerCase());
//	    alert(node.tagName.toLowerCase.match("li"));
//		return;
		if(!node.tagName.toLowerCase().match("li")) return;
		var inst = gjs.AutoCompleter.Node_Map[node.getAttribute("id")];	
		addClass(node,"selected");
		var index = node.getAttribute("id").indexOf("_li")+3;
		index=parseInt(node.getAttribute("id").substr(index));
		inst._index = index;
		inst._highlight({});
	},
	_m_out:function(e){
		var node = (!!document.all)?e.srcElement:this;
		if(!node.tagName.toLowerCase().match("li")) return;
		var inst = gjs.AutoCompleter.Node_Map[node.getAttribute("id")];	
		removeClass(node,"selected");
		inst._index = -1;
	}
};