text: /*
  	Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
  	Available via Academic Free License >= 2.1 OR the modified BSD license.
  	see: http://dojotoolkit.org/license for details
  */
  
  
  if(!dojo._hasResource["dojox.grid.DataGrid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  dojo._hasResource["dojox.grid.DataGrid"] = true;
  dojo.provide("dojox.grid.DataGrid");
  
  dojo.require("dojox.grid._Grid");
  dojo.require("dojox.grid.DataSelection");
  
  /*=====
  dojo.declare("dojox.grid.__DataCellDef", dojox.grid.__CellDef, {
  	constructor: function(){
  		//	field: String?
  		//		The attribute to read from the dojo.data item for the row.
  		//  fields: String[]?
  		//		An array of fields to grab the values of and pass as an array to the grid
  		//	get: Function?
  		//		function(rowIndex, item?){} rowIndex is of type Integer, item is of type
  		//		Object.  This function will be called when a cell requests data.  Returns
  		//		the unformatted data for the cell.
  	}
  });
  =====*/
  
  /*=====
  dojo.declare("dojox.grid.__DataViewDef", dojox.grid.__ViewDef, {
  	constructor: function(){
  		//	cells: dojox.grid.__DataCellDef[]|Array[dojox.grid.__DataCellDef[]]?
  		//		The structure of the cells within this grid.
  		//	defaultCell: dojox.grid.__DataCellDef?
  		//		A cell definition with default values for all cells in this view.  If
  		//		a property is defined in a cell definition in the "cells" array and
  		//		this property, the cell definition's property will override this
  		//		property's property.
  	}
  });
  =====*/
  
  dojo.declare("dojox.grid.DataGrid", dojox.grid._Grid, {
  	store: null,
  	query: null,
  	queryOptions: null,
  	fetchText: '...',
  	sortFields: null,
  	
  	// updateDelay: int
  	//		Time, in milliseconds, to delay updates automatically so that multiple
  	//		calls to onSet/onNew/onDelete don't keep rerendering the grid.  Set
  	//		to 0 to immediately cause updates.  A higher value will result in
  	//		better performance at the expense of responsiveness of the grid.
  	updateDelay: 1,
  
  /*=====
  	// structure: dojox.grid.__DataViewDef|dojox.grid.__DataViewDef[]|dojox.grid.__DataCellDef[]|Array[dojox.grid.__DataCellDef[]]
  	//		View layout defintion.
  	structure: '',
  =====*/
  
  	// You can specify items instead of a query, if you like.  They do not need
  	// to be loaded - but the must be items in the store
  	items: null,
  	
  	_store_connects: null,
  	_by_idty: null,
  	_by_idx: null,
  	_cache: null,
  	_pages: null,
  	_pending_requests: null,
  	_bop: -1,
  	_eop: -1,
  	_requests: 0,
  	rowCount: 0,
  
  	_isLoaded: false,
  	_isLoading: false,
  	
  	postCreate: function(){
  		this._pages = [];
  		this._store_connects = [];
  		this._by_idty = {};
  		this._by_idx = [];
  		this._cache = [];
  		this._pending_requests = {};
  
  		this._setStore(this.store);
  		this.inherited(arguments);
  	},
  
  	createSelection: function(){
  		this.selection = new dojox.grid.DataSelection(this);
  	},
  
  	get: function(inRowIndex, inItem){
  		// summary: Default data getter.
  		// description:
  		//		Provides data to display in a grid cell. Called in grid cell context.
  		//		So this.cell.index is the column index.
  		// inRowIndex: Integer
  		//		Row for which to provide data
  		// returns:
  		//		Data to display for a given grid cell.
  		
  		if(inItem && this.field == "_item" && !this.fields){
  			return inItem;
  		}else if(inItem && this.fields){
  			var ret = [];
  			var s = this.grid.store;
  			dojo.forEach(this.fields, function(f){
  				ret = ret.concat(s.getValues(inItem, f));
  			});
  			return ret;
  		}else if(!inItem && typeof inRowIndex === "string"){
  			return this.inherited(arguments);
  		}
  		return (!inItem ? this.defaultValue : (!this.field ? this.value : (this.field == "_item" ? inItem : this.grid.store.getValue(inItem, this.field))));
  	},
  
  	_checkUpdateStatus: function(){
  		if(this.updateDelay > 0){
  			var iStarted = false;
  			if(this._endUpdateDelay){
  				clearTimeout(this._endUpdateDelay);
  				delete this._endUpdateDelay;
  				iStarted = true;
  			}
  			if(!this.updating){
  				this.beginUpdate();
  				iStarted = true;
  			}
  			if(iStarted){
  				var _this = this;
  				this._endUpdateDelay = setTimeout(function(){
  					delete _this._endUpdateDelay;
  					_this.endUpdate();
  				}, this.updateDelay);
  			}
  		}
  	},
  	
  	_onSet: function(item, attribute, oldValue, newValue){
  		this._checkUpdateStatus();
  		var idx = this.getItemIndex(item);
  		if(idx>-1){
  			this.updateRow(idx);
  		}
  	},
  	
  	_createItem: function(item, index){
  		var idty = this._hasIdentity ? this.store.getIdentity(item) : dojo.toJson(this.query) + ":idx:" + index + ":sort:" + dojo.toJson(this.getSortProps());
  		var o = this._by_idty[idty] = { idty: idty, item: item };
  		return o;
  	},
  
  	_addItem: function(item, index, noUpdate){
  		this._by_idx[index] = this._createItem(item, index);
  		if(!noUpdate){
  			this.updateRow(index);
  		}
  	},
  
  	_onNew: function(item, parentInfo){
  		this._checkUpdateStatus();
  		var rowCount = this.get('rowCount');
  		this._addingItem = true;
  		this.updateRowCount(rowCount+1);
  		this._addingItem = false;
  		this._addItem(item, rowCount);
  		this.showMessage();
  	},
  
  	_onDelete: function(item){
  		this._checkUpdateStatus();
  		var idx = this._getItemIndex(item, true);
  
  		if(idx >= 0){
  			// When a row is deleted, all rest rows are shifted down,
  			// and migrate from page to page. If some page is not 
  			// loaded yet empty rows can migrate to initialized pages
  			// without refreshing. It causes empty rows in some pages, see:
  			// http://bugs.dojotoolkit.org/ticket/6818
  			// this code fix this problem by reseting loaded page info
  			this._pages = [];
  			this._bop = -1;
  			this._eop = -1;
  
  			var o = this._by_idx[idx];
  			this._by_idx.splice(idx, 1);
  			delete this._by_idty[o.idty];
  			this.updateRowCount(this.get('rowCount')-1);
  			if(this.get('rowCount') === 0){
  				this.showMessage(this.noDataMessage);
  			}
  		}
  	},
  
  	_onRevert: function(){
  		this._refresh();
  	},
  
  	setStore: function(store, query, queryOptions){
  		this._setQuery(query, queryOptions);
  		this._setStore(store);
  		this._refresh(true);
  	},
  	
  	setQuery: function(query, queryOptions){
  		this._setQuery(query, queryOptions);
  		this._refresh(true);
  	},
  	
  	setItems: function(items){
  		this.items = items;
  		this._setStore(this.store);
  		this._refresh(true);
  	},
  	
  	_setQuery: function(query, queryOptions){
  		this.query = query;
  		this.queryOptions = queryOptions || this.queryOptions;		
  	},
  
  	_setStore: function(store){
  		if(this.store&&this._store_connects){
  			dojo.forEach(this._store_connects,function(arr){
  				dojo.forEach(arr, dojo.disconnect);
  			});
  		}
  		this.store = store;
  
  		if(this.store){
  			var f = this.store.getFeatures();
  			var h = [];
  
  			this._canEdit = !!f["dojo.data.api.Write"] && !!f["dojo.data.api.Identity"];
  			this._hasIdentity = !!f["dojo.data.api.Identity"];
  
  			if(!!f["dojo.data.api.Notification"] && !this.items){
  				h.push(this.connect(this.store, "onSet", "_onSet"));
  				h.push(this.connect(this.store, "onNew", "_onNew"));
  				h.push(this.connect(this.store, "onDelete", "_onDelete"));
  			}
  			if(this._canEdit){
  				h.push(this.connect(this.store, "revert", "_onRevert"));
  			}
  
  			this._store_connects = h;
  		}
  	},
  
  	_onFetchBegin: function(size, req){
  		if(!this.scroller){ return; }
  		if(this.rowCount != size){
  			if(req.isRender){
  				this.scroller.init(size, this.keepRows, this.rowsPerPage);
  				this.rowCount = size;
  				this._setAutoHeightAttr(this.autoHeight, true);
  				this._skipRowRenormalize = true;
  				this.prerender();
  				this._skipRowRenormalize = false;
  			}else{
  				this.updateRowCount(size);
  			}
  		}
  		if(!size){
  			this.views.render();
  			this._resize();
  			this.showMessage(this.noDataMessage);
  			this.focus.initFocusView();
  		}else{
  			this.showMessage();
  		}
  	},
  
  	_onFetchComplete: function(items, req){
  		if(!this.scroller){ return; }
  		if(items && items.length > 0){
  			//console.log(items);
  			dojo.forEach(items, function(item, idx){
  				this._addItem(item, req.start+idx, true);
  			}, this);
  			if(this._autoHeight){
  				this._skipRowRenormalize = true;
  			}
  			this.updateRows(req.start, items.length);
  			if(this._autoHeight){
  				this._skipRowRenormalize = false;
  			}			
  			if(req.isRender){
  				this.setScrollTop(0);
  				this.postrender();
  			}else if(this._lastScrollTop){
  				this.setScrollTop(this._lastScrollTop);
  			}
  		}
  		delete this._lastScrollTop;
  		if(!this._isLoaded){
  			this._isLoading = false;
  			this._isLoaded = true;
  		}
  		this._pending_requests[req.start] = false;
  	},
  
  	_onFetchError: function(err, req){
  		console.log(err);
  		delete this._lastScrollTop;
  		if(!this._isLoaded){
  			this._isLoading = false;
  			this._isLoaded = true;
  			this.showMessage(this.errorMessage);
  		}
  		this._pending_requests[req.start] = false;
  		this.onFetchError(err, req);
  	},
  
  	onFetchError: function(err, req){
  	},
  
  	_fetch: function(start, isRender){
  		start = start || 0;
  		if(this.store && !this._pending_requests[start]){
  			if(!this._isLoaded && !this._isLoading){
  				this._isLoading = true;
  				this.showMessage(this.loadingMessage);
  			}
  			this._pending_requests[start] = true;
  			//console.log("fetch: ", start);
  			try{
  				if(this.items){
  					var items = this.items;
  					var store = this.store;
  					this.rowsPerPage = items.length;
  					var req = {
  						start: start,
  						count: this.rowsPerPage,
  						isRender: isRender
  					};
  					this._onFetchBegin(items.length, req);
  					
  					// Load them if we need to
  					var waitCount = 0;
  					dojo.forEach(items, function(i){
  						if(!store.isItemLoaded(i)){ waitCount++; }
  					});
  					if(waitCount === 0){
  						this._onFetchComplete(items, req);
  					}else{
  						var onItem = function(item){
  							waitCount--;
  							if(waitCount === 0){
  								this._onFetchComplete(items, req);
  							}
  						};
  						dojo.forEach(items, function(i){
  							if(!store.isItemLoaded(i)){
  								store.loadItem({item: i, onItem: onItem, scope: this});
  							}
  						}, this);
  					}
  				}else{
  					this.store.fetch({
  						start: start,
  						count: this.rowsPerPage,
  						query: this.query,
  						sort: this.getSortProps(),
  						queryOptions: this.queryOptions,
  						isRender: isRender,
  						onBegin: dojo.hitch(this, "_onFetchBegin"),
  						onComplete: dojo.hitch(this, "_onFetchComplete"),
  						onError: dojo.hitch(this, "_onFetchError")
  					});
  				}
  			}catch(e){
  				this._onFetchError(e, {start: start, count: this.rowsPerPage});
  			}
  		}
  	},
  
  	_clearData: function(){
  		this.updateRowCount(0);
  		this._by_idty = {};
  		this._by_idx = [];
  		this._pages = [];
  		this._bop = this._eop = -1;
  		this._isLoaded = false;
  		this._isLoading = false;
  	},
  
  	getItem: function(idx){
  		var data = this._by_idx[idx];
  		if(!data||(data&&!data.item)){
  			this._preparePage(idx);
  			return null;
  		}
  		return data.item;
  	},
  
  	getItemIndex: function(item){
  		return this._getItemIndex(item, false);
  	},
  	
  	_getItemIndex: function(item, isDeleted){
  		if(!isDeleted && !this.store.isItem(item)){
  			return -1;
  		}
  
  		var idty = this._hasIdentity ? this.store.getIdentity(item) : null;
  
  		for(var i=0, l=this._by_idx.length; i<l; i++){
  			var d = this._by_idx[i];
  			if(d && ((idty && d.idty == idty) || (d.item === item))){
  				return i;
  			}
  		}
  		return -1;
  	},
  
  	filter: function(query, reRender){
  		this.query = query;
  		if(reRender){
  			this._clearData();
  		}
  		this._fetch();
  	},
  
  	_getItemAttr: function(idx, attr){
  		var item = this.getItem(idx);
  		return (!item ? this.fetchText : this.store.getValue(item, attr));
  	},
  
  	// rendering
  	_render: function(){
  		if(this.domNode.parentNode){
  			this.scroller.init(this.get('rowCount'), this.keepRows, this.rowsPerPage);
  			this.prerender();
  			this._fetch(0, true);
  		}
  	},
  
  	// paging
  	_requestsPending: function(inRowIndex){
  		return this._pending_requests[inRowIndex];
  	},
  
  	_rowToPage: function(inRowIndex){
  		return (this.rowsPerPage ? Math.floor(inRowIndex / this.rowsPerPage) : inRowIndex);
  	},
  
  	_pageToRow: function(inPageIndex){
  		return (this.rowsPerPage ? this.rowsPerPage * inPageIndex : inPageIndex);
  	},
  
  	_preparePage: function(inRowIndex){
  		if((inRowIndex < this._bop || inRowIndex >= this._eop) && !this._addingItem){
  			var pageIndex = this._rowToPage(inRowIndex);
  			this._needPage(pageIndex);
  			this._bop = pageIndex * this.rowsPerPage;
  			this._eop = this._bop + (this.rowsPerPage || this.get('rowCount'));
  		}
  	},
  
  	_needPage: function(inPageIndex){
  		if(!this._pages[inPageIndex]){
  			this._pages[inPageIndex] = true;
  			this._requestPage(inPageIndex);
  		}
  	},
  
  	_requestPage: function(inPageIndex){
  		var row = this._pageToRow(inPageIndex);
  		var count = Math.min(this.rowsPerPage, this.get('rowCount') - row);
  		if(count > 0){
  			this._requests++;
  			if(!this._requestsPending(row)){
  				setTimeout(dojo.hitch(this, "_fetch", row, false), 1);
  				//this.requestRows(row, count);
  			}
  		}
  	},
  
  	getCellName: function(inCell){
  		return inCell.field;
  		//console.log(inCell);
  	},
  
  	_refresh: function(isRender){
  		this._clearData();
  		this._fetch(0, isRender);
  	},
  
  	sort: function(){
  		this._lastScrollTop = this.scrollTop;
  		this._refresh();
  	},
  
  	canSort: function(){
  		return (!this._isLoading);
  	},
  
  	getSortProps: function(){
  		var c = this.getCell(this.getSortIndex());
  		if(!c){
  			if(this.sortFields){
  				return this.sortFields;
  			}
  			return null;
  		}else{
  			var desc = c["sortDesc"];
  			var si = !(this.sortInfo>0);
  			if(typeof desc == "undefined"){
  				desc = si;
  			}else{
  				desc = si ? !desc : desc;
  			}
  			return [{ attribute: c.field, descending: desc }];
  		}
  	},
  
  	styleRowState: function(inRow){
  		// summary: Perform row styling
  		if(this.store && this.store.getState){
  			var states=this.store.getState(inRow.index), c='';
  			for(var i=0, ss=["inflight", "error", "inserting"], s; s=ss[i]; i++){
  				if(states[s]){
  					c = ' dojoxGridRow-' + s;
  					break;
  				}
  			}
  			inRow.customClasses += c;
  		}
  	},
  
  	onStyleRow: function(inRow){
  		this.styleRowState(inRow);
  		this.inherited(arguments);
  	},
  
  	// editing
  	canEdit: function(inCell, inRowIndex){
  		return this._canEdit;
  	},
  
  	_copyAttr: function(idx, attr){
  		var row = {};
  		var backstop = {};
  		var src = this.getItem(idx);
  		return this.store.getValue(src, attr);
  	},
  
  	doStartEdit: function(inCell, inRowIndex){
  		if(!this._cache[inRowIndex]){
  			this._cache[inRowIndex] = this._copyAttr(inRowIndex, inCell.field);
  		}
  		this.onStartEdit(inCell, inRowIndex);
  	},
  
  	doApplyCellEdit: function(inValue, inRowIndex, inAttrName){
  		this.store.fetchItemByIdentity({
  			identity: this._by_idx[inRowIndex].idty,
  			onItem: dojo.hitch(this, function(item){
  				var oldValue = this.store.getValue(item, inAttrName);
  				if(typeof oldValue == 'number'){
  					inValue = isNaN(inValue) ? inValue : parseFloat(inValue);
  				}else if(typeof oldValue == 'boolean'){
  					inValue = inValue == 'true' ? true : inValue == 'false' ? false : inValue;
  				}else if(oldValue instanceof Date){
  					var asDate = new Date(inValue);
  					inValue = isNaN(asDate.getTime()) ? inValue : asDate;
  				}
  				this.store.setValue(item, inAttrName, inValue);
  				this.onApplyCellEdit(inValue, inRowIndex, inAttrName);
  			})
  		});
  	},
  
  	doCancelEdit: function(inRowIndex){
  		var cache = this._cache[inRowIndex];
  		if(cache){
  			this.updateRow(inRowIndex);
  			delete this._cache[inRowIndex];
  		}
  		this.onCancelEdit.apply(this, arguments);
  	},
  
  	doApplyEdit: function(inRowIndex, inDataAttr){
  		var cache = this._cache[inRowIndex];
  		/*if(cache){
  			var data = this.getItem(inRowIndex);
  			if(this.store.getValue(data, inDataAttr) != cache){
  				this.update(cache, data, inRowIndex);
  			}
  			delete this._cache[inRowIndex];
  		}*/
  		this.onApplyEdit(inRowIndex);
  	},
  
  	removeSelectedRows: function(){
  		// summary:
  		//		Remove the selected rows from the grid.
  		if(this._canEdit){
  			this.edit.apply();
  			var fx = dojo.hitch(this, function(items){
  				if(items.length){
  					dojo.forEach(items, this.store.deleteItem, this.store);
  					this.selection.clear();
  				}			
  			});
  			if(this.allItemsSelected){
  				this.store.fetch({
  							query: this.query, 
  							queryOptions: this.queryOptions,
  							onComplete: fx});
  			}else{
  				fx(this.selection.getSelected());
  			}
  		}
  	}
  });
  
  dojox.grid.DataGrid.cell_markupFactory = function(cellFunc, node, cellDef){
  	var field = dojo.trim(dojo.attr(node, "field")||"");
  	if(field){
  		cellDef.field = field;
  	}
  	cellDef.field = cellDef.field||cellDef.name;
  	var fields = dojo.trim(dojo.attr(node, "fields")||"");
  	if(fields){
  		cellDef.fields = fields.split(",");
  	}
  	if(cellFunc){
  		cellFunc(node, cellDef);
  	}
  };
  
  dojox.grid.DataGrid.markupFactory = function(props, node, ctor, cellFunc){
  	return dojox.grid._Grid.markupFactory(props, node, ctor, 
  					dojo.partial(dojox.grid.DataGrid.cell_markupFactory, cellFunc));
  };
  
  }
  