// ---- types ----
Autocomplete.prototype.types = {};
Autocomplete.prototype.types._defaultFn = function(dublicate, listBox, node, container) {
	// this.setList = function(dublicate, arrList, listBox, container) {
	this.setList = function(arrList) {
		for (var i=0, l=arrList.length; i<l; i++) {
			var item = listBox.createItem("textItem").set("values.text", arrList[i]);
			item.events.addSubscriber("change", "values.hover", dublicate.addHoverToItemNode);
			container.addItem( item );
			listBox.miscDOM.event(item.getHTML(), "mousemove", dublicate.setHover);
			if (i==0) {
				item.set("values.hover", true);
			}
		}
		return dublicate;
	};
	// this.show = function(dublicate, container) {
	this.show = function() {
		var n=node, x=0, y=n.offsetHeight+1;
		while(n.offsetParent) {
			x += n.offsetLeft;
			y += n.offsetTop;
			n = n.offsetParent;
		}
		var containerNode = container.get("nodes.container");
		containerNode.style.position = "absolute";
		containerNode.style.left = x +"px";
		containerNode.style.top = y +"px";
		if (containerNode.style.display!="block") {
			containerNode.style.display = "block";
			var items = container.getAllItems();
			var matchCur;
			for (var i=0, l=items.length-1; i<l; i++) {
				if (items[i].get("values.text")==node.value) {
					items[i].set("values.hover", true);
					matchCur = true;
				} else {
					items[i].set("values.hover", false);
				}
			}
			if (!matchCur && items.length) items[0].set("values.hover", true);
		} else {
			containerNode.style.display = "block";
		}
		dublicate.events.fireEvent("show", "*", dublicate, false);
	};
	// this.hide = function(dublicate, container) {
	this.hide = function() {
		var items = container.getAllItems();
		for (var i=0, l=items.length; i<l; i++) {
			items[i].set("values.hover", false);
		}
		var containerNode = container.get("nodes.container");
		containerNode.style.display = "none";
	};
	// this.onSelect = function(evt, dublicate) {
	this.onSelect = function(evt) {
		var item = evt.target;
		node.value = item.get("values.text");
		dublicate.hide();
	};
	
	// this.attachToNode = function(dublicate, listBox) {
	this.attachToNode = function() {
		if (navigator.userAgent.toLowerCase().indexOf("opera")>-1) {
			listBox.miscDOM.event(node, "keypress", dublicate.onKeyPress);
		} else {
			listBox.miscDOM.event(node, "keydown", dublicate.onKeyPress);
		}
		listBox.miscDOM.event(node, "focus", dublicate.show);
		listBox.miscDOM.event(node, "click", dublicate.stopEvent);
		
		listBox.miscDOM.event(container.get("nodes.container"), "click", dublicate.onClick);
		
		dublicate.events.addSubscriber("selectItem", "*", dublicate.onSelect);
	};
	
	dublicate.stopEvent = function(evt) {
		var evt = evt || window.event;
		evt.cancelBubble = true;
		evt.returnValue = false;
		if (evt.stopPropagation) evt.stopPropagation();
		if (evt.preventDefault) evt.preventDefault();
	};
	
	// this.onClick = function(evt, dublicate, listBox, container) {
	this.onClick = function(evt) {
		var evt = evt || window.event;
		dublicate.stopEvent(evt);
		var el = evt.originalTarget || evt.srcElement;
		while( !listBox.miscDOM.hasClass(el, "item") ) el = el.parentNode;
		if (el) {
			var items = container.getAllItems();
			for (var i=0, l=items.length; i<l; i++) {
				if (items[i].get("nodes.item")==el) {
					dublicate.events.fireEvent("selectItem", "*", items[i], null);
					break;
				}
			}
		} 
	};
	
	// this.onKeyPress = function(evt, dublicate, container) {
	this.onKeyPress = function(evt) {
		// keyCodes:
		// 37 <     38 ^     39 >     40 v
		// 33 pageUp     34 pageDown     35 end     36 home
		var evt = evt || window.event;
		var keyCode = evt.keyCode;
		var items = container.getAllItems();
		/*
		if (keyCode==46) {
			// delete
			for (var i=0, l=items.length; i<l; i++) {
				if (items[i].get("values.hover")) {
					container.remItem(i);
					l--;
					if (l==0) {
						dublicate.hide();
						break;
					}
					if (i>=l) i=l-1;
					items[i].set("values.hover", true);
					break;
				}
			}			
		}
		*/
		if (keyCode==9) {
			// tab
			dublicate.hide();
		}
		if (keyCode==13) {
			// enter
			dublicate.stopEvent(evt);
			for (var i=0, l=items.length; i<l; i++) {
				if (items[i].get("values.hover")) {
					dublicate.events.fireEvent("selectItem", "*", items[i], null);
					break;
				}
			}			
		}
		if (keyCode==38) {
			// oneUp
			dublicate.stopEvent(evt);
			for (var i=1, l=items.length; i<l; i++) {
				if (items[i].get("values.hover")) {
					items[i].set("values.hover", false);
					items[i-1].set("values.hover", true);
					break;
				}
			}
		}
		if (keyCode==40) {
			// oneDown
			dublicate.stopEvent(evt);
			if (container.get("nodes.container").style.display!="block") {
				dublicate.show();
			} else {
				for (var i=0, l=items.length-1; i<l; i++) {
					if (items[i].get("values.hover")) {
						items[i].set("values.hover", false);
						items[i+1].set("values.hover", true);
						break;
					}
				}
			}
		}
		if (keyCode==33) {
			// pageUp
			for (var i=0, l=items.length; i<l; i++) {
				if (items[i].get("values.hover")) {
					var containerNode = container.get("nodes.container");
					var itemNode = items[i].get("nodes.item");
					containerNode.scrollTop = itemNode.offsetTop + itemNode.offsetHeight - containerNode.clientHeight;
					var i2 = 0;
					while( Math.max(items[i2].get("nodes.item").offsetTop, 0) < containerNode.scrollTop ) {
						i2++;
					}
					containerNode.scrollTop = items[i2].get("nodes.item").offsetTop;
					items[i].set("values.hover", false);
					items[i2].set("values.hover", true);
					break;
				}
			}
		}
		if (keyCode==34) {
			// pageDown
			for (var i=0, l=items.length; i<l; i++) {
				if (items[i].get("values.hover")) {
					var containerNode = container.get("nodes.container");
					containerNode.scrollTop = items[i].get("nodes.item").offsetTop;
					var y = containerNode.scrollTop + containerNode.clientHeight - items[i].get("nodes.item").offsetHeight;
					var i2 = i;
					while( i2<l && items[i2].get("nodes.item").offsetTop < y ) i2++;
					if (i2==l) i2--;
					items[i].set("values.hover", false);
					items[i2].set("values.hover", true);
					break;
				}
			}
		}
		if (keyCode==36) {
			// home
			for (var i=0, l=items.length; i<l; i++) {
				if (items[i].get("values.hover")) {
					if (i!=0) {
						items[i].set("values.hover", false);
						items[0].set("values.hover", true);
					}
					break;
				}
			}
		}
		if (keyCode==35) {
			// end
			for (var i=0, l=items.length; i<l; i++) {
				if (items[i].get("values.hover")) {
					if (i!=l-1) {
						items[i].set("values.hover", false);
						items[l-1].set("values.hover", true);
					}
					break;
				}
			}
		}
	};

	// this.setHover = function(evt, listBox, container) {
	this.setHover = function(evt) {
		var evt = evt || window.event;
		var el;
		/*
		if (evt.srcElement) {
			el = evt.srcElement;
			while( !listBox.miscDOM.hasClass(el, "item") ) el = el.parentNode;
		} else {
			el = evt.currentTarget;
		}
		*/
		el = evt.srcElement || evt.originalTarget;
		while( el && !listBox.miscDOM.hasClass(el, "item") ) el = el.parentNode;
		if (el) {
			var items = container.getAllItems();
			for (var i=0, l=items.length; i<l; i++) {
				if (items[i].get("nodes.item")==el) {
					if (!items[i].get("values.hover")) items[i].set("values.hover", true);
				} else {
					if (items[i].get("values.hover")) items[i].set("values.hover", false);
				}
			}
		}
	};
	
	// this.addHoverToItemNode = function(evt, listBox) {
	this.addHoverToItemNode = function(evt) {
		var val = evt.target.get(evt.path);
		if (val!=evt.oldValue) {
			var node = evt.target.get("nodes.item");
			if (val) {
				if (!listBox.miscDOM.hasClass(node, "hover")) node.className = (node.className || "") + " hover";
				var containerNode = container.get("nodes.container");
				var scroll = [containerNode.scrollTop];
				scroll[1] = scroll[0] + containerNode.clientHeight;
				var y = [node.offsetTop];
				y[1] = y[0] + node.offsetHeight;
				if (y[0]<scroll[0]) {
					containerNode.scrollTop = y[0] + 1;
				} else if (y[1]>scroll[1]) {
					containerNode.scrollTop = y[1] - containerNode.clientHeight;
				}
			} else {
				if (listBox.miscDOM.hasClass(node, "hover")) listBox.miscDOM.removeClass(node, "hover");
			}
		}
	};
};

Autocomplete.prototype.types.dataList = function(listBox, node) {
	var dublicate = this;
	ListBox.prototype._events.call(this, dublicate);
	
	var container = listBox.createContainer("defaultBox", "textItem");
	container.createHTML(true);
	container.hide();
	document.getElementsByTagName("body")[0].appendChild( container.get("nodes.container") );

	Autocomplete.prototype.types._defaultFn.call(this, dublicate, listBox, node, container);
	
	this.getListBox = function() { return listBox; }
	this.getNode = function() { return node; }
	this.getContainer = function() { return container; }
};

Autocomplete.prototype.types.customSelect = function(listBox, node) {
	var dublicate = this;
	ListBox.prototype._events.call(this, dublicate);
	var container = listBox.createContainer("defaultBox", "textItem");
	var header = listBox.miscDOM.cr("a", "custom-select-header", false, {href: "#"});
	container.createHTML(true);
	container.hide();
	document.getElementsByTagName("body")[0].appendChild( container.get("nodes.container") );

	Autocomplete.prototype.types._defaultFn.call(this, dublicate, listBox, node, container);

	this.setList = function(arrList) {
		var selectedIndex = 0;
		for (var i=0, l=arrList.length; i<l; i++) {
			var item = listBox.createItem("textItem").set("values.text", arrList[i].title).set("values.value", arrList[i].value).set("values.index", i);
			item.events.addSubscriber("change", "values.hover", dublicate.addHoverToItemNode);
			item.events.addSubscriber("change", "values.selected", dublicate.onSelect);
			if (arrList[i].selected) selectedIndex = i;
			container.addItem( item );
			listBox.miscDOM.event(item.getHTML(), "mousemove", dublicate.setHover);
			listBox.miscDOM.event(item.getHTML(), "click", dublicate.onClick);
			if (i==0) {
				item.set("values.hover", true);
			}
		}
		container.getItem(selectedIndex).set("values.selected", true);
		return dublicate;
	};

	this.attachToNode = function() {
		node.parentNode.insertBefore(header, node);
		node.style.display = "none";
		listBox.miscDOM.event(header, "click", dublicate.stopEventAndShow);
		if (navigator.userAgent.toLowerCase().indexOf("msie")>-1) {
			listBox.miscDOM.event(header, "keydown", dublicate.onKeyPressAndStop);
		} else {
			listBox.miscDOM.event(header, "keypress", dublicate.onKeyPressAndStop);
		}
		/*
		if (navigator.userAgent.toLowerCase().indexOf("opera")>-1) {
			listBox.miscDOM.event(header, "keypress", dublicate.onKeyPressAndStop);
		} else {
			listBox.miscDOM.event(header, "keydown", dublicate.onKeyPressAndStop);
		}
		*/
		/*
		listBox.miscDOM.event(node, "focus", dublicate.show);
		listBox.miscDOM.event(node, "click", dublicate.stopEvent);
		*/
		
		listBox.miscDOM.event(container.get("nodes.container"), "click", dublicate.onClick);
		dublicate.events.addSubscriber("selectItem", "*", dublicate.onSelect);
	};
	
	this.onKeyPressAndStop = function(evt) {
		dublicate.onKeyPress(evt);
		if (evt.keyCode!=9 || evt.keyCode!=116) {
			dublicate.stopEvent(evt);
			return false;
		}
	}
	
	this.stopEventAndShow = function(evt) {
		node.style.display = "block";
		dublicate.show();
		node.style.display = "none";
		dublicate.stopEvent(evt);
		return false;
	};
	
	this.onSelect = function(evt) {
		var item = evt.target;
		var val = item.get("values.selected");
		var div = item.getHTML();
		node.selectedIndex = item.get("values.index");
		header.innerHTML = item.get("values.text");
		var items = container.getAllItems();
		for (var i=0, l=items.length; i<l; i++) {
			if (items[i]!=item) {
				listBox.miscDOM.removeClass(items[i].getHTML(), "selected");
			} else {
				div.className += " selected";
			}
		}
		dublicate.hide();
	};
	
	/*
	this.changeHeader = function(myEvt) {
		var val = myEvt.target.get(myEvt.path);
		if (val) {
			header.innerHTML = myEvt.target.get("values.text");
		} else {
			header.innerHTML = "";
		}
	};
	*/
	
	this.show = function() {
		var n=header, x=0, y=n.offsetHeight+1;
		while(n.offsetParent) {
			x += n.offsetLeft;
			y += n.offsetTop;
			n = n.offsetParent;
		}
		y += header.offsetHeight +1;
		var containerNode = container.get("nodes.container");
		containerNode.style.position = "absolute";
		containerNode.style.left = x +"px";
		containerNode.style.top = y +"px";
		if (containerNode.style.display!="block") {
			containerNode.style.display = "block";
			container.getAllItems()[0].set("values.hover", true);
		} else {
			containerNode.style.display = "block";
		}
		dublicate.events.fireEvent("show", "*", dublicate, false);
	};
	
	this.getListBox = function() { return listBox; }
	this.getNode = function() { return node; }
	this.getContainer = function() { return container; }
};

Autocomplete.prototype.types.searchByKeyboard = function(listBox, node) {
	var dublicate = this;
	ListBox.prototype._events.call(this, dublicate);
	
	var container = listBox.createContainer("defaultBox", "textItem");
	container.createHTML(true);
	container.hide();
	document.getElementsByTagName("body")[0].appendChild( container.get("nodes.container") );

	Autocomplete.prototype.types._defaultFn.call(this, dublicate, listBox, node, container);
	
	this.getListBox = function() { return listBox; }
	this.getNode = function() { return node; }
	this.getContainer = function() { return container; }

	this.attachToNode = function() {
		if (navigator.userAgent.toLowerCase().indexOf("opera")>-1) {
			listBox.miscDOM.event(node, "keypress", dublicate.onKeyPress);
		} else {
			listBox.miscDOM.event(node, "keydown", dublicate.onKeyPress);
		}
		listBox.miscDOM.event(node, "keyup", dublicate.searchText);
		listBox.miscDOM.event(node, "focus", dublicate.show);
		listBox.miscDOM.event(node, "click", dublicate.stopEvent);
		
		listBox.miscDOM.event(container.get("nodes.container"), "click", dublicate.onClick);
		
		dublicate.events.addSubscriber("selectItem", "*", dublicate.onSelect);
	};

	/*
	this.attachToNode = function() {
		listBox.miscDOM.event(node, "keyup", dublicate.searchText);
	};
	*/
	
	this.searchText = function(evt) {
		// keyCodes:
		// 37 <     38 ^     39 >     40 v
		// 33 pageUp     34 pageDown     35 end     36 home
		var evt = evt || window.event;
		var keyCode = evt.keyCode;
		var t = true;
		var keyCodes = {"8":t,"17":t,"27":t,"46":t,"48":t,"49":t,"50":t,"51":t,"52":t,"53":t,"54":t,"55":t,"56":t,"57":t,"58":t,"59":t,"61":t,"65":t,"66":t,"67":t,"68":t,"69":t,"70":t,"71":t,"72":t,"73":t,"74":t,"75":t,"76":t,"77":t,"78":t,"79":t,"80":t,"81":t,"82":t,"83":t,"84":t,"85":t,"86":t,"87":t,"88":t,"89":t,"90":t,"96":t,"97":t,"98":t,"99":t,"100":t,"101":t,"102":t,"103":t,"104":t,"105":t,"106":t,"107":t,"108":t,"109":t,"110":t,"111":t,"188":t,"190":t,"191":t,"192":t,"219":t,"220":t,"221":t,"222":t};
		if ( keyCodes[keyCode] ) {
			var text = node.value;
			var items = container.getAllItems();
			var startsWith = [];
			// var matchText = [];
			for (var i=0, l=items.length, itemText, indexOf, match; i<l; i++) {
				itemText = items[i].get("values.text");
				indexOf = itemText.indexOf(text);
				if (indexOf>-1) {
					match = 0;
					while( indexOf+match<Math.min(itemText.length, text.length) && itemText.substring(indexOf+match, 1) && text.substring(indexOf+match, 1) ) match++;
				}
				if (indexOf==0) {
					startsWith.push({ item: items[i], match: match });
				} else {
					// matchText.push({ item: items[i], match: match });
				}
			}
			if (startsWith.length) {
				var max = 0;
				var maxOn = 0;
				for (var i=0, l=startsWith.length; i<l; i++) {
					if (startsWith[i].match<max) {
						max = startsWith[i].match;
						maxOn = i;
					}
				}
				for (var i=0, l=items.length; i<l; i++) {
					items[i].set("values.hover", startsWith[maxOn].item==items[i]);
				}
			}
		}
	};
};

Autocomplete.prototype.types.yandexSearch = function(listBox, node, url) {
	var dublicate = this;
	ListBox.prototype._events.call(this, dublicate);

	var container = listBox.createContainer("defaultBox", "searchPages");
	container.createHTML(true);
	container.hide();
	document.getElementsByTagName("body")[0].appendChild( container.get("nodes.container") );
	container.get("nodes.container").className += " yandexSearch";

	Autocomplete.prototype.types._defaultFn.call(this, dublicate, listBox, node, container);
	
	var lastQuery = "";
	var lastQueryTime = new Date();
	
	this.getListBox = function() { return listBox; };
	this.getNode = function() { return node; };
	this.getUrl = function() { return url; };

	this.setList = function(xmlDoc) {
		var items = xmlDoc.responseXML.getElementsByTagName("results")[0].getElementsByTagName("page");
		var oldItemsCount = container.getAllItems().length;
		for (var i=0; i<oldItemsCount; i++) container.remItem(0);
		// var myItems = [];
		for (var i=0, l=items.length; i<l; i++) {
			var item = listBox.createItem("searchPages").set("values.title", items[i].getAttribute("title")).set("values.href", items[i].getAttribute("href"));
			var arrP = [];
			var p = items[i].getElementsByTagName("passage");
			for (var i2=0, l2=p.length; i2<l2; i2++) {
				arrP.push(p[i2].textContent);
			}
			item.set("values.passages", arrP);
			item.events.addSubscriber("change", "values.hover", dublicate.addHoverToItemNode);
			// myItems.push(item);
			container.addItem(item);
			if (i==0) item.set("values.hover", true);
		}
		container.show();
	};
	// this.show = function(dublicate, container) {
	this.show = function() {
		var n=node, x=0, y=n.offsetHeight+1;
		while(n.offsetParent) {
			x += n.offsetLeft;
			y += n.offsetTop;
			n = n.offsetParent;
		}
		var containerNode = container.get("nodes.container");
		containerNode.style.position = "absolute";
		containerNode.style.left = x +"px";
		containerNode.style.top = y +"px";
		if (node.value!=lastQuery && (new Date())-lastQueryTime>=3000 ) {
			ajaxSend( url, {query: node.value}, dublicate.setList );
			lastQuery = node.value;
			lastQueryTime = new Date();
		} else if (container.getAllItems().length) {
			containerNode.style.display = "block";
			container.getAllItems()[0].set("values.hover", true);
		}
		dublicate.events.fireEvent("show", "*", dublicate, false);
		return dublicate;
	};

	// this.attachToNode = function(dublicate, listBox) {
	this.attachToNode = function() {
		if (navigator.userAgent.toLowerCase().indexOf("opera")>-1) {
			listBox.miscDOM.event(node, "keypress", dublicate.onKeyPress);
		} else {
			listBox.miscDOM.event(node, "keydown", dublicate.onKeyPress);
		}
		listBox.miscDOM.event(node, "focus", dublicate.show);
		listBox.miscDOM.event(node, "keyup", dublicate.reload);
		listBox.miscDOM.event(node, "click", dublicate.stopEvent);
		listBox.miscDOM.event(container.get("nodes.container"), "mousemove", dublicate.setHover);
		
		listBox.miscDOM.event(container.get("nodes.container"), "click", dublicate.onClick);
		
		dublicate.events.addSubscriber("selectItem", "*", dublicate.onSelect);
	};	

	this.onSelect = function(evt) {
		var item = evt.target;
		// node.value = item.get("values.text");
		alert( item.get("values.href") );
		dublicate.hide();
	};
	
	this.reload = function(evt) {
		// keyCodes:
		// 37 <     38 ^     39 >     40 v
		// 33 pageUp     34 pageDown     35 end     36 home
		var evt = evt || window.event;
		var keyCode = evt.keyCode;
		var t = true;
		var keyCodes = {"8":t,"17":t,"27":t,"46":t,"48":t,"49":t,"50":t,"51":t,"52":t,"53":t,"54":t,"55":t,"56":t,"57":t,"58":t,"59":t,"61":t,"65":t,"66":t,"67":t,"68":t,"69":t,"70":t,"71":t,"72":t,"73":t,"74":t,"75":t,"76":t,"77":t,"78":t,"79":t,"80":t,"81":t,"82":t,"83":t,"84":t,"85":t,"86":t,"87":t,"88":t,"89":t,"90":t,"96":t,"97":t,"98":t,"99":t,"100":t,"101":t,"102":t,"103":t,"104":t,"105":t,"106":t,"107":t,"108":t,"109":t,"110":t,"111":t,"188":t,"190":t,"191":t,"192":t,"219":t,"220":t,"221":t,"222":t};
		if ( keyCodes[keyCode] && node.value!=lastQuery && (new Date())-lastQueryTime>=3000 ) {
			ajaxSend( url, {query: node.value}, dublicate.setList );
			lastQuery = node.value;
			lastQueryTime = new Date();
		}
	};
};

// ---- /types ----
