/**
 * Author: Henry Huang, QQ: 192532, Email: hsl1230@yeah.net.
 * Function: 表格UI组件,任意级弹出菜单组件，弹出表格组件等
 * Description: 本脚本意在提供纯客户端UI组件，简化页面编程，目前作者正在开发更多的UI组件。
 *              与JavaScript Template Engine, JavaScript Validate Framework配合使用可大大提高开发效率和系统性能。
 * License: 本脚本可以自由使用，也可自行更改，但是必须标明更改缘由、位置和以下信息"原作者：Henry Huang, QQ: 192532, Email: hsl1230@yeah.net"。
 * TODO: 本脚本存在性能问题，尤其当返回的数据较多的时候更加明显，作者正在修正，性能有望提高5倍以上，但接口不会改变。
 * Date: 2006-07-08
 *
 * JavaScript Template Engine:    template.js
 * JavaScript Validate Framework: validator.js
 * Javascript UI Component:       supertable.js
 */

//var eventList = ["dblclick"];
var eventList = ["click", "contextmenu", "dblclick", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup"];

var tableEventHandler = {
	tableId: 0,
	//eventList: ["click", "contextmenu", "dblclick", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup"],
	eventList: ["dblclick"],
	tables: {},	
	attachedEvents: new StringBuffer().putEvents(eventList).toString(),
	resizeHandler: function() {
		var event = this.document.parentWindow.event;
		var tableId = this.id;
		tableId = tableId.replace(/^(.*)_layout$/g, "$1");
		var tableObj = tableEventHandler.tables[tableId];
		tableObj.processResize();
	},
	eventHandler: function () {
		var event = this.document.parentWindow.event;
		
		var tagName = this.tagName.toLowerCase();
		var containerTag = null;
		var tableId = null;
		var eventType = "";
		var col = null;
		var row = null;
		switch (tagName) {
			case 'td':
				row = this.parentElement.sectionRowIndex;
				var cells = this.parentElement.cells;
				for (var i=0; i<cells.length; i++) {
					if (cells(i) == this) {
						col = i;
						break;
					}
				}
				containerTag = this.parentElement.parentElement.tagName.toLowerCase();
				tableId = this.parentElement.parentElement.parentElement.id;
				eventType = "cell";
				break;
			case 'tr':
				row = this.sectionRowIndex;
				containerTag = this.parentElement.tagName.toLowerCase();
				tableId = this.parentElement.parentElement.id;
				eventType = "row";
				break;
			case 'table':
				tableId = this.id;
				break;
			default:
				containerTag = this.tagName.toLowerCase();			
				tableId = this.parentElement.id;
				break;
		}
		
		var tableObj = tableEventHandler.tables[tableId];
		var eventObject = tableObj;
		switch(containerTag) {
			case 'tbody':
				eventObject = tableObj.tbody;
				break;
			case 'thead':
				eventObject = tableObj.thead;
				break;
			case 'tfoot':
				eventObject = tableObj.tfoot;
				break;			
			case 'caption':
				eventObject = tableObj.caption;
				break;
		}
		
		var eventName = event.type.toLowerCase();
		event.consumer = this;
		if (eventObject["on" + eventType + eventName]) {
			return eventObject["on" + eventType + eventName].call(eventObject, event, col, row);
		}
	}
}

$e = tableEventHandler.eventHandler;

function Table(parent) {
	var logger = LoggerUtil.getLogger("com.henry.table.Table");
	
	var message = "";
	var self = null;
	
	var _width = null;//400;
	var _height = null;//800;
	var _parent = null;
	
	var _showborder = true;
	var _table = null;
	
	function Table() {
		try {
			logger.debug("Table.construct begining...");
			
			self = this;
			self.type = "table";
	
			self.attribute = {
				width: "100%",
				border: 0,
				cellPadding: "0",
				cellSpacing: "0",
				align: "center"
			};
			self.style = {};
			self.parent = parent;
	
			if (self.parent && !self.parent.htmlObject) {
				self.parent = {htmlObject: $(parent)};				
			}
	
			self.caption = new TableCaption(self);
			self.thead = new TableHead(self);
			self.tbody = new TableBody(self);
			self.tfoot = new TableFoot(self);

			self.htmlObject = null;
	
			self.id = "table_" + (tableEventHandler.tableId++);
			tableEventHandler.tables[self.id] = this;
			
			logger.debug("Table.construct succeed, id=[" + self.id + "]");
		}
		catch (e) {
			logger.error("Table.construct failed! id=[" + self.id + "]", e);
			throw e;		
		}
	}
		
	with (Table){
		prototype.setShowBorder = function(showborder) {
			_showborder = showborder;
			if (_table) {
				_table.setClass("border", showborder? "show":"hide");
			}
		}
		
		prototype.setParent = function(obj) {
			_parent = obj;
			return this;
		}
		prototype.getParent = function() {
			return _parent;
		}


		prototype.setWidth = function(theWidth) {
			_width = theWidth;
			
			var theParent = this;
			while (theParent.getParent()) {
				theParent = theParent.getParent();
			}
			
			if (theParent != this) {
				theParent.setAttribute("width", theWidth);
			}
			return this;
		}
		prototype.getWidth = function() {
			var elTable = _table.getElement();
			if (!elTable) {
				return _width;
			}
			else {
				return elTable.scrollWidth;
			} 
		}
		
		prototype.setHeight = function(theHeight) {
			_height = theHeight;
			var theParent = this;
			while (theParent.getParent()) {
				theParent = theParent.getParent();
			}
			
			if (theParent != this) {
				theParent.setAttribute("height", theHeight);
			}
			return this;
		}
		prototype.getHeight = function() {
			var elTable = _table.getElement();
			if (!elTable) {
				return _height;
			}
			else {
				return elTable.scrollHeight;
			} 
		}

		prototype.setMessage = function(text) {
			message = text;
		}
		
		prototype.getMessage = function() {
			return message;
		}
		
		/**
		 * 设置表格的标题文本
		 */
		prototype.setCaption = function(text) {
			if (!self.caption) {
				self.caption = new TableCaption(this);
			}
			self.caption.setText(text);
		}

		/**
		 * 设置表格的表头
		 * @param head 可以是二维数组,字符串,也可以是函数
		 * @param col  操作的列
		 * @param row  操作的行
		 */
		prototype.setHead = function(head, col, row) {
			if (!self.thead) {
				self.thead = new TableHead(this);
			}
			self.thead.setText(head, col, row);
		}
		
		prototype.setCellText = function(cellText, col, row) {
			if (!self.tbody) {
				self.tbody = new TableBody(this);
			}
			self.tbody.setText(cellText, col, row);
		}
		
		prototype.setCellData = function(data) {
			if (!self.tbody) {
				self.tbody = new TableBody(this);
			}
			self.tbody.setModelData(data);
			self.tbody.draw(0);	
		}

		prototype.setColumnIndices = function(columnIndices) {
			if (!self.thead) {
				self.thead = new TableHead(this);
			}
			self.thead.columnIndices = columnIndices;

			if (!self.tbody) {
				self.tbody = new TableBody(this);
			}
			self.tbody.columnIndices = columnIndices;			
		}

		prototype.setCellAction = function(cellAction, col, row) {
			if (!self.tbody) {
				self.tbody = new TableBody(this);
			}
			self.tbody.setCellAction(cellAction, col, row);
		}
		

		prototype.setFoot = function(foot) {
			if (!self.tfoot) {
				self.tfoot = new TableFoot(this);
			}
			self.tfoot.setText(foot);									
		}

		prototype.decorate = function() {
			var table = new com.henry.ui.TABLE("",self.id);
			_table = table;
			
			table.setAttributes({"border":"0", "cellPadding":"0", "cellSpacing":"0"});
			
			if (_showborder) {
				table.setClass("border", "show");
			}
			
			table.setStyle("width", _width);
			table.setStyle("height", _height);
			//table.setStyle("border", "solid 1px #ccc");
				
			var theDiv = new com.henry.ui.DIV();
			theDiv.setClass("table", "div");
			

			if (_height) {
				theDiv.setStyle("overflow-y", "scroll");
			}

			theDiv.addChild("table", this);
			

			if (self.caption) {
				table.addChild("caption", self.caption);
			}
			
			var tr = new com.henry.ui.TR();
			var td = new com.henry.ui.TD();
			
			//td.setAttribute("height", "100%");
			
			table.addChild("tr", tr);
			tr.addChild("td", td);
						
			td.addChild("content", theDiv);
	
			return table;
		}


		prototype.outerHTML = function(out) {
			try {
				logger.debug("Table.outerHTML begining, id=[" + self.id + "]...");
		
				if (!out) {
					out = new StringBuffer();
				}
				
				var attribute = self.attribute || {};
				var style = self.style || {};
				attribute.id = self.id;
				
				out.openTag(self.type)
					.putAttributes(attribute)
					.append(tableEventHandler.attachedEvents)
					.putStyles(style)
					.closeTag();
	
				var tableParts = [self.thead, self.tbody, self.tfoot];
				
				var old = null;
				for (var i=0; i<tableParts.length; i++) {
					if (tableParts[i]) {
						tableParts[i].outerHTML(out);
						old = i;
					}
				}
				
				out.endTag(self.type);
				
				if (self.getMessage()) {
					out.append(self.getMessage());
				}
				
				logger.debug("Table.outerHTML succeed, id=[" + self.id + "]");

				return out;
			}
			catch (ex) {
				logger.error("Table.outerHTML failed, id=[" + self.id + "]", ex);
				throw ex;
			}
		}
		
		prototype.toString = function() {
			return this.decorate().outerHTML().toString();
		}
		
		prototype.paint = function() {
			try {
				logger.debug("Table.paint begining, id=[" + self.id + "]...");
				var htmlString = self.toString();
				
				var showPlace = $(parent);
				
				showPlace.innerHTML = htmlString;
	
				self.htmlObject = showPlace.all(self.id)[1];
				
				
				self.caption.htmlObject = showPlace.all(self.id)[0].caption;
				self.thead.htmlObject = self.htmlObject.tHead;
				self.tbody.htmlObject = self.htmlObject.tBodies(0);
				self.tfoot.htmlObject = self.htmlObject.tFoot;
				
				logger.debug("Table.paint succeed, id=[" + self.id + "]");
			}
			catch (ex) {
				logger.error("Table.paint failed, id=[" + self.id + "]", ex);
				throw ex;
			}
			
			//$(parent).style.width = self.htmlObject.clientWidth;
		}
	}
	return new Table();
}

function TablePart(parent, type) {
	var logger = LoggerUtil.getLogger("com.henry.table.TablePart");

	var cellFormatTable = {
		date: function(format1, format2, defaultValue) {
			var f1 = format1;
			var f2 = format2
			return function(col, row) {
				var theCol = col;
				if (this.columnIndices) {
					if (typeof this.columnIndices[col] != "undefined") {
						theCol = this.columnIndices[col]
					}
				}
				
				var value = this.getModelData()[row][theCol];
				
				if (value == null || value.trim() == "") {
					if (typeof defaultValue != "undefined") {
						return defaultValue;
					}
					else {
						return value;
					}
				}
				
				return Date.parseDate(value, f1).format(f2);
			}
		},
		number: function(format, defaultValue) {
			var f = format;
			return function(col, row) {
				var theCol = col;
				if (this.columnIndices) {
					if (typeof this.columnIndices[col] != "undefined") {
						theCol = this.columnIndices[col]
					}
				}
				var value = this.getModelData()[row][theCol];
				
				if (typeof value == "number") {
					return new Number(value).format(f);
				}

				if (value == null || value.trim() == "") {
					if (typeof defaultValue != "undefined") {
						return defaultValue;
					}
					else {
						return value;
					}
				}
				return Number.parse(value, "#,##0.###").format(f);
			}
		},
		nvl: function(defaultValue) {
			var df = defaultValue;
			return function(col, row) {
				var theCol = col;
				if (this.columnIndices) {
					if (typeof this.columnIndices[col] != "undefined") {
						theCol = this.columnIndices[col]
					}
				}
				var value = this.getModelData()[row][theCol];
				if (value == null || value.trim() == "") {
					if (typeof df != "undefined") {
						return df;
					}
					else {
						return value;
					}
				}
				return value;
			}
		}
	};
	
	var self = null;
	var viewData = [];
	var modelData = [];
	var cellActionTable = {};
	
	var htmlBuffer = {rowBuffer:[], cellBuffer:[[],[]]};

	function TablePart() {
		try {
			logger.debug("TablePart[" + type + "].construct begining..., parent=[" + parent.id + "]");
			self = this;
			init();
			logger.debug("TablePart[" + type + "].construct succeed!] parent=[" + parent.id + "]");
		}
		catch (e) {
			logger.error("TablePart[" + type + "].construct failed! parent=[" + parent.id + "]", e);
			throw e;		
		}
	}

	function init() {
		self.style = null;
		self.attribute = null;
		self.rowStyle = null;
		self.rowAttribute = null;
		self.alterRowStyle = null;
		self.alterRowAttribute = null;
	
		self.columnStyle = null;
		self.columnAttribute = null;

		self.alterColumnStyle = null;
		self.alterColumnAttribute = null;

		self.columnsStyle = [];
		self.columnsAttribute = [];
		
		
		self.parent = parent;
		self.type = type;
		self.htmlObject = null;
		
		self.columnIndices = null;
		self.rowIndices = null;
		
		self.columnCount = 0;
		
		self.rowCount = 0;
	}
	
	
	function getProperNumber(indices, configLength, array) {
		if (!indices) {
			var indicesLength = 0; 
		}
		else {
			indicesLength = indices.length;
		}
				
		if (!array) {
			var arrayLength = 0;
		}
		else {
			arrayLength = array.length;
		}
		
		if (indicesLength >0) {
			return indicesLength;
		}
		else if (configLength > 0) {
			return configLength;
		}
		else if (arrayLength > 0) {
			return arrayLength;
		}
		return 0;
	}

	function insertRow(row, columnCount) {
		try {
			//logger.debug("TablePart[" + type + "]->insertRow begining..., parent=[" + parent.id + "]");
		
			if (!columnCount) {
				columnCount = getProperNumber(self.columnIndices, self.columnCount, row);
			}
			
			var rowData = [];
				
			for (var k=0; k<columnCount; k++) {
				if (typeof row == "function") {
					rowData[k] = row.call(self, k, viewData.length);
				}
				else if (typeof row == "string") {
					rowData[k] = row;
				}
				else {
					if (self.columnIndices) {
						if (self.columnIndices[k] != null && row[self.columnIndices[k]]) {
							rowData[k] = row[self.columnIndices[k]];
						}
						else {
							rowData[k] = "";
						}
					}
					else {
						rowData[k] = row[k];
					}
				}
			}
			
			if (viewData == null) {
				viewData = [];
			}
			
			viewData[viewData.length] = rowData;
			
			//logger.debug("TablePart[" + type + "]->insertRow succeed! parent=[" + parent.id + "]");
			return rowData;
		}
		catch (e) {
			logger.error("TablePart[" + type + "]->insertRow failed! parent=[" + parent.id + "]", e);
			throw e;
		}
	}

	var colActionFunction = [];
		
	function insertRowData(rowModelData) {
		try {
			logger.debug("TablePart[" + type + "]->insertRowData begining..., parent=[" + parent.id + "]");

			
			var rowCount = self.rowCount;
			if (! rowCount) {
				rowCount = getProperNumber(self.rowIndices, self.rowCount, modelData);
				self.rowCount = rowCount;
			}
			
			var columnCount = self.columnCount;	
			if (! columnCount) {
				columnCount = getProperNumber(self.columnIndices, self.columnCount, modelData[0]);
				self.columnCount = columnCount;
			}
	
	
			var i = modelData.length;
			
			modelData[i] = rowModelData;
			
			if (self.rowIndices) {
				if (modelData[self.rowIndices[i]]) {
					var rowObj = insertRow(rowModelData, columnCount);
				}
				else {
					var rowObj = insertRow("&nbsp;", columnCount);
				}
			}
			else {
				var rowObj = insertRow(rowModelData, columnCount);
			}
			
			if (colActionFunction.length == 0) {
				for (var k=0; k<columnCount; k++) {
					var f = self.getCellAction(k);
					if (typeof f == "function") {
						colActionFunction[k] = f;
					}
					else {
						colActionFunction[k] = null;
					}
				}
			}
			
			for (var k=0; k<columnCount; k++) {
				var f = colActionFunction[k];
				if (f != null) {
					viewData[i][k] = f.call(self, k, i);
				}
			}
			
			logger.debug("TablePart[" + type + "]->insertRowData succeed! parent=[" + parent.id + "]");
		}
		catch (e) {
			logger.error("TablePart[" + type + "]->insertRowData failed! parent=[" + parent.id + "]", e);
			throw e;
		}
		
	}	
	
	with(TablePart) {
		prototype.clear = function() {
			try {
				logger.debug("TablePart[" + type + "].clear begining..., parent=[" + parent.id + "]");
				var tableObj = self.parent.htmlObject;
				if (this.htmlObject) {
					var rows = this.htmlObject.children;
					var loopCount = rows.length;
					for (var i=0; i<loopCount; i++) {
						var row = rows(0);
						this.htmlObject.deleteRow(row.sectionRowIndex);
					}
				}
				viewData = [];
				logger.debug("TablePart[" + type + "].clear succeed! parent=[" + parent.id + "]");
			}
			catch (e) {
				logger.debug("TablePart[" + type + "].clear failed! parent=[" + parent.id + "]");
				throw e;
			}
		}
		
		prototype.deleteRow = function(rowIndex, noRepaint) {
			try {
				logger.debug("TablePart[" + type + "].deleteRow begining..., parent=[" + parent.id + "]");

				self.htmlObject.deleteRow(rowIndex);
				viewData.remove(rowIndex);
				var rowData = modelData.remove(rowIndex);
				if (!noRepaint) {
					self.repaint();
				}

				logger.debug("TablePart[" + type + "].deleteRow succeed! parent=[" + parent.id + "]");

				return rowData;
			}
			catch (e) {
				logger.error("TablePart[" + type + "].deleteRow failed! parent=[" + parent.id + "]", e);
				throw e;
			}
		}
		
		prototype.repaint = function() {
			try {
				logger.debug("TablePart[" + type + "].repaint begining..., parent=[" + parent.id + "]");

				Object.extend(self.htmlObject, self.attribute);
				Object.extend(self.htmlObject.style, self.style);
		
				
				var rows = self.htmlObject.children;
				
				for (var i=0; i<rows.length; i++) {
					var rowObj = rows(i);
					Object.extend(rowObj, self.rowAttribute || {});
					Object.extend(rowObj.style, self.rowStyle || {});
		
					if (i%2 != 0) {
						Object.extend(rowObj, self.alterRowAttribute || {});
						Object.extend(rowObj.style, self.alterRowStyle || {});
					}
					
					var cells = rowObj.cells;
					for (var k=0; k<cells.length; k++) {
						var cellObj = cells(k);
						Object.extend(cellObj, self.columnAttribute || {});
						Object.extend(cellObj.style, self.columnStyle || {});
		
						if (i%2 != 0) {
							Object.extend(cellObj, self.alterColumnAttribute || {});
							Object.extend(cellObj.style, self.alterColumnStyle || {});
						}					
		
						var columnStyle = self.columnsStyle[k] || {};
											
						var columnAttribute = self.columnsAttribute[k] || {};
						
						Object.extend(cellObj, columnAttribute);
						Object.extend(cellObj.style, columnStyle);
					}
				}
				logger.debug("TablePart[" + type + "].repaint succeed! parent=[" + parent.id + "]");
			}
			catch (e) {
				logger.error("TablePart[" + type + "].repaint failed! parent=[" + parent.id + "]", e);
				throw e;
			}
		}
	
		prototype.insertRow = function(row, noRepaint) {
			try {
				logger.debug("TablePart[" + type + "].insertRow begining..., parent=[" + parent.id + "]");
				insertRowData(row);
				var rowObj = self.htmlObject.insertRow();
	
				for (var i=0; i<eventList.length; i++) {
					var eventName = eventList[i];
					rowObj["on" + eventName] = function() {
						return this.document.parentWindow.$e.call(this);
					}
				}
				
				var rowViewData = viewData[viewData.length - 1];
				
				for (var k=0; k<rowViewData.length; k++) {
					var cellObj = rowObj.insertCell();
					//alert("row:" + (viewData.length - 1) + "," + rowViewData[k]);
					cellObj.innerHTML = rowViewData[k];					
				}
				
				if (!noRepaint) {	
					self.repaint();
				}

				logger.debug("TablePart[" + type + "].insertRow succeed! parent=[" + parent.id + "]");
			}
			catch (e) {
				logger.error("TablePart[" + type + "].insertRow failed! parent=[" + parent.id + "]", e);
				throw e;
			}			
		}
		
		prototype.insertRows = function(rows) {
			try {
				logger.debug("TablePart[" + type + "].insertRows begining..., parent=[" + parent.id + "]");
				for (var i=0; i<rows.length; i++) {
					self.insertRow(rows[i]);
				}
				logger.debug("TablePart[" + type + "].insertRows succeed! parent=[" + parent.id + "]");
			}
			catch (e) {
				logger.error("TablePart[" + type + "].insertRows failed! parent=[" + parent.id + "]", e);
				throw e;
			}			
		}

		prototype.setCellAction = function(cellAction, col, row) {
			try {
				logger.debug("TablePart[" + type + "].setCellAction begining..., parent=[" + parent.id + "]");
				if (typeof col != "number") {
					col = "ALL";
				}
				if (typeof row != "number") {
					row = "ALL";
				}
				
				cellActionTable["cellAction-" + col + "-" + row] = cellAction;
				logger.debug("TablePart[" + type + "].setCellAction succeed! parent=[" + parent.id + "]");
			}
			catch (e) {
				logger.error("TablePart[" + type + "].setCellAction failed! parent=[" + parent.id + "]", e);
				throw e;
			}			
		}
		
		prototype.getCellAction = function(col, row) {
			try {
				logger.debug("TablePart[" + type + "].getCellAction begining..., parent=[" + parent.id + "]");

				if (typeof col != "number") {
					col = "ALL";
				}
				if (typeof row != "number") {
					row = "ALL";
				}
			
				var ret = cellActionTable["cellAction-" + col + "-" + row] || "";

				logger.debug("TablePart[" + type + "].getCellAction succeed! parent=[" + parent.id + "]");
				
				return ret;
			}
			catch (e) {
				logger.error("TablePart[" + type + "].getCellAction failed! parent=[" + parent.id + "]", e);
				throw e;
			}			
		}
		
		
		prototype.setCellFormat = function(cellFormat, col, row) {
			try {
				logger.debug("TablePart[" + type + "].setCellFormat begining..., parent=[" + parent.id + "]");

				var p = cellFormat.split(":");
				var type = p[0];
				p = p[1].split("&&");
							
				var f = cellFormatTable[type].apply(this, p);
								
				self.setCellAction(f, col, row);

				logger.debug("TablePart[" + type + "].setCellFormat succeed! parent=[" + parent.id + "]");				
			}
			catch (e) {
				logger.error("TablePart[" + type + "].setCellFormat failed! parent=[" + parent.id + "]", e);
				throw e;
			}			
		}
	
		prototype.setText = function (text, col, row) {
			try {
				logger.debug("TablePart[" + type + "].setText begining..., parent=[" + parent.id + "]");
		
				if (typeof text == "function") {
					self.setCellAction(text, col, row);
				}
				
				var rows = self.getViewData();
				if (typeof col == "number" && typeof row == "number") {
					if (row >= rows.length) {
						throw new Error("out of bondary!");
					}
					else {
						var cellValue = "";	
						if (typeof text == "function") {
							cellValue = text.call(self, col, row);
						}
						else if (typeof text == "string") {
							cellValue = text;
						}
						else {
							cellValue = text[row][self.columnIndices[col]];
						}
						viewData[row][col] = cellValue;
					}
				}
				else if (typeof col == "number") {
					for (var i=0; i<viewData.length; i++) {
						this.setText(text, col, i);
					}
				}
				else if (typeof row == "number"){
					for (var k=0; k<self.columnIndices.length; k++) {
						this.setText(text, k, row);
					}				
				}
				else {
					if (typeof text == "object") {
						var len = Math.max(self.rowCount, text.length);
					}
					
					for (var i=0; i<len; i++) {
						if (i >= rows.length) {
							insertRow(text[i]);
						}
						else {
							for (var k=0; k<self.columnIndices.length; k++) {
								this.setText(text, k, i);
							}
						}
					}				
				}
				logger.debug("TablePart[" + type + "].setText succeed! parent=[" + parent.id + "]");				
			}
			catch (e) {
				logger.error("TablePart[" + type + "].setText failed! parent=[" + parent.id + "]", e);
				throw e;
			}			
		}
		
		prototype.setModelData = function(_data) {
			modelData = []; //_data;
			viewData = [];
			colActionFunction = [];
			
			for (var i=0; i<_data.length; i++) {
				insertRowData(_data[i]);
			}
		}
		
		prototype.getModelData = function() {
			return modelData;
		}
		
		prototype.getViewData = function() {
			return viewData;
		}
		
		prototype.draw = function(beginRowNum) {
			return;
			try {
				logger.debug("TablePart[" + type + "].draw begining..., parent=[" + parent.id + "]");

				if (modelData.length == 0) return;
				var rowCount = getProperNumber(self.rowIndices, self.rowCount, modelData);
				var columnCount = getProperNumber(self.columnIndices, self.columnCount, modelData[0]);
				self.columnCount = columnCount; 
							
				for (var i=beginRowNum; i<rowCount+beginRowNum/*&&i<modelData.length*/; i++) {
					if (self.rowIndices) {
						if (modelData[self.rowIndices[i]]) {
							var rowObj = insertRow(modelData[self.rowIndices[i]], columnCount);
						}
						else {
							var rowObj = insertRow("&nbsp;", columnCount);
						}
					}
					else {
						var rowObj = insertRow(modelData[i], columnCount);
					}
					
/*
					if (typeof self.getCellAction(1) == "function") {
							//alert(i);
							cellValue = self.getCellAction(1).call(self, 1, i);
							viewData[i][1] = cellValue;
					}

					if (typeof self.getCellAction(2) == "function") {
							//alert(i);
							cellValue = self.getCellAction(2).call(self, 2, i);
							viewData[i][2] = cellValue;
					}
					
					if (typeof self.getCellAction(3) == "function") {
							//alert(i);
							cellValue = self.getCellAction(3).call(self, 3, i);
							viewData[i][3] = cellValue;
					}

					if (typeof self.getCellAction(4) == "function") {
							//alert(i);
							cellValue = self.getCellAction(4).call(self, 4, i);
							viewData[i][4] = cellValue;
					}
*/
					/*
					for (var k=0; k<columnCount; k++) {
						var cellValue = null;
						if (typeof self.getCellAction(k, i) == "function") {
							cellValue = self.getCellAction(k, i).call(self, k, i);
						}
						else if (typeof self.getCellAction(k) == "function") {
							cellValue = self.getCellAction(k).call(self, k, i);
						}
						else if (typeof self.getCellAction(null, i) == "function") {
							cellValue = self.getCellAction(null, i).call(self, k, i);
						}
						else if (typeof self.getCellAction() == "function") {
							cellValue = self.getCellAction().call(self, k, i);
						}
						
						if (cellValue) {
							viewData[i][k] = cellValue;
						}
					}
					*/

				}
				logger.debug("TablePart[" + type + "].draw succeed! parent=[" + parent.id + "]");				
			}
			catch (e) {
				logger.error("TablePart[" + type + "].draw failed! parent=[" + parent.id + "]", e);
				throw e;
			}			
		}

		prototype.outerHTML = function (out) {
			try {
				logger.debug("TablePart[" + type + "].outerHTML begining..., parent=[" + parent.id + "]");
				
				if (!out) {
					out = new StringBuffer();
				}
		
				var attribute = self.attribute || {};
				var style = self.style || {};
							
				out.openTag(self.type)
					.putAttributes(attribute)
					.append(tableEventHandler.attachedEvents)
					.putStyles(style)
					.closeTag();
				
				for (var i=0; i<viewData.length; i++) {
									
					var rowData = viewData[i];
	
					if (!htmlBuffer.rowBuffer[i%2]) {
						var rowAttribute = {};
						var rowStyle = {};
						Object.extend(rowAttribute, this.rowAttribute || {});
						Object.extend(rowStyle, this.rowStyle || {});
		
						if (i%2 != 0) {
							Object.extend(rowAttribute, this.alterRowAttribute || {});
							Object.extend(rowStyle, this.alterRowStyle || {});
						}
		
						var innerOut = new StringBuffer();
								
						innerOut.openTag("tr")
							.putAttributes(rowAttribute)
							.append(tableEventHandler.attachedEvents)
							.putStyles(rowStyle)
							.closeTag();
						htmlBuffer.rowBuffer[i%2] = innerOut.toString();	
					}
					
					out.append(htmlBuffer.rowBuffer[i%2]);
	
					for (var k=0; k<rowData.length; k++) {
						var cellData = rowData[k];
						
						if (!htmlBuffer.cellBuffer[i%2][k]) {				
							var columnAttribute = {};
							
							var columnStyle = {};
							
							Object.extend(columnAttribute, self.columnAttribute || {});
							Object.extend(columnStyle, self.columnStyle || {});
		
							if (i%2 != 0) {
								Object.extend(columnAttribute, this.alterColumnAttribute || {});
								Object.extend(columnStyle, this.alterColumnStyle || {});
							}					
		
							var columnStyle1 = self.columnsStyle[k] || {};
												
							var columnAttribute1 = self.columnsAttribute[k] || {};
							
							Object.extend(columnAttribute, columnAttribute1);
							Object.extend(columnStyle, columnStyle1);
													
							var innerOut = new StringBuffer();
							
							if (rowData.length-1 == k) {
								var className = columnAttribute["className"];
								if (className) {
									className += " aw-table-tdRight";
								}
								else {
									className = "aw-table-tdRight";
								}
								columnAttribute["className"] = className;
							}
							
							innerOut.openTag("td")
								.putAttributes(columnAttribute)
						//		.append(tableEventHandler.attachedEvents)
								.putStyles(columnStyle)
								.closeTag();
								
							htmlBuffer.cellBuffer[i%2][k] = innerOut.toString();	
						}
						out.append(htmlBuffer.cellBuffer[i%2][k]);
						
						out.append(cellData);	
						out.endTag("td");
					}
					out.endTag("tr");
				}
	
				out.endTag(self.type);

				logger.debug("TablePart[" + type + "].outerHTML succeed! parent=[" + parent.id + "]");				

				return out;
			}
			catch (e) {
				logger.error("TablePart[" + type + "].outerHTML failed! parent=[" + parent.id + "]", e);
				throw e;
			}			
		}
	}
	
	return new TablePart();
}

function TableCaption(table) {
	var logger = LoggerUtil.getLogger("com.henry.table.TableCaption");

	var self = null;
	function init() {
		self.style = null;
		self.attribute = {className:"aw-table-caption "};
		self.parent = table;
		self.type = "caption";
		self.text = null;
		self.htmlObject = null;
	}
	
	function TableCaption() {
		try {
			logger.debug("TableCaption.construct begining..., parent=[" + table.id + "]");
			self = this;
			init();
			logger.debug("TableCaption.construct succeed! parent=[" + table.id + "]");
		}
		catch (e) {
			logger.error("TableCaption.construct failed! parent=[" + table.id + "]", e);
			throw e;
		}			
	}
	
	with(TableCaption) {
		prototype.clear = function() {
			try {
				logger.debug("TableCaption.clear begining..., parent=[" + table.id + "]");
		
				var tableObj = self.parent.htmlObject;
				tableObj.deleteCaption();
				
				logger.debug("TableCaption.clear succeed! parent=[" + table.id + "]");
			}
			catch (e) {
				logger.error("TableCaption.clear failed! parent=[" + table.id + "]", e);
				throw e;
			}			
		}

		prototype.outerHTML = function(out) {
			if (!self.text) {
				return out;
			}

			try {
				logger.debug("TableCaption.outerHTML begining..., parent=[" + table.id + "]");
				
				
				var attribute = self.attribute || {};
				var style = self.style || {};
				
				out.openTag("tr")
					 .closeTag();
				
				out.openTag("td")
					.putAttributes(attribute)
					.append(tableEventHandler.attachedEvents)
					.putStyles(style)
					.closeTag();
				out.append(self.text);
				out.endTag("td");

				out.endTag("tr");
				logger.debug("TableCaption.outerHTML succeed! parent=[" + table.id + "]");

				return out;
			}
			catch (e) {
				logger.error("TableCaption.outerHTML failed! parent=[" + table.id + "]", e);
				throw e;
			}			
		}

		prototype.setText = function(text) {
			self.text = text;
		}
	}
	return new TableCaption();
}

function TableHead(table) {
	var thead = new TablePart(table, "thead");
	thead.rowAttribute = {
		className: "aw-table-header"
	};

	thead.columnStyle = {
		fontWeight: "bold"
	};
	thead.columnAttribute = {
		align: "center",
		className: "getTableTD0"
	};

	return thead;
}

function TableBody(table) {
	var logger = LoggerUtil.getLogger("com.henry.table.TableBody");

	var lastRow = null;
	
	var tbody = new TablePart(table, "tbody");
		
	tbody.rowAttribute = {
		className: "aw-table-row"
	};

	tbody.columnStyle = {backgroundColor: "#E7E7E7"};
	tbody.alterColumnStyle = {backgroundColor: "#FFFFFF"};
	//tbody.alterColumnStyle = {backgroundColor: "#80ffff"};
	tbody.columnAttribute = {
		align: "center",
		className: "getTableTD0"
	};
	
	tbody.lightRow = function(objRow, mkLight) {
		try {
			logger.debug("TableBody.lightRow begining..., parent=[" + table.id + "]");
		
			objRow = objRow || lastRow;
			if (objRow == null) return;
	
			var theCells = objRow.cells;
			for (var i=0; i<theCells.length; i++) {
				var theColor = theCells(i).style.color;
				var theBackgroundColor = theCells(i).style.backgroundColor;
	
				if (typeof theCells(i).oldColor == "undefined") {
					theCells(i).oldColor = theColor;
				}
				if (typeof theCells(i).oldBackgroundColor == "undefined") {
					theCells(i).oldBackgroundColor = theBackgroundColor;
				}
				
				if (mkLight) {
					theCells(i).style.color = "white";
					theCells(i).style.backgroundColor = "blue";
					lastRow = objRow;
				}				
				else {
					theCells(i).style.color = theCells(i).oldColor;
					theCells(i).style.backgroundColor = theCells(i).oldBackgroundColor;					
				}				
			}
			
			logger.debug("TableBody.lightRow succeed! parent=[" + table.id + "]");
		}
		catch (e) {
			logger.error("TableBody.lightRow failed! parent=[" + table.id + "]", e);
			throw e;
		}			
	}

	tbody.highLightRow = function(el) {
		try {
			logger.debug("TableBody.highLightRow begining..., parent=[" + table.id + "]");
		
			var objRow = el || this;
			if (objRow == null) return;
			if (lastRow != null) {
				this.lightRow(lastRow, false);
			}
			this.lightRow(objRow, true);			
			logger.debug("TableBody.highLightRow succeed! parent=[" + table.id + "]");
		}
		catch (e) {
			logger.error("TableBody.highLightRow failed! parent=[" + table.id + "]", e);
			throw e;
		}			
	}

	return tbody;
}

function TableFoot(table) {
	return new TablePart(table, "tfoot");
}

var SuperTable = Table;	

function PopupTable(win) {
	var self = null;


	function PopupTable() {
		var popup = win.createPopup();
		var popupDoc = popup.document;
		
		popupDoc.clear();
		
		var contextRoot = top.ebankBasepath;
		if (typeof contextRoot == "undefined") {
			try {
				contextRoot = window.opener.top.ebankBasepath;
			}
			catch(ex) {
				contextRoot = ".";
			}
		}
		
		window.status = (contextRoot);
		
		popupDoc.write('<link rel="stylesheet" href="' + contextRoot + '/css/person.css"><link rel="stylesheet" href="' + contextRoot + '/js/ui/xp/ScrollTable.css"><body class="menu-body" oncontextmenu="return false;"><div class="outer-border"><div id="menuArea" class="inner-border"></div></div></body>');				
		
		var menuPlace = popupDoc.all("menuArea");
				
		var popupTable = new Table(menuPlace);
		
		popupTable.setShowBorder(false);

		menuPlace.document.parentWindow.$e = win.$e;
		
		popupTable.popupWindow = popup;
		popupTable.win = win;
		
		// set menu table attributes and styles
		popupTable.tbody.columnAttribute.noWrap = "true";
		
		popupTable.computePos = function(el) {
			var width = this.parent.htmlObject.scrollWidth + 4;
			var height = this.parent.htmlObject.scrollHeight + 4;
			
			window.status = "width:" + width + "; height:" + height;
			
			var left = win.event.screenX;

			var top = win.event.screenY;

			if (win != window) {
				left = left - win.event.clientX + el.getBoundingClientRect().right - 3;
				top = top - win.event.clientY + el.getBoundingClientRect().top;
				if (left + width > win.screen.availWidth) {
					left = left - el.getBoundingClientRect().right - width + 6;
				}
				if (top + height > win.screen.availHeight) {
					top = top - el.getBoundingClientRect().top - height;
				}
			}
			else {
				if (left + width > win.screen.availWidth) {
					left = left - width;
				}
				if (top + height > win.screen.availHeight) {
					top = top - height;
				}
			}
			return {left: left, top: top, width: width, height: height};
		}

		popupTable.show = function(el) {
			this.popupWindow.show(0, 0, 1, 1);
			
				var pos = this.computePos(el);
		
				this.tbody.lightRow(null, false);
				this.popupWindow.show(pos.left, pos.top, pos.width, pos.height);
		}
		
		popupTable.hide = function() {
			this.popupWindow.hide();
		}
		
		return popupTable;			
	}
	
	return new PopupTable();	
}



function Menu(parentMenu) {
	var self = null;
	function Menu() {
		self = this;
		this.m_parentMenu = parentMenu;
		this.m_menuItems = [];
		this.m_menuTable = null;
		this.m_showSubMenu = null;
	}
	
	function addMenuItem(type, label, action, logo) {
		var menuItem = new MenuItem(type, label, action, logo);
		menuItem.menu = self;
		self.m_menuItems[self.m_menuItems.length] = menuItem;
		if (type == "submenu") {
			action.m_parentMenu = self;
		}
	}
	
	with (Menu) {		
		prototype.addMenuItem = function(label, action, logo) {
			addMenuItem("menuItem", label, action, logo);
		}
		prototype.addSeparator = function() {
			addMenuItem("separator");
		}
		prototype.addSubMenu = function(label, submenu, logo) {
			addMenuItem("submenu", label, submenu, logo);
		}
		
		prototype.createHTMLObject = function() {
			if (!this.m_menuTable) {
				var win = window;
				if (this.m_parentMenu != null) {
					win = this.m_parentMenu.m_menuTable.htmlObject.document.parentWindow;
				}
				this.m_menuTable = new PopupTable(win);

				// set menu table attributes and styles
				this.m_menuTable.tbody.columnAttribute = this.m_menuTable.tbody.columnAttribute || {};
				
				this.m_menuTable.tbody.columnAttribute.noWrap = "true";
				
				this.m_menuTable.tbody.alterColumnStyle = null;
				
				//this.m_menuTable.attribute = this.m_menuTable.attribute || {};
				
				/*
				Object.extend(this.m_menuTable.attribute, 
					{
						cellPadding: 0,
						cellSpacing: 0,
						oncontextmenu: function () {
							return false;
						}
					}
				);
				*/
				
				//this.m_menuTable.tbody.rowAttribute = null;				

				// generate menu table data
				var menuData = [];
				for (var i=0; i<this.m_menuItems.length; i++) {
					menuData.push(this.m_menuItems[i].toDataArray());
				}
				
				this.m_menuTable.setColumnIndices([1,2,3]);
				this.m_menuTable.setCellData(menuData);	
				this.m_menuTable.paint();
				
				self.bindEvents();			
			}
		}
				
		prototype.show = function(el) {
			this.createHTMLObject();

			if (this.m_parentMenu != null) {
				this.m_parentMenu.m_showSubMenu = this;
				this.m_menuTable.htmlObject.document.dataObject = this.m_parentMenu.m_menuTable.htmlObject.document.dataObject;
			}
			else {
				this.m_menuTable.htmlObject.document.dataObject = (el||this);
			}


			this.m_menuTable.show(el);
		}

		prototype.hide = function() {
			this.m_menuTable.hide();
			
			if (this.m_parentMenu != null) {
				this.m_parentMenu.m_showSubMenu = null;
			}			
		}


		prototype.bindEvents = function() {
			self.m_menuTable.tbody.onrowclick = function(event, col, row) {
				var menuItem = this.getModelData()[row][0];
				menuItem.menu.hide();
				if (menuItem.type == "menuItem") {
					if (typeof menuItem.action == "function") {
						menuItem.action.call(menuItem, menuItem.menu.m_menuTable.htmlObject.document.dataObject);
					}
					else if (typeof menuItem.action == "string") {
						window.navigate(menuItem.action);
					}
				}
			}
			
			self.m_menuTable.tbody.onrowmouseover = function(event, col, row) {
				var menuItem = this.getModelData()[row][0];
				if (menuItem.type == "menuItem") {
					if (menuItem.menu.m_showSubMenu != null) {
						menuItem.menu.m_menuTable.tbody.lightRow(null, false);
						menuItem.menu.m_showSubMenu.hide();
					}
					menuItem.menu.m_menuTable.tbody.lightRow(event.consumer, true);					
				}
				else if (menuItem.type == "submenu") {
					var submenu = menuItem.action;
					submenu.show(event.consumer);
					menuItem.menu.m_menuTable.tbody.lightRow(event.consumer, true);
				}
			}

			self.m_menuTable.tbody.onrowmouseout = function(event, col, row) {
				var menuItem = this.getModelData()[row][0];
				if (menuItem.type == "menuItem") {
					menuItem.menu.m_menuTable.tbody.lightRow(event.consumer, false);
				}
				else if (menuItem.type == "submenu") {
					if (menuItem.menu.m_showSubMenu == null) {
						menuItem.menu.m_menuTable.tbody.lightRow(event.consumer, false);
					}
				}
			}

			self.m_menuTable.tbody.onrowmousedown = function(event, col, row) {
				var menuItem = this.getModelData()[row][0];
				if (menuItem.type == "submenu") {
					var submenu = menuItem.action;
					submenu.show(event.consumer);
					menuItem.menu.m_menuTable.tbody.lightRow(event.consumer, true);
				}
			}			
		}
	}

	return new Menu();
}

function MenuItem(type, label, action, logo) {
	var self = null;
	function MenuItem() {
		self = this;
		this.menu = null;
		this.type = type || "menuItem";
		this.logo = logo;
		this.label = label;
		this.action = action;
	}
	with(MenuItem) {
		prototype.toDataArray = function() {
			if (this.type == "menuItem") {
				return [this, this.logo? "<img style='margin:2 2 2 2' src=" + this.logo + ">":"&nbsp;&nbsp;", "&nbsp;" + this.label, "&nbsp;&nbsp;"];
			}
			else if (this.type == "submenu") {
				return [this, this.logo? "<img style='margin:2 2 2 2' src=" + this.logo + ">":"&nbsp;&nbsp;", "&nbsp;" + this.label, "&nbsp;&nbsp;<img src=doc_Auditing.gif>"];
			}
			else {
				return [this, "<hr>","<hr>","<hr>"];
			}
		}
	}
	return new MenuItem();
}
