/*---------------------------------------------------------------------------
 * XMLTable Constructor
 *
 * @ param xml			the XML DOM containing the data
 * @ param table		the table object that needs to be filled
 * @ param evenOnly		only draw on even rows (leave the other rows alone,
 *                      for visual reasons)
 *-------------------------------------------------------------------------*/
XMLTable = function(xml, table, evenOnly) {
	this.xml = xml;
	this.table = table;
	this.evenOnly = evenOnly;

	this.columns = new Object;
	this.columnOrdering = [0, "asc"];
	
	this.initialized = false;
	
	this.indicatorUpText="u";
	this.indicatorDownText="d";
	this.indicatorEqualText="e";
	
	this.linkPrefix = "/jsp/kredir.jsp?c=";
}


/*-----------------------------------------------------------------------------
 * XMLTable method setXML
 *
 * set the XML
 *
 * @param	xml		the XML document to set
 *---------------------------------------------------------------------------*/
XMLTable.prototype.setXML = function(xml) {
	this.xml = xml;
}


/*-----------------------------------------------------------------------------
 * XMLTable method setTable
 *
 * set the Table
 *
 * @param	table		the table object to set
 * @param	evenOnly	only draw on even rows (leave the other rows alone,
 *                      for visual reasons)
 *---------------------------------------------------------------------------*/
XMLTable.prototype.setTable = function(table, evenOnly) {
	this.table = table;
	this.evenOnly = evenOnly;
}


/*-----------------------------------------------------------------------------
 * XMLTable method setLinkPrefix
 *
 * set the Prefix for regular links
 *
 * @param	prefix		the link prefix to set
 *---------------------------------------------------------------------------*/
XMLTable.prototype.setLinkPrefix = function(prefix) {
	this.linkPrefix = prefix;
}


/*-----------------------------------------------------------------------------
 * XMLTable method build
 *
 * fill the table
 *---------------------------------------------------------------------------*/
XMLTable.prototype.build = function() {
	this.traverseXMLTable(this.table, this.xml, this.setTableCellValue);
	this.initialized = true;
}


/*-----------------------------------------------------------------------------
 * XMLTable method addColumn
 *
 * add a column definition to the table
 *
 * @param colNumber		the column number to add
 * @param nodeName		the xml node-name to retrieve the data from
 * @param type			type of data (one of: text, float, int, time)
 *---------------------------------------------------------------------------*/
XMLTable.prototype.addColumn = function(colNumber, nodeName, type) {
	var attrNodeName = "";
	var directionNodeName = "";
	if(nodeName.indexOf(';') > -1) {
		var nodeNameSplit = nodeName.split(";");
		nodeName = nodeNameSplit[0];
		attrNodeName = nodeNameSplit[1];
		directionNodeName = nodeNameSplit[2];
	}

	this.columns[nodeName] = [colNumber, type, attrNodeName, directionNodeName];
}	

/*-----------------------------------------------------------------------------
 * XMLTable method setIndicator*
 *
 * set the text of the column type 'indicator' (probably images of arrows)
 *
 * @param text		the text to use for the three indicator settings
 *---------------------------------------------------------------------------*/
XMLTable.prototype.setIndicatorUp = function(text) {
	this.indicatorUpText = text;
}
XMLTable.prototype.setIndicatorDown = function(text) {
	this.indicatorDownText = text;
}
XMLTable.prototype.setIndicatorEqual = function(text) {
	this.indicatorEqualText = text;
}


/*-----------------------------------------------------------------------------
 * XMLTable method reorderTable
 *
 * traverse the XML and set the cells of the table
 *
 * @param column	The column to reorder the table by
 *---------------------------------------------------------------------------*/
XMLTable.prototype.reorderTable = function(column) {
	var orderFunction = this.getOrdering(column);

	// get ordering
 	var order = this.getColumnOrder(column).sort(orderFunction);

	if(this.columnOrdering[0] == column) {
		if(this.columnOrdering[1] == "asc") {
			this.columnOrdering[1] = "desc"
			order.reverse();
		} else {
			this.columnOrdering[1] = "asc"
		}
	} else {
		// default is to sort descending (customer-wish: 2006-09-25)
		this.columnOrdering = [column, "desc"];
		order.reverse();
	}

 	var result = "";

 	// fill the table
	this.traverseXMLTable(this.table, this.xml, this.setTableCellValueOrdered, result, [order]);
}


/*-----------------------------------------------------------------------------
 * XMLTable (private) method getOrdering
 *
 * get the function to sort a column
 *
 * @param column	The column to get the sorting function for
 *---------------------------------------------------------------------------*/
XMLTable.prototype.getOrdering = function(column) {
	var colType = "";
	var c;
	for(c in this.columns) {
		if(this.columns[c][0]==column) {
			colType = this.columns[c][1];
			break;
		}
	}
	
	var orderFunction;
	switch(colType) {
		case "text":
		case "indicator":
			orderFunction = this.sortbycol2text;
			break;
		case "percentage":
		case "int":
		case "float":
			orderFunction = this.sortbycol2number;
			break;
		case "date":
		case "time":		
			orderFunction = this.sortbycol2date;
			break;
		default:
			orderFunction = this.sortbycol2text;
			break;
	}
	
	return orderFunction;
}


/*-----------------------------------------------------------------------------
 * XMLTable method getColumnOrder
 *
 * Traverse the XML and return the values of the column
 *
 * @param column	The column to get the data from
 *---------------------------------------------------------------------------*/
XMLTable.prototype.getColumnOrder = function(column) {
	var result = new Array();

	this.traverseXMLTable(this.table, this.xml, this.getXMLColumn, result, [column]);

	return result;
}


/*-----------------------------------------------------------------------------
 * XMLTable method traverseXMLTable
 *
 * Generic XML traversal function.
 * Traverse the XML and call our injected function
 *
 * @param table		The table object to handle
 * @param xml		The XML object to traverse
 * @param func		The callback function to call while traversting the data
 * @param result	A variable to pass and/or store a result
 * @param params	An array of parameters to the callback function
 *---------------------------------------------------------------------------*/
XMLTable.prototype.traverseXMLTable = function(table, xml, func, result, params) {
	var value = "";
	var name = "";

	var row = 0;

	/**
	 * find first 'real' childnode (of type 1), which is the parent of our child nodes
	 */

	var parentNode=undefined;

	for(var x=0; x<xml.childNodes.length;x++) {
		var candidate = xml.childNodes[x];
		if(candidate.nodeType == 1) {
			parentNode = candidate;
			break;		
		}
	}
	
	for( var node = 0 ; node < parentNode.childNodes.length ; node++ ) {
		var col = 0;
		if( parentNode.childNodes[node].nodeType == 1 ) {
			var myNode = parentNode.childNodes[node]; 
			
			for( var subnode = 0; subnode < myNode.childNodes.length; subnode++ ) {
				if( myNode.childNodes[subnode].nodeType == 1 ) {

					var child = myNode.childNodes[subnode].firstChild;

					value = (child == undefined) ? "" : child.nodeValue;

					name = myNode.childNodes[subnode].nodeName;

					/**
					 * should these be here in the code?
					 * TODO: maybe move this code to a 'better' place..
					 * thought: make these 'injectable' 
					 */
					if(this.columns[name] != undefined) {
						if(this.columns[name][1] == "indicator") {
							switch(value) {
								case "+":
									value=this.indicatorUpText;
									break;
								case "-":
									value=this.indicatorDownText;
									break;
								case "0":
									value=this.indicatorEqualText;
									break;
								default:
									value=".";
									break;
							}
						} else
						if((this.columns[name][1] == "time") && (value.indexOf("pre-opening") == -1)) {
							var curDate = new Date();
							var valueDate = new Date(parseInt(value.substr(6,4),10), parseInt(value.substr(3,2),10) - 1, parseInt(value.substr(0,2),10));
							if ((curDate.getYear() == valueDate.getYear()) && (curDate.getMonth() == valueDate.getMonth()) && (curDate.getDate() == valueDate.getDate())) {
								value = value.substr(12,5);
							} else {
								value = value.substr(0,5);
							}
						} else
						if(this.columns[name][1] == "percentage") {
							value = value+"%";
						} else
						if(this.columns[name][1] == "portfolio") {
							if(value != undefined && value != "") {
								value = "<a href=\"/dft/mijndft/?qk="+value+"\">P</a>";
							} else {
								value = "";
							}
						}

						/* make a link of this value */
						if( this.columns[name][2] != undefined ) {
							var attrNodeName = this.columns[name][2];
							for( var attrSubnode = 0; attrSubnode < myNode.childNodes.length; attrSubnode++ ) {
								if( myNode.childNodes[attrSubnode].nodeType == 1 ) {
									if(myNode.childNodes[attrSubnode].nodeName == attrNodeName) {
										var attrChild = myNode.childNodes[attrSubnode].firstChild;
										var attrValue = (attrChild == undefined) ? "" : attrChild.nodeValue ;
										
										value = ((attrValue.length - 1) == attrValue.indexOf("_")) ? value : "<a href=\""+this.linkPrefix+attrValue+"\">"+value+"</a>";
										break;
									}
								}
							}
						}
						/* check direction of this value */
						if (params != undefined) {
							params[1] = "";
							if( this.columns[name][3] != undefined) {
								var directionNodeName = this.columns[name][3];
								for( var directionSubnode = 0; directionSubnode < myNode.childNodes.length; directionSubnode++ ) {
									if( myNode.childNodes[directionSubnode].nodeType == 1 ) {
										if(myNode.childNodes[directionSubnode].nodeName == directionNodeName) {
											var directionChild = myNode.childNodes[directionSubnode].firstChild;
											var directionValue = (directionChild == undefined) ? "" : directionChild.nodeValue ;										

											if (directionValue != "")
												params[1] = directionValue;
											break;
										}
									}
								}
							}
						}
					}
					/**
					 * END TODO
					 */

					//if(col==0 && row==0 ) { alert("gonna regret this: ("+row+","+col+") "+name+"="+value+" {"+params+"}"); }

					/* code injection */
					var fresult = func(this, result, table, row, col, name, value, params);
					//if(fresult == false ) { alert("gonna regret this: ("+row+","+col+") "+fresult); }

					if(fresult == false)
						break;		
					
					col++;
				}
			}
			row++;
		}
	}
	
	return result;
}


/*-----------------------------------------------------------------------------
 * XMLTable method setTableCellValue                      [injectable function]
 * 
 * Sets the values of the table in 'normal' order.
 *
 * @param caller	The object that calls this function
 * @param result	The variable to store results in
 * @param table		The table to set the value of
 * @param row		The current row-number
 * @param col		The current column-number
 * @param name		The name of the current XML node
 * @param value		The value of the current XML node
 *---------------------------------------------------------------------------*/
XMLTable.prototype.setTableCellValue = function(caller, result, table, row, col, name, value) {
	var nofRows = table.tBodies[0].rows.length;
	var nofColumns = table.tBodies[0].rows[0].cells.length;

	if(row >= nofRows)
		return false;

	var actualRow = caller.evenOnly ? row*2 : row;
	var columnDetails = caller.columns[name];

	if(columnDetails == undefined) {
		// do nothing
	} else {
		var actualColumn = columnDetails[0];

		if( actualColumn >= nofColumns)
			return false;

		table.tBodies[0].rows[actualRow].cells[actualColumn].firstChild.innerHTML = value;
//alert(actualRow+" "+actualColumn);
	}
	

	/*
	// maybe set some css classes in the future
	var divClass = table.tBodies[0].rows[row].cells[col].firstChild.className;
	if(divClass != undefined && divClass!='') {
		table.tBodies[0].rows[row].cells[col].firstChild.className=classname;
	}
	*/
	return true;
}


/*-----------------------------------------------------------------------------
 * XMLTable method setTableCellValueOrdered               [injectable function]
 *
 * Sets the values of the table in supplied order
 *
 * @param caller	The object that calls this function
 * @param result	The variable to store results in
 * @param table		The table to set the value of
 * @param row		The current row-number
 * @param col		The current column-number
 * @param name		The name of the current XML node
 * @param value		The value of the current XML node
 * @param params	The array of parameters passed to this function
 *---------------------------------------------------------------------------*/
XMLTable.prototype.setTableCellValueOrdered = function(caller, result, table, row, col, name, value, params) {
	var nofRows = table.tBodies[0].rows.length;
	var nofColumns = table.tBodies[0].rows[0].cells.length;

	if(row >= nofRows)
		return false;

	var order = params[0];
	var direction = params[1];
	var id = params[2];

	var orderedRow = caller.getOrderRow(row,order);
	var actualRow = caller.evenOnly ? orderedRow*2 : orderedRow;
	
	if (name == 'code') {
		table.tBodies[0].rows[actualRow].setAttribute("id", value);
	} else {	
		var columnDetails = caller.columns[name];

		if(columnDetails == undefined) {
			// do nothing
		} else {
			var actualColumn = columnDetails[0];

			if(actualColumn >= nofColumns)
				return false;

			table.tBodies[0].rows[actualRow].cells[actualColumn].innerHTML = value;
			if (direction == '+') {
				table.tBodies[0].rows[actualRow].cells[actualColumn].className = 'gecentreerd stgreencolor';
			} else if (direction == '-') {
				table.tBodies[0].rows[actualRow].cells[actualColumn].className = 'gecentreerd stredcolor';
			} else if (direction == '0') {
				table.tBodies[0].rows[actualRow].cells[actualColumn].className = 'gecentreerd stgreycolor';
			}
		}
	}

	return true;
}


/*-----------------------------------------------------------------------------
 * XMLTable method getOrderRow
 *
 * Gets the index of the row in the supplied array.
 *
 * @param row		The row
 * @param order		The array of orderings
 *---------------------------------------------------------------------------*/
XMLTable.prototype.getOrderRow = function(row, order) {
	for(var i=0;i<order.length;i++) {
		if(order[i][0]==row) return i;
	}
	return -1;
}


/*-----------------------------------------------------------------------------
 * XMLTable method getXMLColumn                           [injectable function]
 *
 * Get the values of certain column
 *
 * @param caller	The object that calls this function
 * @param result	The variable to store results in
 * @param table		The table to get the value from
 * @param row		The current row-number
 * @param col		The current column-number
 * @param name		The name of the current XML node
 * @param value		The value of the current XML node
 * @param params	The array of parameters passed to this function
 *---------------------------------------------------------------------------*/
XMLTable.prototype.getXMLColumn = function(caller, result, table, row, col, name, value, params) {
	var column = params[0];

	var columnDetails = caller.columns[name];

	if(columnDetails == undefined) {
		// do nothing
	} else {
		var actualColumn = columnDetails[0];
	
		if(actualColumn == column) {
			result[row] = [row, value];
			return false;
		}
	}
	return true;
}


/*-----------------------------------------------------------------------------
 * XMLTable method sortbycol2text
 *
 * sort function for 2-dimensional array, text, case insensitive
 *
 * @param	x	The first value
 * @param 	y	The second value
 *---------------------------------------------------------------------------*/
XMLTable.prototype.sortbycol2text = function(x,y) {
	// case insensitive sorting
	var a = String(x[1]).toUpperCase();
	var b = String(y[1]).toUpperCase();

	// in case of comparing links, compare the text inside them
	var result;
	var regexp = "<A[^>]*>(.*)</A>";

	if(result = a.match(regexp)) { a = result[1]; }
	if(result = b.match(regexp)) { b = result[1]; }

	// do comparison
	if (a < b) return -1;
	if (a > b) return 1;
	return 0;
}

/*-----------------------------------------------------------------------------
 * XMLTable method sortbycol2number
 *
 * sort function for 2-dimensional array, numbers
 *
 * @param	x	The first value
 * @param 	y	The second value
 *---------------------------------------------------------------------------*/
XMLTable.prototype.sortbycol2number = function(x,y) {
	// case insensitive sorting
	var a = String(x[1]).toUpperCase();
	var b = String(y[1]).toUpperCase();

	// in case of comparing links, compare the text inside them
	var result;
	var regexp = "<A[^>]*>(.*)</A>";

	if(result = a.match(regexp)) { a = result[1]; }
	if(result = b.match(regexp)) { b = result[1]; }

	// fallback for empty nodes
	var minimumNumber = "-1000000000";
	if(a == "" || a == "-") a = minimumNumber;
	if(b == "" || b == "-") b = minimumNumber;

	// convert to 'english' numbers
	xVal = a.replace(/\./g,"").replace(/,/g,".");
	yVal = b.replace(/\./g,"").replace(/,/g,".");

	var a = parseFloat(xVal);
	var b = parseFloat(yVal);

	// do comparison
	if (a < b) return -1;
	if (a > b) return 1;
	return 0;
}

/*-----------------------------------------------------------------------------
 * XMLTable method sortbycol2date
 *
 * sort function for 2-dimensional array, date fields
 *
 * @param	x	The first value
 * @param 	y	The second value
 *---------------------------------------------------------------------------*/
XMLTable.prototype.sortbycol2date = function(x,y) {
	// case insensitive sorting
	var a = String(x[1]).toUpperCase();
	var b = String(y[1]).toUpperCase();

	// in case of comparing links, compare the text inside them
	var result;
	var regexp = "<A[^>]*>(.*)</A>";
	var regexpdateyear="(.*)-(.*)-(.*)";
	var regexpdate="(.*)-(.*)";
	var regexptime="(.*):(.*)";
	var curDate = new Date();

	if(result = a.match(regexp)) { a = result[1]; }
	if(result = b.match(regexp)) { b = result[1]; }
	
	// make a sortable date	
	if (a.match(regexpdateyear))
		a = a.substring(6,10)+"-"+a.substring(3,5)+"-"+a.substring(0,2)+" "+curDate.getHours()+":"+curDate.getMinutes();
	else if (a.match(regexpdate))
		a = curDate.getYear()+"-"+a.substring(3,5)+"-"+a.substring(0,2)+" "+curDate.getHours()+":"+curDate.getMinutes();
	else if (a.match(regexptime))
		a = curDate.getYear()+"-"+(curDate.getMonth()+1)+"-"+curDate.getDate()+" "+a.substring(0,2)+":"+a.substring(3,5);

	if (b.match(regexpdateyear))
		b = b.substring(6,10)+"-"+b.substring(3,5)+"-"+b.substring(0,2)+" "+curDate.getHours()+":"+curDate.getMinutes();
	else if (b.match(regexpdate))
		b = curDate.getYear()+"-"+b.substring(3,5)+"-"+b.substring(0,2)+" "+curDate.getHours()+":"+curDate.getMinutes();
	else if (b.match(regexptime))
		b = curDate.getYear()+"-"+(curDate.getMonth()+1)+"-"+curDate.getDate()+" "+b.substring(0,2)+":"+b.substring(3,5);

	// do comparison
	if (a < b) return -1;
	if (a > b) return 1;
	return 0;
}

