var Grid = {

	mode: 'delayed',
	//mode can be 'realtime' or 'delayed'
	delay: 500,
	threshold: 5,
	minimumWidth: 10,
	
	identifier: null,
	
	leftBorder: null,
	rightBorder: null,
	
	defaultCursor: null,
	clickPosition: null,
	selectedColumns: null,
	
	mouseStartPosition: null,
	
	headerRow: null,
	tableGroup: null,
	columnGroup: new Array(),
	columnWidth: new Array(),
	columnHeaders: new Array(),
	columnActions: new Array(),
	
	copy: null,
	copyGroup: new Array(),
	copyWidth: new Array(),
	copyHeaders: new Array(),
	
	columnLine: null,
	
	originalWidth: new Array(),
	
	/**
		This function sets all the absolute variables and gives the actions
		to the events linked to the header of the table.
	*/
	initialize: function(id, cursor, resize) {
		
		//set the variables
		Grid.identifier = id;
		Grid.defaultCursor = cursor;
		
		//this delay is needed for IE that has problem to recover
		// original column width before the grid is actually displayed
		if (resize) window.setTimeout("Grid.activateResize()",100);
	
	},
	
	activateResize: function() {

		//take information from the cookie
		Grid.setColumnWidth();
	
		var id = Grid.identifier;
		//set the variables
		Grid.headerRow = Grid.getHeader(id);
		Grid.tableGroup = Grid.getGroup(id);
		Grid.columnGroup = Grid.getGroupElements(id);
		Grid.columnHeaders = Grid.getHeaderElements(id);
		
		//attach the actions on the events for all columns
		Grid.headerRow.onmouseover = Grid.headerRow.onmousemove = Grid.displayCursor;
		Grid.headerRow.onmousedown = Grid.selectAction;
	
	},
	
	/**
		This function displays the resize cursor when in mouse over
		the edge of the columns.
	*/
	displayCursor: function(e) {
	
		if(!e) e = window.event;
		if(e.target) src = e.target;
		else if(e.srcElement) src = e.srcElement;
		
		var frame = document.getElementById('pageFrame');
		var mouseX = e.clientX + frame.scrollLeft;
		var mouseY = e.clientY + frame.scrollTop;
		
		var left, right;
		var bool = false;
		var distance = (document.all)? 3 : 0;
		//test if we are near on of the cells left or right border
		for(i=0;i<Grid.columnHeaders.length;i++) {
		
			left = Grid.getAbsolutePosition(Grid.columnHeaders[i],'left') - distance;
			right = Grid.getAbsolutePosition(Grid.columnHeaders[i],'left') + Grid.columnHeaders[i].offsetWidth - distance;
			
			if(i != 0 //because we cannot resize the first column to the left
				&& mouseX <= left + Grid.threshold) { 
				//we got a winner on the left hand side
				Grid.columnHeaders[i].style.cursor = 'col-resize';
				if(mouseX >= left - Grid.getBorderWidth(Grid.columnHeaders[i],'l')) {
				
					Grid.selectedColumns = new Array(i-1,i);
					bool = true;
				
				}
			
			} else if(i < (Grid.columnHeaders.length-1) //because we cannot resize the last column to the right
						&& mouseX >= right - Grid.threshold) { 
				//we got a winner on the right hand side
				Grid.columnHeaders[i].style.cursor = 'col-resize';
				if(mouseX <= right + Grid.getBorderWidth(Grid.columnHeaders[i],'r')) {
				
					Grid.selectedColumns = new Array(i,i+1);
					bool = true;
				
				}
				
			} else {
			
				//patch for IE: cursor style
				if(document.all && Grid.defaultCursor == 'pointer') Grid.defaultCursor = 'hand';
				//set the cursor and reset selected columns array
				Grid.columnHeaders[i].style.cursor = Grid.defaultCursor;
			
			}
		
		}
		if(!bool) Grid.selectedColumns = null;
	
	},
	
	/**
		This function launches the action of resizing the column (through the 
		startDrag function). It sets all the parameters needed for this action.
	*/
	selectAction: function(e) {
	
		//if there is no column defined, stop there
		if(!Grid.selectedColumns) return false;
		
		//temporarily deactivated grid sorting
		eval('st' + Grid.identifier + '.uninitHeader()');

		if(!e) e = window.event;
		if(e.target) src = e.target;
		else if(e.srcElement) src = e.srcElement;
		
		var frame = document.getElementById('pageFrame');
		var mouseX = e.clientX + frame.scrollLeft;
		var mouseY = e.clientY + frame.scrollTop;
		
		//set the absolute variables
		//retrieve the width of all columns
		for(i=0;i<Grid.columnHeaders.length;i++)
			Grid.columnWidth[i] = Grid.columnHeaders[i].offsetWidth;

		//set the limit for the drag and drop functions
		Grid.leftBorder = Grid.getAbsolutePosition(Grid.columnHeaders[Grid.selectedColumns[0]],'left');
		Grid.rightBorder = Grid.getAbsolutePosition(Grid.columnHeaders[Grid.selectedColumns[1]],'left') + Grid.columnHeaders[Grid.selectedColumns[1]].offsetWidth;
		
		//get the position of the cursor when the click event occur 
		Grid.clickPosition = mouseX - Grid.getAbsolutePosition(Grid.columnHeaders[Grid.selectedColumns[1]], 'left');
		
		//start position
		Grid.mouseStartPosition = mouseX;
		//avoid selecting text while dragging
		Grid.setTextSelectionMode(false);
		
		//set the actions on the object itself to null
		Grid.headerRow.onmouseover = Grid.headerRow.onmousemove = null;
		
		if(Grid.mode != 'realtime') {
		
			//create the dummy header
			Grid.copy = Grid.createCopy();
			//show the line
			Grid.columnLine = Grid.displayColumnLine();
		
		}
		//launch the drag action
		document.onmousemove = Grid.startDrag;
		document.onmouseup = Grid.stopAction;
	
	},
	
	startDrag: function(e) {
	
		if (!e) var e = window.event;
			
		var frame = document.getElementById('pageFrame');
		var mouseX = e.clientX + frame.scrollLeft;

		//get the boundaries between which we will resize the columns
		var leftColumn = Grid.columnHeaders[Grid.selectedColumns[0]];
		var rightColumn = Grid.columnHeaders[Grid.selectedColumns[1]];
		
		var leftLimit = Grid.getAbsolutePosition(leftColumn,'left');
		var rightLimit = Grid.getAbsolutePosition(rightColumn,'left') + rightColumn.offsetWidth;
		
		//stop everything if we reach one of these
		if(mouseX <= (leftLimit + Grid.minimumWidth + Grid.clickPosition))
			mouseX = (leftLimit + Grid.minimumWidth + Grid.clickPosition) ;
		else if(mouseX >= (rightLimit - Grid.minimumWidth + Grid.clickPosition))
			mouseX = (rightLimit - Grid.minimumWidth + Grid.clickPosition);
		
		//var delta = mouseX - (Grid.mouseStartPosition - Grid.clickPosition);
		var delta = mouseX - Grid.mouseStartPosition;
		
		//resize left hand side column
		Grid.resizeColumn(Grid.selectedColumns, delta, Grid.mode);
		//move the line
		Grid.showColumnWidth(mouseX);
	
	},
	
	/**
		This function retrieves a style property for a given object
	*/
	resizeColumn: function(selected, delta, mode) {
		
		//depending on the mode we need to resize the original or the copy
		var header = (mode == 'realtime')? Grid.headerRow : Grid.copy;
		var columns = (mode == 'realtime')? Grid.columnHeaders : Grid.copyHeaders;
		var colgroup = (mode == 'realtime')? Grid.columnGroup : Grid.copyGroup;
		var colwidth = (mode == 'realtime')? Grid.columnWidth : Grid.copyWidth;
		
		var leftColumn = columns[selected[0]];
		var rightColumn = columns[selected[1]];
		
		//make sure the width of the table doesn't change during the operation
		header.style.width = document.getElementById('table_' + Grid.identifier).offsetWidth + 'px';
		//with IE we must substract borders and padding that are counted inside the elements
		var distance = (document.all)? Grid.getOuterWidth(columns[0],'h') : 0;
		
		//start resizing
		//we prefer percentages for the print
		var string = '';
		var total = 0;
		var percentage;
		for(i=0;i<columns.length;i++) {
		
			if(i == selected[0]) {
				//this is the left hand side column
				if(mode == 'realtime') {
				
					percentage = ((colwidth[i] + delta + distance)/header.offsetWidth)*100;
					columns[i].style.width = colgroup[i].style.width = ((percentage >= 1)? percentage : 1) + '%';
					colwidth[i] = colwidth[i] + delta;
				
				} else columns[i].style.width = colgroup[i].style.width = colwidth[i] + delta - distance + 'px';
			
			} else if(i == selected[1]) {
				
				//this is the right hand side column
				if(mode == 'realtime') {
					
					percentage = ((colwidth[i] - delta + distance)/header.offsetWidth)*100;
					columns[i].style.width = colgroup[i].style.width = ((percentage >= 1)? percentage : 1) + '%';
					colwidth[i] = colwidth[i] - delta;
				
				} else columns[i].style.width = colgroup[i].style.width = colwidth[i] - delta - distance + 'px';
				
			} else {
				
				if(mode == 'realtime') {
				
					percentage = ((colwidth[i] + distance)/header.offsetWidth)*100;
					columns[i].style.width = colgroup[i].style.width = percentage + '%';
				
				} else columns[i].style.width = colgroup[i].style.width = colwidth[i] - distance + 'px';
				
			}
			//string += i + ': ' + colgroup[i].offsetWidth + ' | ';
		
		}
		
		//re-assign values
		if(mode == 'realtime')
			Grid.columnWidth = colwidth;
		else Grid.copyWidth = colwidth;
		
		//TODO: find how the originalWidth variable can be overwritten
		//if(mode == 'realtime') alert('resize: ' + Grid.originalWidth);
	
	},
	
	/**
		The stopAction function sets the obj parameter, the mousemove 
		and the mouseup to 'null' manually to avoid any repeat in the 
		browser's signals.
	*/
	stopAction: function(e) {
	
		if (!e) var e = window.event;
		
		//if we are in delayed mode, update the table columns width
		if(Grid.mode != 'realtime') {
		
			var frame = document.getElementById('pageFrame');
			var table = document.getElementById('table_' + Grid.identifier);
			
			var mouseX = e.clientX + frame.scrollLeft;
			//don't forget to set the boundaries
			var leftColumn = Grid.columnHeaders[Grid.selectedColumns[0]];
			var rightColumn = Grid.columnHeaders[Grid.selectedColumns[1]];
			var leftLimit = Grid.getAbsolutePosition(leftColumn,'left');
			var rightLimit = Grid.getAbsolutePosition(rightColumn,'left') + rightColumn.offsetWidth;
			//test against the boundaries
			if(mouseX <= (leftLimit + Grid.minimumWidth))
				mouseX = (leftLimit + Grid.minimumWidth) ;
			else if(mouseX >= (rightLimit - Grid.minimumWidth))
				mouseX = (rightLimit - Grid.minimumWidth);
			
			var delta = mouseX - Grid.mouseStartPosition;
			//resize of the original by forcing the realtime mode
			Grid.resizeColumn(Grid.selectedColumns, delta, 'realtime');
			
			//hide the dotted line
			Grid.columnLine.style.display = "none";
			//destroy the header copy
			table.parentNode.removeChild(Grid.copy);
		
		}
		//store the information in the cookie
		Grid.storeColumnsInfo();

		document.onmousemove = null;
		document.onmouseup = null;
		
		Grid.headerRow.onmouseover = Grid.headerRow.onmousemove = Grid.displayCursor;
		
		//reset the selection mode
		Grid.setTextSelectionMode(true);
		
		//reset the selectedObject variable
		Grid.selectedColumns = null;
		
		//re-activate grid sorting
		eval('window.setTimeout("Grid.activateSort()",' + Grid.delay + ')');
		
		e.cancelBubble = true;
		if(e.stopPropagation) e.stopPropagation();
	
	},
	
	createCopy: function() {
	
		//for an unknown reason, the main container is not the pageFrame
		var frame = document.getElementById('contentArea');
		var table = document.getElementById('table_' + Grid.identifier);

		//first create the dummy header for the purpose of showing the move
		//create a table that has the same parameters as the original
		var dummyTable = table.cloneNode(false);
		dummyTable.id = 'table_' + Grid.identifier + '_copy';
		
		//create a clone of the table colgroup
		var dummyGroup = Grid.tableGroup.cloneNode(true);
		dummyTable.appendChild(dummyGroup);
		//create a thead tag that has the same information
		var dummyTHead = document.createElement('THEAD');
		dummyTable.appendChild(dummyTHead);
		//and now create a clone of the grid header
		var dummyHeader = Grid.headerRow.cloneNode(true);
		dummyTHead.appendChild(dummyHeader);
		
		//we also need the height of the caption if there is one
		var spacing = Grid.getHeaderTopSpacing();
		var adjustX = (document.all)? 7 : 0;
		var adjustY = (document.all)? 2 : 0;
		
		//place it in a div that we will insert in the document
		var container = document.createElement('DIV');
		container.appendChild(dummyTable);
		//set the style properties of the new element
		container.style.position = "absolute";
		container.style.top = Grid.getAbsolutePosition(table,'top') - Grid.getAbsolutePosition(frame,'top') + spacing - adjustY + 'px';
		container.style.left = Grid.getAbsolutePosition(table,'left') - Grid.getAbsolutePosition(frame,'left') - adjustX + 'px';
		container.style.width = table.offsetWidth + 'px';
		container.style.height = Grid.headerRow.parentNode.offsetHeight + 'px';
		
		//insert the new element just before the table (to get the styles)
		table.parentNode.insertBefore(container, table);
		
		//assign absolute variables
		//need to make that when it's already created
		Grid.copyGroup = Grid.getGroupElements(Grid.identifier + '_copy');
		Grid.copyHeaders = Grid.getHeaderElements(Grid.identifier + '_copy');
		//retrieve the width of all columns
		for(i=0;i<Grid.copyHeaders.length;i++) {
			
			//we need to force upon IE the nowrap of labels
			label = Grid.copyHeaders[i].innerHTML;
			Grid.copyHeaders[i].innerHTML = label.replace(" ","&nbsp;");
			
			//now set the width of the copied elements
			Grid.copyWidth[i] = Grid.copyHeaders[i].offsetWidth;
			
		}
		
		//return the div object
		return container;
	
	},
	
	displayColumnLine: function() {
	
		var line;
		//for an unknown reason, the main container is not the pageFrame
		var frame = document.getElementById('contentArea');
		var table = document.getElementById('table_' + Grid.identifier);
		var spacing = Grid.getHeaderTopSpacing();
		var distance = (document.all)? 0 : 2;

		if(!Grid.columnLine) {
		
			line = document.createElement('DIV');
			line.style.position = 'absolute';
			line.style.width = '1px';
			line.style.height = table.offsetHeight - (spacing + Grid.headerRow.offsetHeight) + 'px';
			line.style.borderLeft = '1px dotted black';
			line.style.top = Grid.getAbsolutePosition(table,'top') - Grid.getAbsolutePosition(frame,'top') + Grid.copy.offsetHeight + spacing + distance + 'px';
			line.style.display = 'none';
			line.style.zIndex = 9999;
			
			frame.appendChild(line);
		
		} else line = Grid.columnLine;
			
		return line;
	
	},
	
	showColumnWidth: function(mousePosition) {
	
		var line = Grid.columnLine;
		var distance = (document.all)? 12 : 5;
		line.style.left = mousePosition - Grid.clickPosition - distance + 'px';
		
		line.style.display = 'block';
	
	},
	
	activateSort: function() {
		//for that we need to get the sort types parameters from the grid
		var sortTypes = new Array();
		for(var i=0;i<Grid.columnHeaders.length;i++) {
		
			var temp = eval('st' + Grid.identifier + '.getSortType(' + i + ')');
			sortTypes.push(temp);
		
		}
		eval('st' + Grid.identifier + '.initHeader(sortTypes)');

	},
	
	getHeader: function(gridId) {
	
		var count = 0;
		
		var table = document.getElementById('table_' + gridId);
		
		//parse the elements of the table to return all header elements
		var thead = Grid.getNodesByType(table, 'THEAD');
		//we assume there is only one THEAD tag
		var headerRow = Grid.getNodesByType(thead[0], 'TR', 'className', 'grid-header');
		
		return headerRow[0];
	
	},
	
	getHeaderElements: function(gridId) {
	
		var count = 0;
		var collection = new Array();
		
		var table = document.getElementById('table_' + gridId);
		
		//parse the elements of the table to return all header elements
		var thead = Grid.getNodesByType(table, 'THEAD');
		//we assume there is only one THEAD tag
		var rowHeader = Grid.getNodesByType(thead[0], 'TR', 'className', 'grid-header');

		//get all columns from the grid-header elements
		var columnHeader = new Array();
		for(var i=0;i<rowHeader.length;i++) {
			//in case there are several headers (don't know why it should be but...)
			temp = Grid.getNodesByType(rowHeader[i], 'TD');
			for(var n=0;n<temp.length;n++)
				columnHeader.push(temp[n]);
		
		}
		return columnHeader;
	
	},
	
	getGroup: function(gridId) {
		
		var count = 0;
		var table = document.getElementById('table_' + gridId);
		
		//parse the elements of the table to return all header elements
		var group = Grid.getNodesByType(table, 'COLGROUP');
		//we assume there is only one COLGROUP tag
		return group[0];
	
	},
	
	getGroupElements: function(gridId) {
	
		var count = 0;
		var collection = new Array();
		
		var table = document.getElementById('table_' + gridId);
		
		//parse the elements of the table to return the colgroup element
		var colgroup = Grid.getNodesByType(table, 'COLGROUP');
		//we assume there is only one COLGROUP tag
		var columns = Grid.getNodesByType(colgroup[0], 'COL');
		
		return columns;
	
	},
	
	getHeaderTopSpacing: function() {
	
		var table = document.getElementById('table_' + Grid.identifier);
		var caption = Grid.getNodesByType(table,'CAPTION')[0];
		if(caption) {
		
			var tab = Grid.getNodesByType(caption,'DIV','className','gridTabber')[0];
			//TODO: I don't know why 3
			spacing = tab.offsetHeight + 3;
		
		} else spacing = 0;
		
		return spacing;
	
	},
	
	/**
		Cookie related functions
	*/
	
	setColumnWidth: function() {

		var id = Grid.identifier;
		
		var colgroup = Grid.getGroupElements(id);
		var columns = Grid.getHeaderElements(id);
		
		//TODO: find how the originalWidth variable can be overwritten
		//alert('setting the originalWidth variable');
		//store the original width of columns
		for(i=0;i<columns.length;i++)		
			Grid.originalWidth[i] = columns[i].offsetWidth;
			
		if(!Grid.getCookie('akilia[gui_grid_' + id + '][columns_width]')) return false;

		//get the informations from the cookie
		var str = Grid.getCookie('akilia[gui_grid_' + id + '][columns_width]');
		var collection = str.split('|');
		//resize columns following cookie information
		for(i=0;i<collection.length;i++)
			columns[i].style.width = colgroup[i].style.width = collection[i] + '%';
		
		//set the reset icon to active
		document.getElementById('switchResize').className = "active";
	
	},
	
	storeColumnsInfo: function() {
	
		var str = "";
		for(var i=0; i<Grid.columnWidth.length; i++)
			str += (Grid.columnWidth[i]/Grid.headerRow.offsetWidth)*100 + "|";
			
		str = str.substring(0,str.lastIndexOf("|"));

		//store everything in the cookie
		Grid.setCookie('akilia[gui_grid_' + Grid.identifier + '][columns_width]',str);
		
		//TODO: find how the originalWidth variable can be overwritten
		//alert('store: ' + Grid.originalWidth);
		
		//set the reset icon to active
		if(document.getElementById('switchResize').className != "active")
			document.getElementById('switchResize').className = "active";
	
	},
	
	resetColumnWidth: function(id) {
	
		var name = 'akilia[gui_grid_' + id + '][columns_width]';
		Grid.deleteCookie(name);
		
		Grid.columnWidth = Grid.originalWidth;
		Grid.resizeColumn(new Array([0,1]), 0, 'realtime');
		
		//set the reset icon to disabled
		document.getElementById('switchResize').className = "disabled";
		
	},
	
	getCookie: function(name) {
	
		var start = document.cookie.indexOf(name+"=");
		var len = start+name.length+1;
		if ((!start) && (name != document.cookie.substring(0,name.length))) return null;
		if (start == -1) return null;
		var end = document.cookie.indexOf(";",len);
		if (end == -1) end = document.cookie.length;
		return unescape(document.cookie.substring(len,end));
	
	},

	setCookie: function(name,value,expires,path,domain,secure) {
	
		document.cookie = name + "=" +escape(value) +
			( (expires) ? ";expires=" + expires.toGMTString() : "") +
			( (path) ? ";path=" + path : "") + 
			( (domain) ? ";domain=" + domain : "") +
			( (secure) ? ";secure" : "");
			
		//alert('value: ' + Grid.getCookie('akilia[gui_grid_' + Grid.identifier + '][columns_width]'));
	
	},
	
	deleteCookie: function(name, path, domain) {

		if(Grid.getCookie(name))
			document.cookie = name + "=" + ((path)? ";path=" + path : "") + ((domain)? ";domain=" + domain : "" ) + ";expires=Thu, 01-Jan-1970 00:00:01 GMT";

	},
	
	/**
		This function finds absolute position x or y of the element in the viewport
	*/
	getAbsolutePosition: function(object, side) {
	
		var currentPosition = 0;
		if (object.offsetParent) {
		
			while (object.offsetParent) {
			
				currentPosition += (side == "left")? object.offsetLeft : object.offsetTop;
				object = object.offsetParent;
			
			}
		
		} else if(side == "left" && object.x) currentPosition += object.x;
		else if(side == "top" && object.y) currentPosition += object.y;
				
		return currentPosition;

	},
	
	/**
		This function returns a collection of child of an object depending
		on the type of node given in parameter and, optionally, a specific 
		attribute on which the function can filter the nodes.
	*/
	getNodesByType: function(object,type,attribute,value) {
	
		var collection = new Array();
			
		var count = 0;
		var nodes = object.childNodes;		
		
		//if there's an attribute specified, prepare the regular expression
		if(attribute) var reg = new RegExp(value,"g");
		//now loop around the childNodes to create the array
		var string = "";
		for(var i=0;i<nodes.length;i++) {
		
			if(nodes[i].nodeName == type) {
				
				if(attribute) {
					
					switch(attribute) {
					
						case 'className':
							/*alert('attribute: ' + attribute + '\n' +
									'nodes[i]: ' + nodes[i] + '\n' +
									eval("nodes[i]." + attribute) + '\n' +
									nodes[i].getAttribute(attribute)
								);*/
							if(eval("nodes[i]." + attribute) != null
								&& ((value)? eval("nodes[i]." + attribute).indexOf(value) != -1 : 1 == 1)) {
								
									collection[count] = nodes[i];
									string += nodes[i].id + '(' + nodes[i].className + '),';
									count++;
							
							}
							break;
					
						default:
							if(nodes[i].getAttribute(attribute) != null
								&& ((value)? nodes[i].getAttribute(attribute).indexOf(value) != -1 : 1 == 1)) {
									
									collection[count] = nodes[i];
									string += nodes[i].id + '(' + nodes[i].className + '),';
									
									/*alert('object: ' + object.id + '\n' + 
											'type: ' + nodes[i].nodeName + ' | ' + type + '\n' +
											'attribute: ' + attribute + '\n' +
											'value: ' + nodes[i].getAttribute(attribute) + ' | ' + value + '\n' +
											string + '\n' + collection
										);*/
									count++;
								 
							}
							break;
					
					}
 
				} else {
				
					/*alert('object: ' + object.id + '\n' + 
							'type: ' + nodes[i].nodeName + ' | ' + type + '\n' +
							string + '\n' + collection
						);*/
					collection[count] = nodes[i];
					count++;
				
				}
			
			}
		
		}
		//alert(collection);
		if(collection.length > 0) 
			return collection;
		else {
			//alert('Grid::getNodesByType error : empty node collection');
			return false;
		}
	
	},
	
	/**
		This function retrieves a style property for a given object
		parameter property must be a string in css style ('background-color' and not 'backgroundColor')
	*/
	getStyle: function(object, property) {
	
		if (object.currentStyle)
			var style = object.currentStyle[property];
		else if (window.getComputedStyle)
			var style = document.defaultView.getComputedStyle(object,null).getPropertyValue(property);
		
		return style;
	
	},
	
	getBorderWidth: function(object,direction) {
	
		var width = 0;
		switch(direction) {
		
			case 'h':
			case 'l':
			case 'r':
				//IE expects the style in JS style, the others in CSS style
				var left = (object.currentStyle)? 'borderLeftWidth' : 'border-left-width';
				var right = (object.currentStyle)? 'borderLeftWidth' : 'border-left-width';
				//now, add the two borders
				if(direction != 'r') width += Number(Grid.getStyle(object,left).substring(0,Grid.getStyle(object,left).indexOf('px')));
				if(direction != 'l') width += Number(Grid.getStyle(object,right).substring(0,Grid.getStyle(object,right).indexOf('px')));
				break;
			
			case 'v':
			case 't':
			case 'b':
				//IE expects the style in JS style, the others in CSS style
				var top = (object.currentStyle)? 'borderTopWidth' : 'border-top-width';
				var bottom = (object.currentStyle)? 'borderBottomWidth' : 'border-bottom-width';
				//now add the two borders				
				if(direction != 'b') width += Number(Grid.getStyle(object,top).substring(0,Grid.getStyle(object,top).indexOf('px')));
				if(direction != 't') width += Number(Grid.getStyle(object,bottom).substring(0,Grid.getStyle(object,bottom).indexOf('px')));
				break;
		
		}
		return width;
	
	},
	
	getPaddingWidth: function(object,direction) {
		
		var width = 0;
		switch(direction) {
		
			case 'h':
			case 'l':
			case 'r':
				var left = (object.currentStyle)? 'paddingLeft': 'padding-left';
				var right = (object.currentStyle)? 'paddingRight': 'padding-right';
				if(direction != 'r') width += Number(Grid.getStyle(object,left).substring(0,Grid.getStyle(object,left).indexOf('px')));
				if(direction != 'l') width += Number(Grid.getStyle(object,right).substring(0,Grid.getStyle(object,right).indexOf('px')));
				break;
		
			case 'v':
			case 't':
			case 'b':
				var top = (object.currentStyle)? 'paddingTop': 'padding-top';
				var bottom = (object.currentStyle)? 'paddingBottom': 'padding-bottom';
				if(direction != 'b') width += Number(Grid.getStyle(object,top).substring(0,Grid.getStyle(object,top).indexOf('px')));
				if(direction != 't') width += Number(Grid.getStyle(object,bottom).substring(0,Grid.getStyle(object,bottom).indexOf('px')));
				break;
		
		}
		return width;
	
	},
	
	getOuterWidth: function(object,direction) {
	
		var width = Grid.getBorderWidth(object,direction) + Grid.getPaddingWidth(object,direction);
		return width;
	
	
	},
	
	setTextSelectionMode: function(bool) {
	
		if(bool) {
				
			document.onselectstart = new Function("return true");	
			if (window.sidebar)			
				document.onmousedown = function() { return true; }		
		
		} else {
			//if the browser is IE4+
			document.onselectstart = new Function("return false");	
			//if the browser is Gecko
			if (window.sidebar){
			
				document.onmousedown = function() { return false; }
				document.onclick = function() { return true; }
		
			}
		
		}
	
	
	}

}


function copyToClipboard(id) {

	var form = eval('document.forms.form_' + id);
	var tableId = 'table_' + id;
	
	if(!form) {
	
		alert(loading_error);
		return false;
	
	}
	var text = cleanHTML(document.getElementById(tableId),false);
	
	if (window.clipboardData) { //IE

		if(!window.clipboardData.getData("Text")) {

			alert(security_error);
			return false;
	
		} else { window.clipboardData.setData("Text", text); }

	} else if (window.netscape) { //mozilla engine
   
		// you have to sign the code or modify security settings to enable this...
		try {
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
		} catch(error) { alert(security_error); }

		var str = Components.classes["@mozilla.org/supports-string;1"].
					createInstance(Components.interfaces.nsISupportsString);
		if (!str) return false;
		str.data = text;
		
		var trans = Components.classes["@mozilla.org/widget/transferable;1"].
					  createInstance(Components.interfaces.nsITransferable);
		if (!trans) return false;
		
		trans.addDataFlavor("text/unicode");
		trans.setTransferData("text/unicode",str,text.length * 2);
		
		var clipid = Components.interfaces.nsIClipboard;
		var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
		if (!clip) return false;
		
		clip.setData(trans,null,clipid.kGlobalClipboard);

	}

	alert(confirmation);
	return false;

}

function sendToExcel(id) {
		
	var form = eval('document.forms.form_' + id);
	var tableId = 'table_' + id;

	if(!form) {
	
		alert(loading_error);
		return false;
	
	}

	var prm = location.search.slice(1).split('&');
	var url = 'index.php?';

	for(i=0;i<prm.length;i++) {
	
		if(i > 0) url = url + '&';
		if(prm[i].slice(0,prm[i].indexOf('=')) == 'request') 
			url += prm[i] + ':::exportToExcel';
		else url += prm[i];
	
	}

	if(document.all) form.target = "_new";
	form.action = url + "&tableId=" + id;
	form.submit();

}

function cleanHTML(table,parsing) {

	var theader, tbody, tfooter;	
	var nodes = table.childNodes;
		
	//first we must separate the table parts
	for(i=0;i<nodes.length;i++) {
	
		if(nodes[i].tagName == "THEAD") theader = nodes[i];
		else if(nodes[i].tagName == "TFOOT") tfooter = nodes[i];
		else if(nodes[i].tagName == "TBODY") tbody = nodes[i];
	
	}
	
	var txt = '<table border="1">';
	
	//now begin with the table header
	if(theader)
		txt += (parsing) ? parseNodes(theader.childNodes) : '<thead>' + theader.innerHTML + '</thead>';
	//pursue with the table body
	txt += (parsing) ? parseNodes(tbody.childNodes) : '<tbody>' + tbody.innerHTML + '</tbody>';
	//pursue with the table footer
	if(tfooter)
		txt += (parsing) ? parseNodes(tfooter.childNodes) : '<tfoot>' + tfooter.innerHTML + '</tfoot>';
	
	txt += '</table>';
	
	return txt;

}

function parseNodes(nod) {

	var text = '';
	for(var i=0;i<nod.length;i++) {
	
		if(nod[i].tagName == "TR") {
	
			text += '<tr>';
			var sub = nod[i].childNodes;
			for(var n=0;n<sub.length;n++)
				if(sub[n].tagName == "TD") text += '<td nowrap="nowrap">' + removeTags(sub[n].innerHTML) + '</td>';
			text += '</tr>';
	
		}
	
	}
	return text;

}

function removeTags(str) {

	var a, b, c, d;
	
	a = str.indexOf("<");
	b = str.indexOf(">");
	c = stripWhitespace(str.substring(0,a));
	
	if(b == -1) b = a;
	
	d = stripWhitespace(str.substring((b + 1), str.length));
	str = c + d;
	
	tagCheck = str.indexOf("<");
	if(tagCheck != -1) str = removeTags(str);
	
	return stripWhitespace(str);

}
function stripWhitespace(string) {

	var start = 0;
	var end = string.length;
	var spaces = new RegExp("[ \f\n\r\t\v]","gi");
	
	//strip before
	for(var i=0;i<string.length;i++) 	
		if(string.substring(i,i+1).match(spaces)) start = i + 1;
		else break;

	//strip after
	for(i=(string.length - 1);i>=0;i--) 
		if(string.substring(i,i+1).match(spaces)) end = i;
		else break;
	
	string = string.substring(start,end);
	return string;

}