
/**
 *
 */
function DataType () {
};

DataType._checkForNulls = function (a, b) {
	if ((a === undefined || a === null) && (b === undefined || b === null)) {
		return 0;
	}
	
	if (a === undefined || a === null) {
		return -1;
	}
	
	if (b === undefined || b === null) {
		return 1;
	}
	
	return null;
};

DataType.DATE = function (a, b) {
	var oResult = DataType._checkForNulls (a, b);
	
	if (oResult != null) {
		return oResult;
	}
	
	return a.getTime () - b.getTime ();
};

DataType.NUMBER = function (a, b) {
	var oResult = DataType._checkForNulls (a, b);
	
	if (oResult != null) {
		return oResult;
	}
	
	return b - a;
};

DataType.TEXT = function (a, b) {
	var oResult = DataType._checkForNulls (a, b);
	
	if (oResult != null) {
		return oResult;
	}

	/*
	// Human sorting algorithm
	function alphaNumKey (sText) {
		// This regular expression works in Firefox, but not in IE6
		var aArray = sText.split (/(\d+)/);
		alert (sText + ' := [ ' + aArray + ' ]');
		for (var oKey in aArray) {
			aArray[oKey] = function (sText) {
				var nValue = parseInt (sText);
				return isNaN (nValue) ? sText : nValue;
			} (aArray[oKey]);
		}
		return aArray;
	};
	
	var aAKeys = alphaNumKey (a);
	var aBKeys = alphaNumKey (b);
	
	for (var i = 0; i < aAKeys.length; ++i) {
		if (i > aBKeys.length) {
			return 1;
		}
		if (aAKeys[i] > aBKeys[i]) {
			return 1;
		} else if (aAKeys[i] < aBKeys[i]) {
			return -1;
		}
	}
	return 0;
	 */
	return (a > b) ? 1 : (a < b) ? -1 : 0;
};

/**
 *
 */
function Column (sName, sInnerHTML, sTooltipHTML, aStyles, bSortable, oDataType, sDateFormat) {
	this._name = sName; // sName.replace (/\s+/, '_');
	this._innerHTML = sInnerHTML;
	this._tooltipHTML = sTooltipHTML;
	this._styles = aStyles;
	this._sortable = bSortable;
	this._dataType = oDataType;
	this._dateFormat = sDateFormat;
	
};

Column.prototype.getName = function () {
	return this._name;
};

Column.prototype.getInnerHTML = function () {
	return this._innerHTML;
};

Column.prototype.getTooltipHTML = function () {
	return this._tooltipHTML;
};

Column.prototype.applyStyleMap = function (oNode) {
	for (var style in this._styles) {
		oNode.style[style] = this._styles[style];
	}
};

Column.prototype.isSortable = function () {
	return this._sortable;
};

Column.prototype.getDataType = function () {
	return this._dataType;
};

Column.prototype.getDateFormat = function () {
	return this._dateFormat;
};

/**
 *
 */
function DynamicTable (sIdentifier, sClassName, aHeaderStyles, aEvenStyles, aOddStyles, bSortable, nSortIndex, nPageSize) {
	this._identifier = sIdentifier;
	this._className = sClassName;
	this._headerStyles = aHeaderStyles;
	this._evenStyles = aEvenStyles;
	this._oddStyles = aOddStyles;
	this._sortIndex = nSortIndex;
	this._sortDirection = 1;
	this._sortable = bSortable;
	this._pageSize = nPageSize;
	this._pageNumber = 0;
	
	this._columns = [];
	this._data = [];
	
	this._element = document.getElementById ('dynamictable_' + this._identifier + '_div');
};

DynamicTable.prototype.addColumn = function (oColumn) {
	this._columns.push (oColumn);
};

DynamicTable.prototype.addItem = function (oItem) {
	this._data.push (oItem);
};

DynamicTable.prototype.getColumnTooltipHTML = function (nIndex) {
	return this._columns[nIndex].getTooltipHTML ();
};

DynamicTable.prototype.render = function () {
	var oTable = document.createElement ('table');

	oTable.id = 'dynamictable_' + this._identifier;
	oTable.name = 'dynamictable_' + this._identifier;
	oTable.className = this._className;
	
	var oTBody = document.createElement ('tbody');
	
	this._renderHeader (oTBody);
	this._renderBody (oTBody);
	this._renderFooter ();
	
	oTable.appendChild (oTBody);
	
	var oPrevTable = document.getElementById ('dynamictable_' + this._identifier);
	
	if (oPrevTable !== undefined && oPrevTable !== null) {
		this._element.replaceChild (oTable, oPrevTable);
	} else {
		this._element.appendChild (oTable);
	}
};

DynamicTable.prototype._renderHeader = function (oTBody) {
	var oTR = document.createElement ('tr');
	
	oTR.id = 'dynamictable_' + this._identifier + '_header';
	oTR.name = 'dynamictable_' + this._identifier + '_header';
	
	for (var i = 0; i < this._columns.length; ++i) {
		var oTD = document.createElement ('th');
		var oColumn = this._columns[i];
		
		oTD.id = 'dynamictable_' + this._identifier + '_header_col' + i;
		oTD.name = 'dynamictable_' + this._identifier + '_header_col' + i;
		
		for (var style in this._headerStyles) {
			oTD.style[style] = this._headerStyles[style];
		}
		
		if (this._sortable && oColumn.isSortable ()) {
			var oDiv = document.createElement ('div');

			oDiv.style.display = 'inline';
			oDiv._dynamicTable = this;
			oDiv._columnIndex = i;
			oDiv.onclick = function () {
				this._dynamicTable.sortTable (this._columnIndex);
			};
			
			if (this._sortIndex == i) {
				// oDiv.innerHTML = (oColumn.getInnerHTML () + ((this._sortDirection < 0) ? '&dArr;' : '&uArr;'));
				oDiv.innerHTML = (oColumn.getInnerHTML () + ((this._sortDirection < 0) ? '&darr;' : '&uarr;'));
			} else {
				oDiv.innerHTML = oColumn.getInnerHTML ();
			}
			
			oTD.appendChild (oDiv);
		} else {
			oTD.innerHTML = oColumn.getInnerHTML ();
		}
		
		oTD._tooltipHTML = oColumn.getTooltipHTML ();
		oTD.onmouseover = function () {
			Tooltip.show (this._tooltipHTML);
		};
		oTD.onmouseout = function () {
			Tooltip.hide ();
		};
		
		oTR.appendChild (oTD);
	}
	
	oTBody.appendChild (oTR);
};

DynamicTable.prototype._renderBody = function (oTBody) {
	var nStartIndex = 0;
	var nLength = this._data.length;
	
	if (this._pageSize > 0) {
		nStartIndex = this._pageNumber * this._pageSize;
		var nRemaining = this._data.length - nStartIndex;
		nLength = (nRemaining > this._pageSize) ? this._pageSize : nRemaining;
	}

	for (var i = 0; i < nLength; ++i) {
		var oTR = document.createElement ('tr');
		var oStyleMap;
		
		oTR.id = 'dynamictable_' + this._identifier + '_row' + i;
		oTR.name = 'dynamictable_' + this._identifier + '_row' + i;
	
		if (((i + 1) % 2) == 0) {
			oStyleMap = this._evenStyles;
		} else {
			oStyleMap = this._oddStyles;
		}

		var oDataItem = this._data[nStartIndex + i];
		
		for (var j = 0; j < this._columns.length; ++j) {
			var oTD = document.createElement ('td');
			var oColumn = this._columns[j];
			
			oTD.id = 'dynamictable_' + this._identifier + '_row' + i + '_col' + j;
			oTD.name = 'dynamictable_' + this._identifier + '_row' + i + '_col' + j;
		
			for (var style in oStyleMap) {
				oTD.style[style] = oStyleMap[style];
			}
			oColumn.applyStyleMap (oTD);

			if (oColumn.getDataType () == DataType.DATE) {
				try {
					oTD.innerHTML = DateFormat (oColumn.getDateFormat (), oDataItem[oColumn.getName ()]);
					// oTD.innerHTML = oDataItem[oColumn.getName ()];
				} catch (oException) {
					// alert (oException.message);
					oTD.innerHTML = oDataItem[oColumn.getName ()];
				}
			} else {
				oTD.innerHTML = oDataItem[oColumn.getName ()];
			}
			
			oTR.appendChild (oTD);
		}
		
		oTBody.appendChild (oTR);
	}
};

DynamicTable.prototype._renderFooter = function () {
	if (this._pageSize > 0) {
		var nStartIndex = this._pageNumber * this._pageSize;
		var nRemaining = this._data.length - nStartIndex;
		var nLength = (nRemaining > this._pageSize) ? this._pageSize : nRemaining;
		
		var oPagingElement = document.getElementById ('dynamictable_' + this._identifier + '_paging');
		if (oPagingElement !== undefined && oPagingElement !== null) {
			var sPagingHTML = '';
			
			if (this._pageNumber > 0) {
				sPagingHTML += '<a href="#" onclick="javascript:oDynamicTable_' + this._identifier + '.prevPage ();" >&lt;&lt; Prev</a>';
				sPagingHTML += ' ';
			}

			if (Math.ceil (this._data.length / this._pageSize) >= 10) {
				sPagingHTML += '<input type="text" size="2" value="' + (this._pageNumber + 1) + '" onchange="javascript:this.value = oDynamicTable_' + this._identifier + '.gotoPage (this.value);" />';
			} else {
				sPagingHTML += '' + (this._pageNumber + 1);
			}
			sPagingHTML += ' of ' + Math.ceil (this._data.length / this._pageSize);
			
			if (nStartIndex + nLength < this._data.length) {
				sPagingHTML += ' ';
				sPagingHTML += '<a href="#" onclick="javascript:oDynamicTable_' + this._identifier + '.nextPage ();" >Next &gt;&gt;</a>';
			}
			
			oPagingElement.innerHTML = sPagingHTML;
		}
	}
};

DynamicTable.prototype.sortTable = function (nIndex) {
	var nSortDirection = this._sortDirection;
	
	if (nIndex === undefined || nIndex === null) {
		nIndex = (this._sortIndex < 0) ? -this._sortIndex : this._sortIndex;
	}
	if (nIndex == this._sortIndex) {
		nSortDirection = -nSortDirection;
	} else {
		nSortDirection = 1;
	}
	
	var aData = [];
	
	for (var i = 0; i < this._data.length; ++i) {
		aData[i] = this._data[i];
	}
	
	var oColumn = this._columns[nIndex];
	var oDataType = oColumn.getDataType ();
	if (oDataType === undefined || oDataType === null) {
		oDataType = DataType.TEXT;
	}

	aData.sort (function (a, b) {
		var aItem = a[oColumn.getName ()];
		var bItem = b[oColumn.getName ()];
		
		return nSortDirection * oDataType (aItem, bItem);
	});
	
	this._data = aData;
	
	this._sortIndex = nIndex;
	this._sortDirection = nSortDirection;
	
	this.render ();
};

DynamicTable.prototype.prevPage = function () {
	if (this._pageNumber >= 1) {
		this._pageNumber--;
		this.render ();
	}
};

DynamicTable.prototype.nextPage = function () {
	if (this._pageNumber < Math.ceil (this._data.length / this._pageSize) - 1) {
		this._pageNumber++;
		this.render ();
	}
};

DynamicTable.prototype.gotoPage = function (nPage) {
	if (nPage >= 1 && nPage <= Math.ceil (this._data.length / this._pageSize)) {
		this._pageNumber = nPage - 1;
		this.render ();
	}
	return this._pageNumber + 1;
};
