function GEOTabReportObject(table_id,pager_id,options){
	var self = this;
	this.container = document.getElementById(table_id).parentNode;
	this.table_id = table_id;
	this.pager_id = pager_id;
	
	this.options = {
		height : 400,
		width: 200,
		
		onEnable:null,
		onDisable:null,
		onGridRefresh: null,
		onLoadReport: null,
		onGetDeviceOrDriver:null,
		onGetNodes:null,
		onGetDrivers:null,
		onGetDevices:null,
		onGetStartDate:null,
		onGetEndDate:null,
		
		connectOptionsForm: null,
		includeDriverName:false,
		minCustomerStopMinutes:0,
		includeAuxiliary:false,
		excludeStopsOver:false,
		excludeStopsOverValue:0,
		highlightStopsOver:false,
		highlightStopsOverValue:0,
		expandNodesIntoAssets:false,
		driver_or_device:"",
		current_report_cell_data:"empty"
	};
	
	// Init options
	this.initOptions = function(options){
		for (var i in options){
			this.options[i] = options[i];	
		}
	};
	
	// some init functionality
	this.init = function(){
		this.initOptionsForm();
		this.initGrid();	
		this.fixSizes();
	};
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	// init the form with options that are used on the page
	this.initOptionsForm = function(){
		if (!this.options.connectOptionsForm) return;
		var els = this.options.connectOptionsForm.elements;
		for (var i=0; i<els.length; i++){
			var fld = els[i];
			if (fld.name){
				if (fld.tagName=='SELECT'||(fld.tagName=="INPUT" && fld.type.toLowerCase()!="checkbox")){
					fld.onchange=function(){self.refreshFormOptionData(this.name);};
				}else if (fld.tagName=="INPUT" && fld.type.toLowerCase()=="checkbox"){
					fld.onclick=function(){self.refreshFormOptionData(this.name);};
				}	
				this.refreshFormOptionData(fld.name,true);
			}
		}
	};
	this.refreshFormOptionData = function(name,disableCallback){
		if (!this.options.connectOptionsForm) return;
		var fld = this.options.connectOptionsForm[name];
		if (!fld||fld.length) return;
		if (fld.tagName=='SELECT'||(fld.tagName=="INPUT" && fld.type.toLowerCase()!="checkbox")){
			this.options[name] = fld.value;	
		}else if (fld.tagName=="INPUT" && fld.type.toLowerCase()=="checkbox"){
			this.options[name] = fld.checked;		
		}
		if (!disableCallback && this.options.onGridRefresh) this.options.onGridRefresh();
	};
		
		
		
	// load the grid according to the mentioned type
	this.Grid = null;
	this.GridConfig = null;
	this.current_settings = {};
	this.initGrid = function(){
		this.GridConfig = this._getGridConfig(this.options.current_report_cell_data);
		if (this.Grid) this.Grid.GridUnload();
		this.Grid = jQuery("#"+this.table_id).jqGrid({
			height : this.options.height,
			width : this.options.width,
			shrinkToFit: false, 
			datatype: 'local',
			colNames: this.GridConfig.colNames,
			colModel: this.GridConfig.colModel,
			pager: this.pager_id?jQuery("#"+this.pager_id):null,
			viewrecords: true,
			pgtext: "",
			imgpath: '/jQuery/jqGrid/themes/basic/images'
		  }); 	
	};
	this.fixSizes = function(){
		if (this.Grid){
			this.container.style.display="none";
			var $container = $(this.container.parentNode);
			var h = $container.height();
			var w = $container.width();	
			this.options.width = w;
			this.options.height = h;
			this.Grid.setGridHeight(h - 43);
			this.Grid.setGridWidth(w,false);
			this.container.style.height=h+"px";	
			this.container.style.width=w+"px";	
			this.container.style.display="block";	
		}
	};
	this._getGridConfig = function(method){
		//get the labels from the structs
		for (var i in this.options)
			this.refreshFormOptionData(i,true);
		var data = GeotabConfig.reporttable.grid_config(method,this.options);
		if (method=="details" && this.options.includeAuxiliary) data = data.concat(GeotabConfig.reporttable.grid_config("aux",this.options)); 	
		
		for (var i=0; i<data.length; i++)
			for (var j in data[i]){
				if (j.substr(0,5)=="eval_") {
					alert(data[i][j]);	
					data[i][j.substr(5)] = eval(data[i][j]);
					alert(j.substr(5)+":"+data[i][j.substr(5)]);
				}
			}
		
		
		var colNames = [];
		for (var i=0; i<data.length; i++)
			colNames[i] = data[i].label;
		return {colNames:colNames,colModel:data};
	};
	
	///// Formatters 
	this.dateFormatter = function(el, cellval, opts){
		$(el).html(ConverterAPI.dateTimeFormat(ConverterAPI.parseJSONDate(cellval)));
	};
	this.distanceFormatter = function(el, cellval, opts){
		$(el).html(ConverterAPI.fixDistance(cellval));
	};
	
	
	this.gridEnabled = true;
	this.enableGrid = function(){
		this.gridEnabled = true;	
		if (this.options.onEnable) this.options.onEnable();
	};
	this.disableGrid = function(){
		this.gridEnabled = false;	
		if (this.options.onDisable) this.options.onDisable();
	};
	
	this.currentGridData = [];
	this.maxRowCount = 30;
	this._fillGrid = function(data) {
	    self.enableGrid();
	    self.fillGrid(data);
	    self.fixSizes();
	};
	this.fillGrid = function(data){
		if (!this.gridEnabled) return;
		var mydata = [];
		var flds = this.GridConfig.colModel;
		var currentAddedIndex = 0;
		this.currentGridData = [];
		var start = new Date();
		var extractors = {};
		window.extractComplexField = function(dataObj, name){
			var fieldsChain = name.split('.');
			var currentField = dataObj;
			for(var i = 0; i < fieldsChain.length;i++){
				if (currentField)
					currentField = currentField[fieldsChain[i]];
				else break;
			}
			return currentField;
		};
		for (var j= 0; j<flds.length; j++){
			var name = flds[j].name;
			if (flds[j].name.indexOf('.')==-1)
				extractors[name] = new Function("dataObj", "return dataObj['" + name + "'];");
			else 
				extractors[name] = new Function("dataObj", "return window.extractComplexField(dataObj, '" + name + "');");
		}
		for (var i=0; i<data.length; i++){
			mydata[i] = {};
			var visible = true;
			for (var j= 0; j<flds.length; j++){
				var fldName = flds[j].name;
				var fldConvertor = flds[j].convertor;
				var currentValue = extractors[fldName](data[i]);
      			if (fldConvertor=="date")
					mydata[i][fldName] = ConverterAPI.dateTimeFormat(ConverterAPI.parseJSONDate(currentValue));
				else if	(fldConvertor=="time")
					mydata[i][fldName] = ConverterAPI.parseJSONTime(currentValue);	
				else if	(fldConvertor=="distance")
					mydata[i][fldName] = ConverterAPI.fixDistance(currentValue);
				else if	(fldConvertor=="duration")
					mydata[i][fldName] = ConverterAPI.durationToDecoratedString(currentValue);
				else
					mydata[i][fldName] = currentValue;
					
				if (this.current_report_cell_data=='details' && fld.name=="stopDuration" && this.options.excludeStopsOver && Number(ConverterAPI.strToMinutes(currentValue)) >= Number(this.options.excludeStopsOverValue)) visible=false;
			}
			
			
			//load the rest data
			for (var j in data[i])
				if (mydata[i][j]==undefined)
					mydata[i][j] = data[i][j];
			
			if (this.current_report_cell_data=='details' && this.options.includeAuxiliary){
				for (var j=1; j<=8; j++){
					mydata[i]["aux"+j+"d"] = ConverterAPI.parseJSONTime(data[i].auxIncidentResults["aux"+j].duration);
					mydata[i]["aux"+j+"m"] = ConverterAPI.fixDistance(data[i].auxIncidentResults["aux"+j].distance);	
				}
			}
			if (currentAddedIndex<this.maxRowCount && visible){
				this.Grid.addRowData(currentAddedIndex+1, mydata[i]); 			
				this.currentGridData[currentAddedIndex] = mydata[i];
				currentAddedIndex++;
			}
		}
		this.refreshGridData();
		var end = new Date();
	};
	
	this.refreshGridData = function(){
		var tbl = document.getElementById(this.table_id);
		var flds = this.GridConfig.colModel;
		for (var i=0; i<this.currentGridData.length; i++){
			var data = this.currentGridData[i];
			for (var j=0; j<flds.length; j++){
				var fld = flds[j];
				switch(fld.name){
					case "startDrive": 	
						if (data.isStartDriveWorkHours==false) 
							tbl.rows[i+1].cells[j].style.backgroundColor="yellow";
						break;	
					case "stopDrive": 	
						if (data.isStopDriveWorkHours==false) 
							tbl.rows[i+1].cells[j].style.backgroundColor="yellow";
						break;	
					case "stopDuration": 
						if (this.options.highlightStopsOver && Number(ConverterAPI.strToMinutes(data[fld.name])) >= Number(this.options.highlightStopsOverValue))
							tbl.rows[i+1].cells[j].style.backgroundColor="red";
						break;
					case "idlingDuration": 	
						if (this.options.highlightIdleOver && Number(ConverterAPI.strToMinutes(data[fld.name])) >= Number(this.options.highlightIdleOverValue))
							tbl.rows[i+1].cells[j].style.backgroundColor="red";
						break;
					case "aux1d":
					case "aux2d":
					case "aux3d":
					case "aux4d":
					case "aux5d":
					case "aux6d":
					case "aux7d":
					case "aux8d":
						if (Number(ConverterAPI.strToSeconds(data[fld.name])) > 0)
							tbl.rows[i+1].cells[j].style.backgroundColor="red";
						break;	
					case "aux1m":
					case "aux2m":
					case "aux3m":
					case "aux4m":
					case "aux5m":
					case "aux6m":
					case "aux7m":
					case "aux8m":
						if (Number(data[fld.name]) > 0)
							tbl.rows[i+1].cells[j].style.backgroundColor="red";
						break;		
				}
			}
		}
	};
	
	
	this.loadReport = function(report){
		this.options.current_report_cell_data = report;
		this.options.driver_or_device = this.options.onGetDeviceOrDriver?this.options.onGetDeviceOrDriver():"";
		var fromDate = this.options.onGetStartDate?this.options.onGetStartDate():"2008-06-01T00:00:00Z";
		
		var toDate = this.options.onGetEndDate?this.options.onGetEndDate():"2009-06-01T00:00:00Z";
		var type = this.options.current_report_cell_data+"_"+this.options.driver_or_device;
		var nodes = this.options.onGetNodes?this.options.onGetNodes():[];
		var drivers = this.options.onGetDrivers?this.options.onGetDrivers():[];;
		var devices = this.options.onGetDevices?this.options.onGetDevices():[];;
		var minCustomerStopMinutes = this.options.minCustomerStopMinutes;
		var expandNodesIntoAssets = this.options.expandNodesIntoAssets;
		var includeAuxiliary = this.options.includeAuxiliary;
		if (this.options.onLoadReport) {
			this.initGrid();
			this.disableGrid();	
			this.options.onLoadReport(type,fromDate,toDate,nodes,drivers,devices,minCustomerStopMinutes,expandNodesIntoAssets,includeAuxiliary,self._fillGrid);
		}
	};
	
	options = options||{};
	if (options.length){
		for (var i=0; i<options.length; i++)
			this.initOptions(options[i]);	
	} else {
		this.initOptions(options);		
	}
	this.init();	
}

function GEOTabReportObject2(containerID, options){
	var self = this;
	this.containerID = containerID;
	this.container = document.getElementById(containerID);
	//this.table_id = table_id;
	//this.pager_id = pager_id;
	
	this.options = {
		height : 400,
		width: 200,
		
		onEnable:null,
		onDisable:null,
		onGridRefresh: null,
		onLoadReport: null,
		onGetDeviceOrDriver:null,
		onGetNodes:null,
		onGetDrivers:null,
		onGetDevices:null,
		onGetStartDate:null,
		onGetEndDate:null,
		
		connectOptionsForm: null,
		includeDriverName:false,
		minCustomerStopMinutes:0,
		includeAuxiliary:false,
		excludeStopsOver:false,
		excludeStopsOverValue:0,
		highlightStopsOver:false,
		highlightStopsOverValue:0,
		expandNodesIntoAssets:false,
		driver_or_device:"",
		current_report_cell_data:"empty"
	};
	
	// Init options
	this.initOptions = function(options){
		for (var i in options){
			this.options[i] = options[i];	
		}
	};
	
	// some init functionality
	this.init = function(){
		this.initOptionsForm();
		this.initGrid();	
		this.fixSizes();
	};
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	// init the form with options that are used on the page
	this.initOptionsForm = function(){
		if (!this.options.connectOptionsForm) return;
		var els = this.options.connectOptionsForm.elements;
		for (var i=0; i<els.length; i++){
			var fld = els[i];
			if (fld.name){
				if (fld.tagName=='SELECT'||(fld.tagName=="INPUT" && fld.type.toLowerCase()!="checkbox")){
					fld.onchange=function(){self.refreshFormOptionData(this.name);};
				}else if (fld.tagName=="INPUT" && fld.type.toLowerCase()=="checkbox"){
					fld.onclick=function(){self.refreshFormOptionData(this.name);};
				}	
				this.refreshFormOptionData(fld.name,true);
			}
		}
	};
	this.refreshFormOptionData = function(name,disableCallback){
		if (!this.options.connectOptionsForm) return;
		var fld = this.options.connectOptionsForm[name];
		if (!fld||fld.length) return;
		if (fld.tagName=='SELECT'||(fld.tagName=="INPUT" && fld.type.toLowerCase()!="checkbox")){
			this.options[name] = fld.value;	
		}else if (fld.tagName=="INPUT" && fld.type.toLowerCase()=="checkbox"){
			this.options[name] = fld.checked;		
		}
		if (!disableCallback && this.options.onGridRefresh) this.options.onGridRefresh();
	};
		
		
		
	// load the grid according to the mentioned type
	this.Grid = null;
	this.GridConfig = null;
	this.current_settings = {};
	this.initGrid = function(){
		this.GridConfig = this._getGridConfig(this.options.current_report_cell_data);
		if (this.Grid == null){
			this.Grid = new sGrid(this.containerID, this.GridConfig.colModel);
			this.Grid.attachEvent('onselectionchange', function(){
				if (self.onGridSelectionChange)
					self.onGridSelectionChange.apply(this, arguments);
			});
			this.Grid.attachEvent('ondoubleclick', function(){
				if (self.onGridRowDblClick)
					self.onGridRowDblClick.apply(this, arguments);
			});
		}
		else
			this.Grid.reInit(this.GridConfig.colModel);
	};
	this.fixSizes = function(){
		if (this.Grid){
			this.container.style.display="none";	
			var h = this.container.parentNode.offsetHeight;
			var w = this.container.parentNode.offsetWidth;	
			this.options.width = w;
			this.options.height = h;
			this.Grid.setGridHeight(h-50);
			this.Grid.setGridWidth(w-10);
			this.container.style.height=h+"px";	
			this.container.style.width=w+"px";	
			this.container.style.display="block";	
		}
	};
	this._getGridConfig = function(method){
		//get the labels from the structs
		for (var i in this.options)
			this.refreshFormOptionData(i,true);
		var data = GeotabConfig.reporttable.grid_config(method,this.options);
		if (method=="details" && this.options.includeAuxiliary) data = data.concat(GeotabConfig.reporttable.grid_config("aux",this.options)); 	
		
		for (var i=0; i<data.length; i++)
			for (var j in data[i]){
				if (j.substr(0,5)=="eval_") {
					alert(data[i][j]);	
					data[i][j.substr(5)] = eval(data[i][j]);
					alert(j.substr(5)+":"+data[i][j.substr(5)]);
				}
			}
		
		
		var colNames = [];
		for (var i=0; i<data.length; i++)
			colNames[i] = data[i].label;
		return {colNames:colNames,colModel:data};
	};
	
	///// Formatters 
	this.dateFormatter = function(el, cellval, opts){
		$(el).html(ConverterAPI.dateTimeFormat(ConverterAPI.parseJSONDate(cellval)));
	};
	this.distanceFormatter = function(el, cellval, opts){
		$(el).html(ConverterAPI.fixDistance(cellval));
	};
	
	
	this.gridEnabled = true;
	this.enableGrid = function(){
		this.gridEnabled = true;	
		if (this.options.onEnable) this.options.onEnable();
	};
	this.disableGrid = function(){
		this.gridEnabled = false;	
		if (this.options.onDisable) this.options.onDisable();
	};
	
	this.currentGridData = [];
	this.maxRowCount = 30;
	this._fillGrid = function(data){
		self.enableGrid();
		self.fillGrid(data);
		//self.fixSizes();
	};
	this.fillGrid = function(data) {
		try{
		    this.currentGridData = this.preprocessData(data);
		    var start = new Date();
		    this.Grid.loadDataCollection(this.currentGridData);
		}
		finally{
			this._$gridProgressDialog.stop();
		}
	    var end = new Date();
	};
	
	this.preprocessData = function(dataObjectsArray){//TODO optimization candidate 1
		var extractors = {};
		window.extractComplexField = function(dataObj, name){
			var fieldsChain = name.split('.');
			var currentField = dataObj;
			for(var i = 0; i < fieldsChain.length;i++){
				if (currentField)
					currentField = currentField[fieldsChain[i]];
				else break;
			}
			return currentField;
		};
		for (var j= 0; j<this.GridConfig.colModel.length; j++){
			var name = this.GridConfig.colModel[j].name;
			if (name .indexOf('.')!=-1)
				extractors[name] = new Function("dataObj", "return window.extractComplexField(dataObj, '" + name + "');");
		}
		
		//grid optimization
		var unknownDriverId = 1;
		var unknownDriverName = "Unknown";
		var driverIdFieldName = "driver.entityIdentifier.Id";
		var driverNameFieldName = "driver.name";
		
		extractors[driverIdFieldName] = new Function("dataObj", "return window.extractComplexField(dataObj, '" + driverIdFieldName + "');");
		extractors[driverNameFieldName] = new Function("dataObj", "return window.extractComplexField(dataObj, '" + driverNameFieldName + "');");
		
		var idsCache = {};
		var distinctIdsCount = 0;
		for(var i = 0; i < dataObjectsArray.length; i++){
			for(var name in extractors)
				dataObjectsArray[i][name] = extractors[name](dataObjectsArray[i]);
			var currentDriverId = extractors[driverIdFieldName](dataObjectsArray[i]);
			if (!idsCache[currentDriverId]){
				distinctIdsCount++;
				idsCache[currentDriverId] = true;
			}
			if (currentDriverId == unknownDriverId){
				dataObjectsArray[i][driverNameFieldName] = unknownDriverName;
			}
		}
		
		this.Grid.setColumnVisibility(driverNameFieldName, !(distinctIdsCount == 1 && idsCache[unknownDriverId]));
	
		return dataObjectsArray;
	};
	
	this.refreshGridData = function(){
		var tbl = document.getElementById(this.table_id);
		var flds = this.GridConfig.colModel;
		for (var i=0; i<this.currentGridData.length; i++){
			var data = this.currentGridData[i];
			for (var j=0; j<flds.length; j++){
				var fld = flds[j];
				switch(fld.name){
					case "startDrive": 	
						if (data.isStartDriveWorkHours==false) 
							tbl.rows[i+1].cells[j].style.backgroundColor="yellow";
						break;	
					case "stopDrive": 	
						if (data.isStopDriveWorkHours==false) 
							tbl.rows[i+1].cells[j].style.backgroundColor="yellow";
						break;	
					case "stopDuration": 
						if (this.options.highlightStopsOver && Number(ConverterAPI.strToMinutes(data[fld.name])) >= Number(this.options.highlightStopsOverValue))
							tbl.rows[i+1].cells[j].style.backgroundColor="red";
						break;
					case "idlingDuration": 	
						if (this.options.highlightIdleOver && Number(ConverterAPI.strToMinutes(data[fld.name])) >= Number(this.options.highlightIdleOverValue))
							tbl.rows[i+1].cells[j].style.backgroundColor="red";
						break;
					case "aux1d":
					case "aux2d":
					case "aux3d":
					case "aux4d":
					case "aux5d":
					case "aux6d":
					case "aux7d":
					case "aux8d":
						if (Number(ConverterAPI.strToSeconds(data[fld.name])) > 0)
							tbl.rows[i+1].cells[j].style.backgroundColor="red";
						break;	
					case "aux1m":
					case "aux2m":
					case "aux3m":
					case "aux4m":
					case "aux5m":
					case "aux6m":
					case "aux7m":
					case "aux8m":
						if (Number(data[fld.name]) > 0)
							tbl.rows[i+1].cells[j].style.backgroundColor="red";
						break;		
				}
			}
		}
	};
	
	this._$gridProgressDialog = $("#rightCol").addProgressDialog();
	
	this.loadReport = function(report){
		this._$gridProgressDialog.start();
		var onDataRequestError = function(){
			self._$gridProgressDialog.stop();
			server.dataSource.events.detachEvent("onError", window.__dataRequestError);
		};
		window.__dataRequestError = onDataRequestError;
		server.dataSource.events.attachEvent("onError", onDataRequestError);
		
		this.options.current_report_cell_data = report;
		this.options.driver_or_device = this.options.onGetDeviceOrDriver?this.options.onGetDeviceOrDriver():"";
		var fromDate = this.options.onGetStartDate?this.options.onGetStartDate():"2008-06-01T00:00:00Z";
		
		var toDate = this.options.onGetEndDate?this.options.onGetEndDate():"2009-06-01T00:00:00Z";
		var type = this.options.current_report_cell_data+"_"+this.options.driver_or_device;
		var nodes = this.options.onGetNodes?this.options.onGetNodes():[];
		var drivers = this.options.onGetDrivers?this.options.onGetDrivers():[];;
		var devices = this.options.onGetDevices?this.options.onGetDevices():[];;
		var minCustomerStopMinutes = this.options.minCustomerStopMinutes;
		var expandNodesIntoAssets = this.options.expandNodesIntoAssets;
		var includeAuxiliary = this.options.includeAuxiliary;
		if ( document.selection && document.selection.empty ) document.selection.empty(); // IE Fix. Without it navigation from popup menu directly to grid will crush IE8
		if (this.options.onLoadReport) {
			this.initGrid();
			this.disableGrid();	
			this.options.onLoadReport(type,fromDate,toDate,nodes,drivers,devices,minCustomerStopMinutes,expandNodesIntoAssets,includeAuxiliary,self._fillGrid);
		}
	};
	
	options = options||{};
	if (options.length){
		for (var i=0; i<options.length; i++)
			this.initOptions(options[i]);	
	} else {
		this.initOptions(options);		
	}
	this.init();	
}


