﻿

function extend_grid(o)
{
	// extend functions
	o.sortRowsByColumn 		= grid_sortRowsByColumn;
	//o.colorRows 			= grid_colorRows;
	o.insertRowAtIndex		= grid_insertRowAtIndex;
	o.removeRowAtIndex		= grid_removeRowAtIndex;
	o.getRowIndexByTRID 	= grid_getRowIndexByTRID;
	o.getColumnIndexByTDID 	= grid_getColumnIndexByTDID;
	o.moveRow 				= grid_moveRow;
	o.updateDisplay			= grid_updateDisplay;
	o.groupRowsByColumn		= grid_groupRowsByColumn;
	o.rerow					= rerow;	
	//constants
	o.types = 
	{
		ALTERNATING : 0,
		GROUPED : 1
	}
	
	o.sortOrders = 
	{
		ASCENDING	: 0,
		DESCENDING	: 1
	}
	
	// default type
	o.type = o.types.ALTERNATING;
	
	// the column index that the current sort order is based on
	o.currentSortColumnIndex = 0;	
	o.currentGroupColumnIndex = 0;	
	o.currentSortOrder = o.sortOrders.ASCENDING;
}

function grid_groupRowsByColumn(idx)
{

	if (idx == null)
	{
		this.type = this.types.ALTERNATING;
		this.currentGroupColumnIndex = null;
		return;
	}
	if(this.tBodies[0].rows[0].cells.length==1)
	{
		return;
	}
	if (idx > this.tBodies[0].rows[0].cells.length)
	{
		this.type = this.types.ALTERNATING;
		this.currentGroupColumnIndex = null;
		alert("Invalid index specified for row grouping.");
		return;
	}
	
	this.type = this.types.GROUPED;
	this.currentGroupColumnIndex = idx;
	
}

function grid_updateDisplay()
{
	var currentGroupingValue 	= null;
	var currentRowClass			= null;
	
	// update index number and hide first and last row elements
	
	for(var i = 0; i < this.tBodies[0].rows.length; i++)
	{
		
		var s = this.tBodies[0].rows[i].getElementsByTagName("span");
		
		for(var j = 0; j < s.length; j++)
		{
			if (s[j].id == "index")
			{
				s[j].innerHTML = i + 1;
			}
				
			if (s[j].id == "hide_when_first")
			{
				(i == 0) ? s[j].style.display = "none" : s[j].style.display = "";
			}
			
			if (s[j].id == "hide_when_last")
			{
				(i == this.tBodies[0].rows.length - 1) ? s[j].style.display = "none" : s[j].style.display = "";
			}
		}
		
		// change row colors - alternating or grouped
		
		var c = this.tBodies[0].rows[i].className;
			c = c.replace("rowOdd", "");
			c = c.replace("rowEven", "");
				
		if (this.type == this.types.ALTERNATING)
		{
			(i % 2 == 0) ? currentRowClass = "rowOdd" : currentRowClass = "rowEven";
		}
		else if (this.type == this.types.GROUPED)
		{
			if (i == 0)
			{
				currentRowClass = "rowOdd";
				currentRowValue = this.tBodies[0].rows[i].cells[this.currentGroupColumnIndex].textContent;
			}
			else
			{
				if (currentRowValue != this.tBodies[0].rows[i].cells[this.currentGroupColumnIndex].textContent)
				{
					(currentRowClass == "rowOdd") ? currentRowClass = "rowEven" : currentRowClass = "rowOdd";
					currentRowValue = this.tBodies[0].rows[i].cells[this.currentGroupColumnIndex].textContent;
				}
			}
			
		}
		
		this.tBodies[0].rows[i].className = currentRowClass + " " + c;
		
	}
	
}

function grid_getRowIndexByTRID(pid)
{
	for (var i = 0; i < this.tBodies[0].rows.length; i++)
	{
		if (this.tBodies[0].rows[i].id == pid)
			return i;
	}
	
}

function grid_getColumnIndexByTDID(pid)
{

	for (var i = 0; i < this.tHead.rows[0].cells.length; i++)
	{
		
		if (this.tHead.rows[0].cells[i].id == pid)
			return i;
	}

}

function grid_moveRow(idx, distance)
{
	if (distance == 0)
		return true;
	
	var d;
	
	// min and max constraints 
	
	if (idx + distance < 0)
		d = 0;
	else if (idx + distance >= this.tBodies[0].rows.length)
		d = this.tBodies[0].rows.length - 1;
	else
		d = idx + distance;
		
	var row = this.removeRowAtIndex(idx);

	this.insertRowAtIndex(d, row);
	
	// update the displayed indexes and row colors
	
	this.updateDisplay();
	
}

//**
// removes the table row at the specified index
//
// @returns the removed row object
//*
function grid_removeRowAtIndex(idx)
{
	return this.tBodies[0].removeChild(this.tBodies[0].rows[idx]);
}

//**
// inserts the provided table row object at the index specified.
// the row AT that index and all others after are bumped down one row
//
// @idx = the row index to insert the new row
// @row = the row object to insert
//*
function grid_insertRowAtIndex(idx, row)
{
	if (idx < this.tBodies[0].rows.length)
		//insert it
		this.tBodies[0].insertBefore(row, this.tBodies[0].rows[idx]);
	else
		// put it at the end
		this.tBodies[0].appendChild(row);		
}

function grid_sortRowsByColumn(pint, type)
{

	var tbody, thead, tr;
	var sortArray = new Array();
	var tagName;
	var a;
	var tdC; //td counter
	
	if (this.sortColumn == pint){
		if (this.sortOrder == ""){
			this.sortOrder = "desc";
		} else {
			this.sortOrder = "";
		}
	} else {
		this.sortOrder = "";
	}
	this.sortColumn = pint;
	//find the thead
	for (var i = 0; i < this.childNodes.length; i++){
		if (this.childNodes[i].tagName == "THEAD"){
			thead = this.childNodes[i];
		}
	}
	if (!thead){
		alert("failed.");
		return false;
	}
	for (var i = 0; i < thead.childNodes.length; i++){
		if (thead.childNodes[i].tagName == "TR") {
			tr = thead.childNodes[i];
			//loop the cells
			tdC = -1;
			for (var j = 0; j < tr.childNodes.length; j++){
				
				if (tr.childNodes[j].tagName == "TD"){
					
					tdC++;
					td = tr.childNodes[j];
					td.className = td.className.replace("sorton ", "");
					for (var k = 0; k < td.childNodes.length; k++){
						if (td.childNodes[k].tagName == "IMG"){
							td.removeChild(td.childNodes[k]);
						}
					}
					
					if (tdC == pint){
						var img = document.createElement("img");
						img.border = 0;
						img.style.marginLeft = "16px";
						(this.sortOrder == "desc") ? img.src = "/_images/grid/sortarrow_desc.gif" : img.src = "/_images/grid/sortarrow_asc.gif" ;
						if(td.id.substring(0,7) == "_order_")
						{
							var newColID= td.id.substring(7,td.id.length);
							td = document.getElementById(newColID);	
						}
						td.appendChild(img);
						td.className = "sorton " + td.className;
					}
				}
			}
		}
	}

	// header
	
	// fewer than 2 body rows, skip the process
	
	//find the tbody
	for (var i = 0; i < this.childNodes.length; i++){
		if (this.childNodes[i].tagName == "TBODY"){
			tbody = this.childNodes[i];
		}
	}
	if (!tbody){
		alert("ERROR: No table body element found.");
		return false;
	}
	
	// fewer than 2 rows...exit cleanly
	var z = 0;
	for (var i = 0; i < tbody.childNodes.length; i++){
		if (tbody.childNodes[i].tagName == "TR") {
			z++;
		}
	}
	if (z <= 1) {
		//re-color the rows
		this.rerow();
		return true;
	}

	//loop the rows to find the trs
	for (var i = 0; i < tbody.childNodes.length; i++){
		if (tbody.childNodes[i].tagName == "TR") {
			tr = tbody.childNodes[i];
			// find the nth TD
			tdC = -1;
			td = null;
			for (var j = 0; j < tr.childNodes.length; j++){
				if (tr.childNodes[j].tagName == "TD"){
					tdC++;
					if (tdC == pint) { td = tr.childNodes[j] };
				}
			}
			// push the value into the sort array
			if (td) {
				if (td.textContent){
					a = new Array (td.textContent.toLowerCase(), tr); //FF
				} else {
					if (td.innerText)
					{
						a = new Array (td.innerText.toLowerCase(), tr); //FF
					}
					else
					{
						a = new Array ("", tr); //FF
					}
				}
			} else {
				alert("ABORTED: No data cell found for sorting.");
				return false;
			}
			sortArray.push (a);
		}
	}

	//re-type the array
	if (type){
		for (var i = 0; i < sortArray.length; i++){
			switch (type){
			case "date":
				var dt = new Date(sortArray[i][0]);
				//add 10 to day and month so that they are all double digits and remain relative for proper ordering.
				sortArray[i][0] = dt.getFullYear() + "-" + (dt.getMonth() + 10) + "-" + (dt.getDate() + 10); 
				break;
			case "integer":
				if (isNaN(parseFloat(sortArray[i][0])))
				{
					sortArray[i][0] = -999999999;
				}
				{
					sortArray[i][0] = parseFloat(sortArray[i][0]);
				}
									   
				break;
			}
		}
	}

	//sort the array
	if (this.sortOrder == "desc"){
		sortArray.sort(grid_sort_descending);
	} else {
		sortArray.sort(grid_sort_ascending);
	}

	//replace the tbody in the table
	this.removeChild(tbody);

	//create the new tbody
	tbody = document.createElement("tbody"); 
	
	//put the body back in the table
	this.appendChild(tbody);
	
	//append the rows
	for (var i = 0; i < sortArray.length; i++){
		tbody.appendChild(sortArray[i][1]);
	}
	
	//re-color the rows
	this.rerow();
	
}

function grid_sort_descending(a,b){
	(a[0] > b[0]) ? i = -1 : (b[0] > a[0]) ? i = 1 : i = 0 ;
	return i;
}

function grid_sort_ascending(a,b){
	(a[0] > b[0]) ? i = 1 : (b[0] > a[0]) ? i = -1 : i = 0 ;
	return i;
}



function rerow(){
	var tbody;
	var tr;
	var trC, tdC;
	var val = "";
	var cE = "rowEven";
	var cO = "rowOdd";
	var eo; //current even or odd class
	
	//find the tbody
	for (var i = 0; i < this.childNodes.length; i++){
		if (this.childNodes[i].tagName == "TBODY"){
			tbody = this.childNodes[i];
		}
	}
	if (!tbody){
		alert("failed.");
		return false;
	}
	
	trC = -1;
	for (var i = 0; i < tbody.childNodes.length; i++){
		if (tbody.childNodes[i].tagName == "TR") {
			trC++;
			tr = tbody.childNodes[i];
			
			switch (this.rowType){
			case 1 :
				td = null;
				tdC = -1;
				for (var j = 0; j < tr.childNodes.length; j++){
					if (tr.childNodes[j].tagName == "TD"){
						tdC++;
						if (tdC == this.sortColumn) { td = tr.childNodes[j] };
					}
					if (td){
						if (td.textContent){
							if (td.textContent.toLowerCase() != val){
								(eo == cO) ? eo = cE : eo = cO ;
								val = td.textContent.toLowerCase();
							}
						} else {
							if (td.innerHTML.toLowerCase() != val){
								(eo == cO) ? eo = cE : eo = cO ;
								val = td.innerHTML.toLowerCase();
							}
						}
						tr.className = eo;
					}
				}
				break;
			default :
				if (trC % 2){
					tr.className = cE;
				} else {
					tr.className = cO;
				}
				break;
			}
		}
	}
}
