KeyBoard = function(ele, datasource, inputDefaultValue) {
	this.inputElement = ele;
	this.datasource = datasource;
	this.inputElement.autocomplete = "off";
	this.inputElement.otherAttr = "other";
	this.codelist = new Array();
	this.currentTrIndex = 0;
	
	// 初始化常量，使得文本框加载时有默认值
	this.inputDefaultValue = inputDefaultValue ? inputDefaultValue : "代码/名称";
	this.inputElement.value = this.inputDefaultValue;

	this.addEventListener("click", this.inputElement, this.draw, this);
	// 在文本框中按下键盘时，可以上下移动表格	this.addEventListener("keydown", this.inputElement, this.movetable, this);
	// 文本变化时重新绘制	this.addEventListener("keyup", this.inputElement, this.draw, this);
	// 为 document 添加 click 监听
	this.addEventListener("click", document, this.predispose, this);
	// 添加事件监听时附加参数	this.inputElement.attachment = this;
	document.attachment = this;
}

KeyBoard.prototype = {
	// 键盘的绘制	draw: function(eve) {
		var event = eve || window.event;
		var eveSrc = event.srcElement || event.target;
		var inputvalue = eveSrc.value.trim();
		
		// 如果文本框为默认值(初始化，现第一次放入鼠标入文本框)，使得文本框的内容为空("")
		if (this.inputElement.value == this.inputDefaultValue) {
			this.inputElement.value = "";
			// 清空后不绘制，直接返回
			return;
		}
		
		var keyCode = event.keyCode;
		// 若是 <ESC>、↑、→、↓、←，回车、则不绘制小键盘
		if (keyCode == 27 || keyCode == 38 || keyCode == 39 || keyCode == 40 || keyCode == 37 || keyCode == 13) {
			return;
		}
		
		// 首先清空 codelist
		this.codelist.length = 0;
		
		// 根据用户输入的内容匹配
		this.match(inputvalue);
		
		// 小键盘将处于 id 为 "stockcodeprompt" 的层中，若存在，删除，以便重绘
		var bodychilds = document.body.childNodes;
		for (var i = 0; i < bodychilds.length; i++) {
			if ((bodychilds[i].nodeType == 1) && bodychilds[i].id == "stockcodeprompt") {
				document.body.removeChild(bodychilds[i]);
				break;	
			}
		}
		
		// 小键盘所在的层
		var div = document.createElement("div");
		div.id = "stockcodeprompt";
		// 一个窗口可显示 11 条记录，少于 11 条记录的话不产生滚动条效果
		if (this.codelist.length >= 11) {
			div.className = "prompt_limit";
		} else {
			div.className = "prompt_common";
		}
		
		// 该 table 将放入 div 中
		var table = document.createElement("table");
		table.id = "promptlist";
		table.otherAttr = "other";
		table.border = 0;
		table.cellPadding = 2;
		table.cellSpacing = 0;
		table.width = "100%";
		
		// 下面两段不让选择表格中的文本
		table.onselectstart = function() {
			return false;	
		}
		
		table.onselect = function() {
			document.selection.empty();	
		}
		
		var tbody = document.createElement("tbody");
		table.appendChild(tbody);
		
		// 标题行
		var titleRow = table.insertRow(0);
		titleRow.className = "tr_item";
		var codeTd = titleRow.insertCell(0);
		codeTd.innerHTML = "股票代码";
		codeTd.align = "center";
		// “股票代码” 列占 25%
		codeTd.width = "25.5%";
		
		var nameTd = titleRow.insertCell(1);
		nameTd.innerHTML = "股票名称";
		nameTd.align = "center";
		// “股票名称” 列占 50%
		nameTd.width = "49%";
		
		var cnspellTd = titleRow.insertCell(2);
		cnspellTd.innerHTML = "股票拼音";
		cnspellTd.align = "center";
		// “股票拼音” 列占 25%
		cnspellTd.width = "25.5%";
		
		for (var i = 0; i < this.codelist.length; i++) {
			var stockcodeitem = this.codelist[i];
			
			var tr = table.insertRow(i + 1);
			tr.textvalue = stockcodeitem.c;
			tr.index = i + 1;
			// attinfo 存储更多信息
			tr.attinfo = stockcodeitem;
			tr.className = "tr_item_bg" + i % 2;
			
			// 股票代码
			var codeTdContent = tr.insertCell(0);
			codeTdContent.innerHTML = this.format(stockcodeitem.c);
			codeTdContent.align = "center";
			
			// 股票名称
			var nameTdContent = tr.insertCell(1);
			nameTdContent.innerHTML = this.format(stockcodeitem.n);
			nameTdContent.align = "center";
			
			// 股票拼音
			var cnspellContent = tr.insertCell(2);
			cnspellContent.innerHTML = this.format(stockcodeitem.p);
			cnspellContent.align = "center";
			
			this.addEventListener("click", tr, this.trClick, this);
			this.addEventListener("dblclick", tr, this.trdblClick, this);
		}
		
		// 为表格添加 keydown 事件
		this.addEventListener("keydown", table, this.movetable, this);
		
		// 检测当前选中的 row 是否存在(因此重绘了，重绘后的 codelist.length 有可能小于 currentTrIndex)
		if (table.rows[this.currentTrIndex] == null) {
			KeyBoard.currentTrIndex = 0;	
		}
		
		div.appendChild(table);
		// 确定 div 的位置
		var top = Gti.Common.getTop(this.inputElement);
		var left = Gti.Common.getLeft(this.inputElement);
		// var width = this.inputElement.clientWidth;
		var Height = this.inputElement.clientHeight; //Gti.common.getHeight(this.inputElement, false);
		
		/*
		alert("top: " + top + "\n\n" + 
					"left: " + left + "\n\n" + 
					// "width: " + width + "\n\n" + 
					"height: " + Height);
		*/
		
		div.style.position = "absolute";
		var browser = Gti.Common.browser.getBrowser();
		if (this.codelist.length <= 11) {
			switch (browser) {
				case Gti.Common.browser.IE6:
					div.style.left = left - 42 + "px";
					break;
				case Gti.Common.browser.IE7:
					div.style.left = left - 42 + "px";
					break;
				case Gti.Common.browser.Mozilla:
					div.style.left = left - 45 + "px";
					break;
			}
		} else {
			switch (browser) {
				case Gti.Common.browser.IE6:
					div.style.left = left - 78 + "px";
					break;
				case Gti.Common.browser.IE7:
					div.style.left = left - 65 + "px";
					break;
				case Gti.Common.browser.Mozilla:
					div.style.left = left - 65 + "px";
					break;
			}
		}
		
		div.style.top = top + Height + "px";
		document.body.appendChild(div);
	},
	
	format: function(str) {
		// 用户输入(即要被匹配的字符串)
		var matchedStr = this.inputElement.value;
		var index = str.toUpperCase().indexOf(matchedStr.toUpperCase());
		if (index == -1) {
			return str;
		}
		
		var span = document.createElement("span");
		
		// 创建匹配前的字符串层及设置其样式
		var beforeMatchedSpan = document.createElement("span");
		beforeMatchedSpan.className = "unmatched";
		
		// 创建匹配的字符串层及设置其样式
		var matchedspan = document.createElement("span");
		matchedspan.className = "matched";
		
		// 创建匹配后的字符串层及设置其样式
		var afterMatchedSpan = document.createElement("span");
		afterMatchedSpan.className = "unmatched";
		
		// 被匹配之前的字符串(黑字)
		beforeMatchedSpan.innerHTML = str.substring(0, index - 1);
		// 匹配的字符串(红字)
		matchedspan.innerHTML = matchedStr;
		// 匹配后的字符串(黑字)
		afterMatchedSpan.innerHTML = str.substring(index + matchedStr.length);
		
		span.appendChild(beforeMatchedSpan);
		span.appendChild(matchedspan);
		span.appendChild(afterMatchedSpan);
		
		return span.innerHTML;
	},
	
	trClick: function(eve) {
		var trEvent = eve || window.event;
		var trSrc = trEvent.target || trEvent.srcElement;
		
		while (trSrc.nodeName.toUpperCase() != "TR") {
			trSrc = trSrc.parentNode;
		}
		
		this.selectedData = trSrc.attinfo;
		
		// 用户选中某行时(onclick)，将当前行的索引(index) 保存到类属性中(KeyBoard.currentTrIndex)
		// this.currentTrIndex = trSrc.index;
		// this.changeTRClass(trSrc);
		
		
		this.evaluate(trSrc);
		this.dispose();
		
		// 单击表格的某行时，使文本框聚焦，此时按上下左右键可以上下翻动
		// 由于没有给文本框设置 focus 事件，因此使文本框聚焦时不会进行重绘
		this.inputElement.focus();
	},
	
	trdblClick: function(eve) {
		var trEvent = eve || window.event;
		var trSrc = trEvent.target || trEvent.srcElement;
		
		if (trSrc.nodeName.toUpperCase() == "TD") {
			trSrc = trSrc.parentNode;
		}
		
		this.evaluate(trSrc);
		this.dispose();
	},
	
	movetable: function(eve) {
		var event = eve || window.event;
		var eveSrc = event.srcElement || this;
		var keyCode = event.keyCode;

		// <ESC>
		if (keyCode == 27) {
			// 隐藏 div
			this.dispose();
			return;
		}
		
		var table = document.getElementById("promptlist");
		var rows = null;
		if (table != null) {
			rows = table.rows;
		}
		
		// ←，↑
		if (keyCode == 37 || keyCode == 38) {
			// promptlist 为 table 的 id
			if (rows != null) {
				this.currentTrIndex--;
				if (this.currentTrIndex < 0) {
					this.currentTrIndex += this.codelist.length + 1;
				}
				if (this.currentTrIndex <= 0) {
					this.currentTrIndex += this.codelist.length;
				}
				
				if (rows[this.currentTrIndex] != null) {
					this.changeTRClass(rows[this.currentTrIndex]);
				}
				
				document.getElementById("stockcodeprompt").scrollTop = Math.floor(this.currentTrIndex / 10) * 180;
			}
			return;
		}
		
		// →，↓
		if (keyCode == 39 || keyCode == 40) {
			// promptlist 为 table 的 id
			if (rows != null) {
				this.currentTrIndex = this.currentTrIndex + 1;
				if (this.currentTrIndex > this.codelist.length) {
					this.currentTrIndex = 1;
				}
				if (rows[this.currentTrIndex] != null) {
					this.changeTRClass(rows[this.currentTrIndex]);
				}
				
				document.getElementById("stockcodeprompt").scrollTop = Math.floor(this.currentTrIndex / 10) * 180;
			}
			return;
		}
		
		// 回车确定
		if (keyCode == 13) {
			if (this.currentTrIndex != 0 && rows[this.currentTrIndex] != null) {
				this.evaluate(rows[this.currentTrIndex]);
				// 文本框聚焦				this.inputElement.focus();
			} else {
				// 直接回车，用户有可嫩输入的是错误的代码，但系统将会分配给它一个默认值
				var obj = this.getSelectedData(this);
				this.inputElement.value = (obj == null ? this.datasource[0].c : obj.c);
				this.inputElement.focus();
				this.dispose();	
			}
		}
	},
	
	// 针对点击 document 来销毁小键盘，document 的任意元素被点击均会触发该事件
	// nodeName == "undefined":	Firefox
	// nodeName ==  "body"			IE
	predispose: function(eve) {
		var event = eve || window.event;
		var eveSrc = event.target || event.srcElement;
		
		if (eveSrc.nodeName.toUpperCase() == "TD") {
			while (true) {
				eveSrc = eveSrc.parentNode;
				if (eveSrc.nodeName.toUpperCase() == "TABLE") {
					break;	
				}
			}
		}
		
		if (eveSrc.otherAttr != "other") {
			this.dispose();	
		}
	},
	
	// 销毁小键盘
	dispose: function() {		
		// 小键盘将处于 id 为 "stockcodeprompt" 的层中，若存在，删除，以便重绘
		var bodychilds = document.body.childNodes;
		for (var i = 0; i < bodychilds.length; i++) {
			if ((bodychilds[i].nodeType == 1) && bodychilds[i].id == "stockcodeprompt") {
				document.body.removeChild(bodychilds[i]);
				break;	
			}
		}
		
		// 如果文本框的内容为空("")，销毁时还原成默认值
		if (this.inputElement.value.trim().length == 0) {
			this.inputElement.value = this.inputDefaultValue;
		}
	},
	
	// 为 input 赋值，并销毁 div
	evaluate: function(trSrc) {
		this.inputElement.value = trSrc.textvalue;
		
		// 随即销毁 div
		this.dispose();
	},
	
	// 匹配用户输入
	match: function(inputvalue) {
		for (var i = 0; i < this.datasource.length; i++) {
			// 根据股票代码搜集满足用户输入的集合
			if (this.datasource[i].c.indexOf(inputvalue, 0) != -1) {
				this.append(this.datasource[i]);
			}
			// alert("\"" + this.datasource[i].p.toUpperCase() + "\".indexOf(\"" + inputvalue.toUpperCase() + "\") = " + this.datasource[i].p.indexOf(inputvalue.toUpperCase()));
			// 根据汉语拼音搜集满足用户输入的集合
			if (this.datasource[i].p.toUpperCase().indexOf(inputvalue.toUpperCase(), 0) != -1) {
				this.append(this.datasource[i]);
			}
			
			// 根据股票中文名称搜集满足用户输入的集合
			if (this.datasource[i].n.indexOf(inputvalue, 0) != -1) {
				this.append(this.datasource[i]);
			}
			
			// 只匹配前 30 个，以节省内存消耗
			if (this.codelist.length > 29) {
				break;	
			}
		}
	},
	
	// 追加匹配的股票
	append: function(stockcodeobj) {
		var isExists = function(c, context) {
			var existence = false;
			for (var i = 0; i < context.codelist.length; i++) {
				if (context.codelist[i].c == c) {
					existence	= true;
					break;
				}
			}
			return existence;
		};
		
		if (!isExists(stockcodeobj.c, this)) {
			this.codelist[this.codelist.length++] = stockcodeobj;
		}
	},
	
	getSelectedData: function(thisobj) {
		var iterate = function(textvalue) {
			// 如果当前窗口只要一个匹配项，不管用户是否输入完整，均返回这唯一的匹配项
			if (thisobj.codelist.length == 1) {
				return thisobj.codelist[0];	
			}
			
			// 不止一个匹配项或没有匹配项时，首先遍历满足当前窗口的的集合
			for (var i = 0; i < thisobj.codelist.length; i++) {
				if (textvalue == thisobj.codelist[i].c ||
						textvalue == thisobj.codelist[i].n ||
						textvalue == thisobj.codelist[i].p) {
					return thisobj.codelist[i];
				}
			}
			
			// 当前窗口未找到，遍历全部
			for (var i = 0; i < thisobj.datasource.length; i++) {
				if (textvalue == thisobj.datasource[i].c ||
						textvalue == thisobj.datasource[i].n ||
						textvalue == thisobj.datasource[i].p) {
					return thisobj.datasource[i];
				}	
			}
			
			// 都未找到，返回 null
			return null;
		};
		
		// 数据源若为 null，直接返回 null
		if (!this.datasource) {
			return null;
		}
		
		var textvalue = thisobj.inputElement.value;
		if (textvalue.trim().length == 0) {
			return null;
		}
		
		if (thisobj.selectedData != null) {
			if (textvalue == thisobj.selectedData.c ||
					textvalue == thisobj.selectedData.n ||
					textvalue == thisobj.selectedData.p) {
				return thisobj.selectedData;	
			} else {
					return iterate(textvalue);
			}
		} else {
				return iterate(textvalue);
		}
	},
	
	changeTRClass: function(selectedTR) {
		// promptlistEle 为 table 元素
		var promptlistEle = document.getElementById("promptlist");
		if (promptlistEle != null) {
			var trs = promptlistEle.childNodes[0].getElementsByTagName("tr");
			for (var i = 0; i < trs.length; i++) {
				if (trs[i].textvalue == selectedTR.textvalue) {
					trs[i].className = "tr_item_onclick";	
				} else {
					trs[i].className = "tr_item_bg" + (i + 1) % 2;	
				}
			}
		}
	},
	
	/**
	 * @eventType	事件类型，例如："click"
	 * @eventSrc	事件源
	 * @eventHandler	事件处理函数
	 * @attachment		附加信息
	 */
	addEventListener: function(eventType, eventSrc, eventHandler, attachment) {
		var handler = eventHandler;
		
		if (attachment) {
			handler = function(eve) {
				eventHandler.call(attachment, eve);	
			}	
		}
		
		if (navigator.userAgent.indexOf("MSIE") > 0) {
			eventSrc.attachEvent("on" + eventType, handler);	
		} else if(isFirefox=navigator.userAgent.indexOf("Firefox") > 0) {
			eventSrc.addEventListener(eventType, handler, false);	
		}
	}
}

String.prototype.trim = function() {
	return this.replace(/(^\s*)|(\s*$)/g,"");	
}