﻿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;
	
	//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 (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(idx, data_type, order)
{
	var a = new Array();
	var i;
	var aa;
	
	// sort mode
	
	switch(order)
	{
	case this.sortOrders.DESCENDING:
		this.currentSortOrder = this.sortOrders.DESCENDING;
		break;
	default:
		this.currentSortOrder = this.sortOrders.ASCENDING;
		break;	
	}
	
	// header
	
	// fewer than 2 body rows, skip the process
	
	if (this.tBodies[0].rows.length > 1)
	{	
		
		//loop the body rows, get the nth td and push into the sorting array based on textcontent
	
		for (i = 0; i < this.tBodies[0].rows.length; i++)
		{
			var row = this.tBodies[0].rows[i];
			
			// skip if nth element is beyond the upper limit of the row tds
			
			if (idx >= row.cells.length)
				continue;
				
			var cell = row.cells[idx];
			
			// place in the array for sorting
			
			if (cell.textContent)
				aa = new Array (cell.textContent.toLowerCase(), row);
			else
				if (cell.innerText)
					aa = new Array (cell.innerText.toLowerCase(), row); 
				else
					aa = new Array ("", row); 
					
			a.push (aa);
		}
		
		// re-type the sorting values in the array
		switch (data_type)
		{
		case "number":
			for (i = 0; i < a.length; i++)
			{
				a[i][0] = parseInt(a[i][0]);
			}
			break;
		default:
			break;
		}
		
		//sort the array
		
		(this.currentSortOrder == this.sortOrders.DESCENDING) ? a.sort(grid_descending_sort) : a.sort();
		
		// kill all the tbody rows
		
		for (var i = this.tBodies[0].rows.length - 1; i >= 0 ; i--)
		{
			this.tBodies[0].removeChild(this.tBodies[0].rows[0]);
		}
		
		// re-attach the rows in the correct order
		
		for (var i = 0; i < a.length; i++)
		{
		
			this.tBodies[0].appendChild(a[i][1]);
		
		}
	
	}
		
	// set the sort column index
	
	this.currentSortColumnIndex = idx;
	
	// update the index numbering and the row class names
	
	this.updateDisplay();
	
}

//**
// descending sort function
//*
function grid_descending_sort(a, b)
{
	(a > b) ? i = -1 : (b > a) ? i = 1 : i = 0 ;
	return i;
}
