
var __grids = new Array();

function __gridProcObj( sf, str, css, cleanUp, widthOvr, heightOvr, obeyCss )
{

	var w = 0, h = 0;

	var txt = null;

	if( ( widthOvr == null ) || ( heightOvr == null ) ) {
		 txt = textSize( str, css, cleanUp );
	}

	if( widthOvr != null ) w = widthOvr; else w = txt.width;
	if( heightOvr != null ) h = heightOvr; else h = txt.height;

	if( ( obeyCss ) && ( str.length == 0 ) ) {
		w = 0;
	}

	return ret = {

		'sf': sf,
		'minWidth': w,
		'minHeight': h,
		'css': css

	}
}



function Grid( id, parent, opt, debugLog )
{
	this.construct = function( id, parent, opt, debugLog )
	{

		this._id = id;
		this._dbg = debugLog;

		var loc = window.location + "";
		var ch = '';

	/*
		if( loc.indexOf( '?', 0 ) == -1 ) {
			ch = '?';
		}
		else {
			ch = '&';
		}

		this._url = loc + ch + 'ctlId=' + this._id;
		this._patchUrl = this._url + '&get=patch';
*/

		if( loc.indexOf( '?', 0 ) != -1 ) {

			var tmp = new Array();

			tmp = loc.split( '?' );

			//loc = loc.replace( /\?*/, '' );

			loc = tmp[ 0 ];
		}

		this._parent = parent;
		this._url = loc;
		this._patchUrl = this._url;

		__grids[ id ] = this;

		this._sRows = new Array();

	}

	this._parent = null;
	this._dbg = null;
	this._id = '';
	this._patchUrl = '';
	this._sfCtl = null;
	this._sfWait = null;

	this._hlRowGroup = 0;
	this._hlRow = 0;

	this._sRows = null;

	this._gridInfo = null;
	this._gridRef = null;

	this._procPipe = null;

	this._recCnt = 0;

	this.getId = function()
	{
		return this._id;
	}

	// --- Pre processing ---

	this._procLayout = function( gridInfo, gridRef )
	{

	}

	

	this._procRowCaptionHeading = function( gridInfo, gridRef )
	{
		gridRef.head.rowCaptionHeading = __gridProcObj(
			new Surface( this.getId() + '_rowCaptionHeading', gridRef.head.sf, this._dbg ), 
			gridInfo.rowCaptionHeading,
			'grid-rowCaptionHeading',
			false,
			null,
			null,
			true
		);

	}

	this._procHeadPadding = function( gridInfo, gridRef )
	{
		gridRef.head.headPadding = __gridProcObj(
			new Surface( this.getId() + '_headPadding', gridRef.head.sf, this._dbg ), 
			gridInfo.rowCaptionHeading,
			'',
			false
		);
	}

	this._procColContainer = function( gridInfo, gridRef )
	{
		gridRef.head.colContainer = __gridProcObj(
			new Surface( this.getId() + '_colContainer', gridRef.head.sf, this._dbg ), 
			'',
			'',
			false
		);

		gridRef.head.colContainer.sf.lock();
	}

	this._procColGroupCaption = function( gridInfo, gridRef, colGrpIndex )
	{
		var css = 'grid-columnGroup-caption';
		if( colGrpIndex == 0 ) css += '-first';

		gridRef.columnGroups[ colGrpIndex ].caption = __gridProcObj(
			new Surface( this.getId() + '_colGrpCaption_' + colGrpIndex, gridRef.head.colContainer.sf, this._dbg ), 
			gridInfo.columnGroups[ colGrpIndex ].caption,			
			css,
			false
		);

		if( gridInfo.showColumnGroupCaptions == true ) {
			gridRef.dim.vert.columnGroupCaption = max(
				gridRef.dim.vert.columnSelect,
				gridRef.columnGroups[ colGrpIndex ].caption.minHeight
			);
		}
		else {
			gridRef.dim.vert.columnGroupCaption = 0;
		}
	}

	this._procColSelect = function( gridInfo, gridRef, colGrpIndex, colIndex  )
	{

		var w = null, h = 20;

		if( gridInfo.fixedColumnWidth != 0 ) {
			w = gridInfo.fixedColumnWidth;
		}

		var css = 'grid-column-select';	
		if( ( colIndex == 0 ) && ( colGrpIndex > 0 ) ) css += '-first';

		gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].select = __gridProcObj(
			new Surface( this.getId() + '_colSelect', gridRef.head.colContainer.sf, this._dbg ), 
			'<input type="checkbox">X</input>',
			css,
			false,
			w,
			h
		);

		if( gridInfo.fixedColumnWidth == 0 ) {
			gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ] = gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].select.minWidth;
		}
		else {
			gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ] = gridInfo.fixedColumnWidth;
		}

		if( gridInfo.showColumnSelects == true ) {

			gridRef.dim.vert.columnSelect = max(
				gridRef.dim.vert.columnSelect,
				gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].select.minHeight
			);
			//gridRef.dim.horz.columns.push( gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ] );
		}
		else {
			gridRef.dim.vert.columnSelect = 0;
		}

	}

	this._procColComment = function( gridInfo, gridRef, colGrpIndex, colIndex  )
	{

		var w = null, h = 20;

		if( gridInfo.fixedColumnWidth != 0 ) {
			w = gridInfo.fixedColumnWidth;
		}

		var css = 'grid-column-comment';	
		if( ( colIndex == 0 ) && ( colGrpIndex > 0 ) ) css += '-first';


		gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].comment = __gridProcObj(
			new Surface( this.getId() + '_colComment', gridRef.head.colContainer.sf, this._dbg ), 
			'X',
			css,
			false,
			w,
			h
		);

		if( gridInfo.fixedColumnWidth == 0 ) {
			gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ] = max(
				gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].comment.minWidth,
				gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ]
			);
		}

		if( gridInfo.showColumnComments == true ) {

			gridRef.dim.vert.columnComment = max(
				gridRef.dim.vert.columnComment,
				gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].comment.minHeight
			);
		}
		else {
			gridRef.dim.vert.columnComment = 0;
		}
	}

	this._procColCaption = function( gridInfo, gridRef, colGrpIndex, colIndex )
	{

		var w = null, h = null;

		if( gridInfo.fixedColumnWidth != 0 ) {
			w = gridInfo.fixedColumnWidth;
		}

		var css = 'grid-column-caption';	
		if( ( colIndex == 0 ) && ( colGrpIndex > 0 ) ) css += '-first';


		gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].caption = __gridProcObj(
			new Surface( this.getId() + '_colCaption', gridRef.head.colContainer.sf, this._dbg ), 
			gridInfo.columnGroups[ colGrpIndex ].columns[ colIndex].caption,
			css,
			false,
			w,
			h
		);



		if( gridInfo.fixedColumnWidth == 0 ) {
			gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ] = max(
				gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].caption.minWidth,
				gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ]
			);
		}

		if( gridInfo.showColumnCaptions == true ) {

			gridRef.dim.vert.columnCaption = max(
				gridRef.dim.vert.columnCaption,
				gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].caption.minHeight
			);
		}
		else {
			gridRef.dim.vert.columnCaption = 0;
		}
	
	}

	this._procColSubCaption = function( gridInfo, gridRef, colGrpIndex, colIndex  )
	{

		var w = null, h = null;

		if( gridInfo.fixedColumnWidth != 0 ) {
			w = gridInfo.fixedColumnWidth;
		}

		var css = 'grid-column-subCaption';	
		if( ( colIndex == 0 ) && ( colGrpIndex > 0 ) ) css += '-first';


		gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].subCaption = __gridProcObj(
			new Surface( this.getId() + '_colSubCaption', gridRef.head.colContainer.sf, this._dbg ), 
			gridInfo.columnGroups[ colGrpIndex ].columns[ colIndex].subCaption,
			css,
			false,
			w,
			h
		);

		if( gridInfo.fixedColumnWidth == 0 ) {
			gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ] = max(
				gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].subCaption.minWidth,
				gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ]
			);
		}

		if( gridInfo.showColumnSubCaptions == true ) {

			gridRef.dim.vert.columnSubCaption = max(
				gridRef.dim.vert.columnSubCaption,
				gridRef.columnGroups[ colGrpIndex ].columns[ colIndex ].subCaption.minHeight
			);
		}
		else gridRef.dim.vert.columnSubCaption = 0;
	}




	// body

	this._procBodyContainer = function( gridInfo, gridRef )
	{


	}

	this._procVertScrollBar = function( gridInfo, gridRef )
	{
		gridRef.body.vertScrollBar = __gridProcObj(
			new Surface( this.getId() + '_vertScrollBarContainer', gridRef.body.sf, this._dbg ), 
			'',
			'grid-vertScrollBar',
			false
		);

		if( gridInfo.showVerticalScrollBar == true ) {
			//FIXME
			gridRef.dim.horz.vertScrollBar = 20;
		}
		else {
			gridRef.dim.horz.vertScrollBar = 0;
		}
	}

	this._procRowGroupCaption = function( gridInfo, gridRef, rowGrpIndex )
	{
		gridRef.rowGroups[ rowGrpIndex ].caption = __gridProcObj(

			new Surface( this.getId() + '_rowGrpCaption_' + rowGrpIndex, gridRef.body.rows.sf, this._dbg ), 
			gridInfo.rowGroups[ rowGrpIndex ].caption,
			'grid-rowGroup-caption',
			false			

		);


		if( gridInfo.showRowGroupCaptions == true ) {

			gridRef.dim.vert.rowGroups[ rowGrpIndex ].caption = gridRef.rowGroups[ rowGrpIndex ].caption.minHeight;
		}
		else gridRef.dim.vert.rowGroups[ rowGrpIndex ].caption = 0;

	}

	this._procCellContainer = function( gridInfo, gridRef, rowGrpIndex )
	{
		gridRef.rowGroups[ rowGrpIndex ].cells = __gridProcObj(

			new Surface( this.getId() + '_cellContainer_' + rowGrpIndex, gridRef.body.rows.sf, this._dbg ), 
			'',
			'',
			false			

		);

		//gridRef.dim.vert.rowGroups[ rowGrpIndex ].caption = gridRef.rowGroups[ rowGrpIndex ].caption.minHeight;



		gridRef.rowGroups[ rowGrpIndex ].cells.sf.lock();
	}

	this._procRowContainer = function( gridInfo, gridRef )
	{

		var self = this;

		gridRef.body.rows = __gridProcObj(
			new Surface( this.getId() + '_rowContainer', gridRef.body.sf, this._dbg ), 
			'',
			'',
			false
		);


		gridRef.body.rows.sf.lock();
	}

	this._procRowSelect = function( gridInfo, gridRef, rowGrpIndex, rowIndex )
	{

		var w = gridRef.dim.horz.rowSelect;
		var h = null;

		if( gridInfo.fixedRowHeight != 0 ) {
			h = gridInfo.fixedRowHeight;
		}

		gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].select = __gridProcObj(
			new Surface( this.getId() + '_rowSelect_' + rowGrpIndex + '_' + rowIndex, gridRef.body.rows.sf, this._dbg ), 
			'X',
			'grid-row-select',
			false,
			w,
			h
		);

		
		if( gridInfo.showRowSelects == true ) {
/*
			gridRef.dim.horz.rowSelect = max(
				gridRef.dim.horz.rowSelect,
				gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].select.minWidth
			);
*/

			gridRef.dim.horz.rowSelect = 30;
		}
		else {
			gridRef.dim.horz.rowSelect = 0;
		}

		gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows.push( gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].select.minHeight );
	}

	this._procRowComment = function( gridInfo, gridRef, rowGrpIndex, rowIndex )
	{
		var w = gridRef.dim.horz.rowComment;
		var h = null;

		if( gridInfo.fixedRowHeight != 0 ) {
			h = gridInfo.fixedRowHeight;
		}	

		gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].comment = __gridProcObj(
			new Surface( this.getId() + '_rowComment_' + rowGrpIndex + '_' + rowIndex, gridRef.body.rows.sf, this._dbg ), 
			'X',
			'grid-row-comment',
			false,
			w,
			h
		);


		if( gridInfo.showRowComments == true ) {
			gridRef.dim.horz.rowComment = max(
				gridRef.dim.horz.rowComment,
				gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].comment.minWidth
			);

			gridRef.dim.horz.rowComment = 30;

		}
		else gridRef.dim.horz.rowComment = 0;
		


		gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ rowIndex ] = max( 
			gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ rowIndex ],
			gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].comment.minHeight
		);

			

	}

	this._procRowCaption = function( gridInfo, gridRef, rowGrpIndex, rowIndex )
	{
		//var w = gridRef.dim.horz.rowCaption;
		var w = null;
		var h = null;

		if( gridInfo.fixedRowHeight != 0 ) {
			h = gridInfo.fixedRowHeight;
		}	

		gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].caption = __gridProcObj(
			new Surface( this.getId() + '_rowCaption_' + rowGrpIndex + '_' + rowIndex, gridRef.body.rows.sf, this._dbg ), 
			gridInfo.rowGroups[ rowGrpIndex ].rows[ rowIndex ].caption,
			'grid-row-caption',
			false,
			w,
			h
		);		

		if( gridInfo.showRowCaptions == true ) {

			var tmpRowWidth = 0;

			if( gridInfo.rowGroups[ rowGrpIndex ].rows[ rowIndex ].caption.length > 0 ) {
				tmpRowWidth = gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].caption.minWidth;
			}

			
			var tmpCapWidth = 0;

			if( gridInfo.rowCaptionHeading.length > 0 ) {
				tmpCapWidth = gridRef.head.rowCaptionHeading.minWidth;
			}

			gridRef.dim.horz.rowCaption = max( tmpRowWidth, tmpCapWidth );
		}
		else gridRef.dim.horz.rowCaption = 0;

		gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ rowIndex ] = max( 
			gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ rowIndex ],
			gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].caption.minHeight
		);


	}

	this._procFuncIcon = function( gridInfo, gridRef, colGrpIndex, colIndex, rowGrpIndex, rowIndex, iconIndex )
	{
	}

	this._procCellContent = function( gridInfo, gridRef, colGrpIndex, colIndex, rowGrpIndex, rowIndex )
	{
	}

	this._procCell = function( gridInfo, gridRef, cellIndex, colGrpIndex, colIndex, rowGrpIndex, rowIndex )
	{	
	
		var w = null;
		var h = null;

		if( gridInfo.fixedColumnWidth != 0 ) {
			w = gridInfo.fixedColumnWidth;
			//w = gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ];
		}

		if( gridInfo.fixedRowHeight != 0 ) {
			h = gridInfo.fixedRowHeight;
			//h = gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ rowIndex ];
		}

		if( gridInfo.renderMode == 1 ) {

			var css = 'grid-cell';	
			if( ( colIndex == 0 ) && ( colGrpIndex > 0 ) ) css += '-first';


			var tmp = __gridProcObj(
				new Surface(
					this.getId() + '_cell_' + rowGrpIndex + '_' + rowIndex + '_' + cellIndex,
					gridRef.rowGroups[ rowGrpIndex ].cells.sf,
					this._dbg
				), 
				gridInfo.rowGroups[ rowGrpIndex ].rows[ rowIndex ].cells[ cellIndex ].value,
				css,
				false,
				w,
				h
			)

			gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].cells.push( tmp );


			if( gridInfo.fixedColumnWidth == 0 ) {
				gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ] = max(
					gridRef.rowGroups[ rowGrpIndex ].rows[ rowIndex ].cells[ cellIndex ].minWidth,
					gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ]
				);
			}
			else {
				gridRef.dim.horz.columnGroups[ colGrpIndex ].columns[ colIndex ] = gridInfo.fixedColumnWidth;
			}
		}
		else {


		}

	}


	// foot

	this._procRowCaptionPadding = function( gridInfo, gridRef )
	{
		gridRef.foot.rowCaptionPadding = new Object();

		

		gridRef.foot.rowCaptionPadding.sf = new Surface( this.getId() + '_rowCaptionPadding', gridRef.foot.sf, this._dbg );

	}

	this._procHorzScrollBar = function( gridInfo, gridRef )
	{
		gridRef.foot.horzScrollBar = new Object();

		gridRef.foot.horzScrollBar.sf = new Surface( this.getId() + '_horzScrollBar', gridRef.foot.sf, this._dbg );


		if( gridInfo.showHorizontalScrollBar == true ) {
			gridRef.dim.vert.horzScrollBar = 20;
		}
		else {
			gridRef.dim.vert.horzScrollBar = 0;
		}
	}

	this._procFootPadding = function( gridInfo, gridRef )
	{
		gridRef.foot.footPadding = new Object();

		gridRef.foot.footPadding.sf = new Surface( this.getId() + '_footPadding', gridRef.foot.sf, this._dbg );
	}

	this._procControlBar = function( gridInfo, gridRef )
	{
		gridRef.controlBar = new Object();

		if( gridInfo.controlBarPosition == 'bottom' ) {

			gridRef.controlBar.sf = new Surface( this.getId() + '_controlBar', gridRef.foot.sf, this._dbg );

			if( gridInfo.showControlBar == true ) {
				//FIXME
				gridRef.dim.vert.controlBar = 32;
			}
			else gridRef.dim.vert.controlBar = 0;
		}
		else if( gridInfo.controlBarPosition == 'top' ) {

			gridRef.controlBar.sf = new Surface( this.getId() + '_controlBar', gridRef.head.sf, this._dbg );

			if( gridInfo.showControlBar == true ) {
				//FIXME
				gridRef.dim.vert.controlBar = 32;
			}
			else gridRef.dim.vert.controlBar = 0;
		}

	}

	// ---

	this._preProcess = function( gridInfo, gridRef )
	{

		//this._dbg.message( 'Starting pre-procesing ' + timeStamp() );

		this._procPipe = new GridProcessPipe( this.id + '_processPipe', gridInfo, gridRef, this, this._dbg );

		var pipe = this._procPipe;

		pipe.queueCmd( gridProcCmd_layout, null );
		pipe.queueCmd( gridProcCmd_rowCaptionHeading, null );

		pipe.queueCmd( gridProcCmd_vertScrollBar, null );
		pipe.queueCmd( gridProcCmd_headPadding, null );
		pipe.queueCmd( gridProcCmd_colContainer, null );


		pipe.queueCmd( gridProcCmd_rowCaptionPadding, null );
		pipe.queueCmd( gridProcCmd_horzScrollBar, null );
		pipe.queueCmd( gridProcCmd_footPadding, null );
		pipe.queueCmd( gridProcCmd_controlBar, null );


		pipe.queueCmd( gridProcCmd_bodyContainer, null );
		pipe.queueCmd( gridProcCmd_rowContainer, null );
		pipe.queueCmd( gridProcCmd_vertScrollBar, null );

		for( var colGrp in gridInfo.columnGroups ) {


			gridRef.dim.horz.columnGroups.push( { 'columns': new Array() } );
			gridRef.columnGroups.push( { 'caption': null, 'columns': new Array() } );

			for( var col in gridInfo.columnGroups[ colGrp ].columns ) {

				gridRef.columnGroups[ colGrp ].columns.push( { 'select': null, 'comment': null, 'caption': null, 'subCaption': null } );


				pipe.queueCmd( gridProcCmd_colSelect, { 'colGrpIndex': colGrp, 'colIndex': col } );
				pipe.queueCmd( gridProcCmd_colComment, { 'colGrpIndex': colGrp, 'colIndex': col } );
				pipe.queueCmd( gridProcCmd_colCaption, { 'colGrpIndex': colGrp, 'colIndex': col } );
				pipe.queueCmd( gridProcCmd_colSubCaption, { 'colGrpIndex': colGrp, 'colIndex': col } );

			}

			pipe.queueCmd( gridProcCmd_colGroupCaption, { 'colGrpIndex': colGrp } );
		}

		var rowVar = null;


		this._recCnt = 0;
		var cell = 0;

		if( gridInfo.renderMode == 1) {
			for( var rowGrp in gridInfo.rowGroups ) {

			
				gridRef.dim.vert.rowGroups.push( { 'caption': 0, 'rows': new Array() } );
				gridRef.rowGroups.push( { 'caption': null, 'rows': new Array() } );

				pipe.queueCmd( gridProcCmd_cellContainer, { 'rowGrpIndex': rowGrp } );
				pipe.queueCmd( gridProcCmd_rowGroupCaption, { 'rowGrpIndex': rowGrp } );

				for( var row in gridInfo.rowGroups[ rowGrp ].rows ) {

					//gridRef.dim.vert.rowGroups[ rowGrp ].rows.push( 
					gridRef.rowGroups[ rowGrp ].rows.push( { 'select': null, 'comment': null, 'caption': null, 'cells': new Array() } );

					//rowVar = gridRef.rowGroups[ rowGrp ].rows[ row ];

					pipe.queueCmd( gridProcCmd_rowSelect, { 'rowGrpIndex': rowGrp, 'rowIndex': row } );
					pipe.queueCmd( gridProcCmd_rowComment, { 'rowGrpIndex': rowGrp, 'rowIndex': row } );
					pipe.queueCmd( gridProcCmd_rowCaption, { 'rowGrpIndex': rowGrp, 'rowIndex': row } );

				

					cell = 0;

					for( var colGrp in gridInfo.columnGroups ) {

						for( var col in gridInfo.columnGroups[ colGrp ].columns ) {


					
							pipe.queueCmd( gridProcCmd_cell, {						
								'cellIndex': cell,
								'colGrpIndex': colGrp,
								'colIndex': col,
								'rowGrpIndex': rowGrp,
								'rowIndex': row
							});

							cell++;
						}
					}
				}


				this._recCnt++;
			}

		}
		else {

			if( gridInfo.showRowSelects == true ) {
				gridRef.dim.horz.rowSelect = 30;
			}
			else {
				gridRef.dim.horz.rowSelect = 0;	
			}
		
			if( gridInfo.showRowComments == true ) {
				gridRef.dim.horz.rowComment = 30;
			}
			else {
				gridRef.dim.horz.rowComment = 0;	
			}


			var tmp1 = '';
			for( var s = 0; s < gridInfo.longestRowCaption; s++ ) tmp1 += 'X';
			
			var tmp2 = textSize( tmp1, 'grid-row-caption', false ).width;
			var tmp3 = textSize( tmp1, 'grid-row-caption-alt', false ).width;

			gridRef.dim.horz.rowCaption = max( tmp2, tmp3 );

		}


		var self = this;

		pipe.onDone( function() {
			self._renderTable( gridInfo, gridRef );
		});

		pipe.start();

	}

	// --- Render the visual elements ---

	this._renderHead = function( gridInfo, gridRef ) 
	{
		// the head container

		var self = this;


		gridRef.head.sf.onUnlock( function( sfHead ) {
	
			sfHead.expand( true, false );

			var cbTmp = 0;

			if( gridInfo.controlBarPosition == 'top' ) {
				cbTmp = gridRef.dim.vert.controlBar;
			}

			sfHead.setHeight( 
				cbTmp +
				gridRef.dim.vert.columnGroupCaption +
				gridRef.dim.vert.columnSelect +
				gridRef.dim.vert.columnComment +
				gridRef.dim.vert.columnCaption +
				gridRef.dim.vert.columnSubCaption
			);

			sfHead.vAlign( sfAlign_top );

			sfHead.lock();
			sfHead.show();
			sfHead.complete();
			sfHead.unlock();
			
			// control bar

			if( gridInfo.controlBarPosition == 'top' ) {
				self._renderControlBar( gridInfo, gridRef );
			}


			// row caption heading

			var sfRowCaptionHeading = gridRef.head.rowCaptionHeading.sf;


			sfRowCaptionHeading.setCssClass( 'grid-rowCaptionHeading' );

			sfRowCaptionHeading.hAlign( sfAlign_left );
			sfRowCaptionHeading.setWidth( 
				gridRef.dim.horz.rowSelect +
				gridRef.dim.horz.rowComment +
				gridRef.dim.horz.rowCaption
			);
			sfRowCaptionHeading.setHeight( 
				gridRef.dim.vert.columnGroupCaption +
				gridRef.dim.vert.columnSelect +
				gridRef.dim.vert.columnComment +
				gridRef.dim.vert.columnCaption +
				gridRef.dim.vert.columnSubCaption
			);

			sfRowCaptionHeading.setY( cbTmp );

			if( gridInfo.showRowCaptions == true ) {
				sfRowCaptionHeading.setText( gridInfo.rowCaptionHeading );
			}

			sfRowCaptionHeading.lock();

			// head padding

			var sfHeadPadding = gridRef.head.headPadding.sf;

			sfHeadPadding.setCssClass( 'grid-headPadding' );
			sfHeadPadding.setWidth( gridRef.dim.horz.vertScrollBar );
			sfHeadPadding.setHeight( 
				cbTmp +
				gridRef.dim.vert.columnGroupCaption +
				gridRef.dim.vert.columnSelect +
				gridRef.dim.vert.columnComment +
				gridRef.dim.vert.columnCaption +
				gridRef.dim.vert.columnSubCaption
			);
			sfHeadPadding.hAlign( sfAlign_right );
			//sfHeadPadding.setText( gridInfo.sfHeadPadding );

			sfHeadPadding.setY( cbTmp );

			sfHeadPadding.lock();

			// check whether we need to show the head padding and row caption heading

			if(
				(
					gridInfo.showColumnGroupCaptions || gridInfo.showColumnSelects || gridInfo.showColumnComments ||
					gridInfo.showColumnCaptions || gridInfo.showColumnSubCaptions
				) &&	
				(
					gridInfo.showRowSelects || gridInfo.showRowComments || gridInfo.showRowCaptions

				)
			) {		
				sfRowCaptionHeading.show();
				if( gridInfo.showVerticalScrollBar == true ) sfHeadPadding.show(); else sfHeadPadding.hide();
			}
			else {
				sfRowCaptionHeading.hide();
				sfHeadPadding.hide();
			}


			sfRowCaptionHeading.complete();
			sfRowCaptionHeading.unlock();

			sfHeadPadding.complete();
			sfHeadPadding.unlock();

			// column container

			var sfColContainer = gridRef.head.colContainer.sf;

			sfColContainer.onUnlock( function( sfColContainer ) {


				var tmpRs = 0, tmpRc = 0, tmpRcap = 0;
				if( gridInfo.showRowSelects == true ) tmpRs = gridRef.dim.horz.rowSelect; else tmpRs = 0;
				if( gridInfo.showRowComments == true ) tmpRc = gridRef.dim.horz.rowComment; else tmpRc = 0;
				if( gridInfo.showRowCaptions == true ) tmpRcap = gridRef.dim.horz.rowCaption; else tmpRcap = 0;



				var conWidth = 
					gridRef.sf.getWidth() - (
						tmpRs +
						tmpRc +
						tmpRcap +
						gridRef.dim.horz.vertScrollBar
					);

				sfColContainer.setX( tmpRs + tmpRc + tmpRcap );
				sfColContainer.setY( cbTmp );

/*
				var conWidth = 
					gridRef.sf.getWidth() - (
						gridRef.dim.horz.rowSelect +
						gridRef.dim.horz.rowComment +
						gridRef.dim.horz.rowCaption +
						gridRef.dim.horz.vertScrollBar
					);

				sfColContainer.setX( gridRef.dim.horz.rowSelect + gridRef.dim.horz.rowComment + gridRef.dim.horz.rowCaption );
*/
				sfColContainer.setWidth( conWidth );

				var colWidth = 0;
				var colCnt = 0;

				for( var colGrp in gridRef.dim.horz.columnGroups ) {
					for( var col in gridRef.dim.horz.columnGroups[ colGrp ].columns ) {
						colWidth += ( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] * 1 );
						colCnt++;
					}
				}

				// if columns widths are to be modified, do that now


				if( colWidth < conWidth ) {

					if( ( gridInfo.fixedColumnWidth == 0 ) && ( gridInfo.stretchColumns == true ) ) {
						var newWidth = ( conWidth - colWidth ) / colCnt;
						var remWidth = conWidth % newWidth;


						for( var colGrp in gridRef.dim.horz.columnGroups ) {
							for( var col in gridRef.dim.horz.columnGroups[ colGrp ].columns ) {
								gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] += newWidth;

								if( col == colCnt - 1 ) gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] += remWidth;

							}
						}
					}
				}
				else {
					if( gridInfo.renderMode == 2 ) {
						// quick rendering disables horizontal scrolling, so we have to squish the column sizes if too big

						var newWidth = ( colWidth - conWidth ) / colCnt;
						var remWidth = colWidth % newWidth;			

						for( var colGrp in gridRef.dim.horz.columnGroups ) {
							for( var col in gridRef.dim.horz.columnGroups[ colGrp ].columns ) {
								gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] -= ( newWidth * 1 );
								if( col == colCnt - 1 ) gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] -= remWidth;

							}
						}

					}

				}

				


				sfColContainer.setHeight( 
					gridRef.dim.vert.columnGroupCaption +
					gridRef.dim.vert.columnSelect +
					gridRef.dim.vert.columnComment +
					gridRef.dim.vert.columnCaption +
					gridRef.dim.vert.columnSubCaption
				);

				sfColContainer.lock();
				sfColContainer.show();
				sfColContainer.complete();
				//sfColContainer.unlock();

				// columns and column groups


				var colX = 0;
				var colY = 0;
				var colGrpX = 0;

				var sfColGrpCaption = null;

				var sfColSelect = null;
				var sfColComment = null;
				var sfColCaption = null;
				var sfColSubCaption = null;

				var colGrpWidth = 0;

				var css = '';

				for( var colGrp in gridRef.columnGroups ) {


					colGrpWidth = 0;
	
					

					for( var col in gridRef.columnGroups[ colGrp ].columns ) {

						colY = gridRef.dim.vert.columnGroupCaption;
						
						// column select
					
						sfColSelect = gridRef.columnGroups[ colGrp ].columns[ col ].select.sf;

						sfColSelect.setX( colX );
						sfColSelect.setY( colY );

						sfColSelect.setWidth( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] );
						sfColSelect.setHeight( gridRef.dim.vert.columnSelect );


						//FIXME
						sfColSelect.setText( '&nbsp;<input type="radio"></input>&nbsp;' );


						if( gridInfo.globalColumnSelect == false ) {
							if( gridInfo.columnGroups[ colGrp ].multipleSelections == true ) {

								//FIXME
								sfColSelect.setText( '<input type="checkbox"></input>&nbsp;' );
							}
							else {
								//FIXME
								sfColSelect.setText( '<input type="radio" name="' + self.getId() + '_colRadioGroup_' + colGrp +  '"></input>&nbsp;' );		
							}
						}
						else {
							//FIXME
							sfColSelect.setText( '<input type="radio" name="' + self.getId() + '_colRadioGroup"></input>&nbsp;' );		
						}

						css = 'grid-column-select';	
						if( ( col == 0 ) && ( colGrp > 0 ) ) css += '-first';
						sfColSelect.setCssClass( css );


						sfColSelect.lock();
						
						//FIXME: hide removed due to problems with IE... bug must be tracked down
						if( gridInfo.showColumnSelects == true ) sfColSelect.show(); //else sfColSelect.hide();

						sfColSelect.complete();
						sfColSelect.unlock();



						colY += gridRef.dim.vert.columnSelect;

						// column comment

						sfColComment = gridRef.columnGroups[ colGrp ].columns[ col ].comment.sf;

						sfColComment.setX( colX );
						sfColComment.setY( colY );

						css = 'grid-column-comment';	
						if( ( col == 0 ) && ( colGrp > 0 ) ) css += '-first';
						sfColComment.setCssClass( css );

						sfColComment.setWidth( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] );
						sfColComment.setHeight( gridRef.dim.vert.columnComment );

						//FIXME
						if( gridInfo.columnGroups[ colGrp ].columns[ col ].comment.length > 0 ) {
							sfColComment.setText( '<img src="/images/comment.gif" />' );
						}
						else sfColComment.setText( '&nbsp;' );

						sfColComment.lock();
						//FIXME: hide removed due to problems with IE... bug must be tracked down
						if( gridInfo.showColumnComments == true ) sfColComment.show(); // else sfColComment.hide();


						if( gridInfo.columnGroups[ colGrp ].columns[ col ].comment.length > 0 ) {
							
							sfColComment.onUpdate( function( sfColComment, colGrp, col ) {

								var tip = new ToolTip(
									sfColComment.getId() + '_tip',
									sfColComment,
									self._debugLog
								);

								tip.setText( gridInfo.columnGroups[ colGrp ].columns[ col ].comment );

								gridRef.columnGroups[ colGrp ].columns[ col ].comment.tip = tip;

							}, colGrp, col );
						}

						sfColComment.complete();
						sfColComment.unlock();

						colY += gridRef.dim.vert.columnComment;
			

						// column caption

						sfColCaption = gridRef.columnGroups[ colGrp ].columns[ col ].caption.sf;

						sfColCaption.setX( colX );
						sfColCaption.setY( colY );

						css = 'grid-column-caption';	
						if( ( col == 0 ) && ( colGrp > 0 ) ) css += '-first';
						sfColCaption.setCssClass( css );

						sfColCaption.setWidth( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] );
						sfColCaption.setHeight( gridRef.dim.vert.columnCaption );

						sfColCaption.setText( gridInfo.columnGroups[ colGrp ].columns[ col ].caption );
						
						sfColCaption.lock();

						//FIXME: hide removed due to problems with IE... bug must be tracked down
						if( gridInfo.showColumnCaptions == true ) sfColCaption.show(); //else sfColCaption.hide();
						sfColCaption.complete();
						sfColCaption.unlock();

						colY += gridRef.dim.vert.columnCaption;

						// column sub caption

						sfColSubCaption = gridRef.columnGroups[ colGrp ].columns[ col ].subCaption.sf;


						sfColSubCaption.setX( colX );
						sfColSubCaption.setY( colY );

						css = 'grid-column-subCaption';	
						if( ( col == 0 ) && ( colGrp > 0 ) ) css += '-first';
						sfColSubCaption.setCssClass( css );

						sfColSubCaption.setWidth( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] );
						sfColSubCaption.setHeight( gridRef.dim.vert.columnSubCaption );

						sfColSubCaption.setText( gridInfo.columnGroups[ colGrp ].columns[ col ].subCaption );

						sfColSubCaption.lock();
						//FIXME: hide removed due to problems with IE... bug must be tracked down
						if( gridInfo.showColumnSubCaptions == true ) sfColSubCaption.show(); //else sfColSubCaption.hide();
						sfColSubCaption.complete();
						sfColSubCaption.unlock();

						colGrpWidth += ( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] * 1 );

						colX += ( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] * 1 );
					}

					//colGrpWidth = 120;

					sfColGrpCaption = gridRef.columnGroups[ colGrp ].caption.sf;

					sfColGrpCaption.setX( colGrpX );
				
					css = 'grid-columnGroup-caption';
					if( colGrp == 0 ) css += '-first';
					sfColGrpCaption.setCssClass( css );
					sfColGrpCaption.setWidth( colGrpWidth  );
					sfColGrpCaption.setHeight( gridRef.dim.vert.columnGroupCaption );
					sfColGrpCaption.setText( gridInfo.columnGroups[ colGrp ].caption );

					sfColGrpCaption.lock();
					//FIXME: hide removed due to problems with IE... bug must be tracked down
					if( gridInfo.showColumnGroupCaptions == true ) sfColGrpCaption.show(); // else sfColGrpCaption.hide();
					sfColGrpCaption.complete();
					sfColGrpCaption.unlock();


					colGrpX += ( colGrpWidth * 1 );

				}


			});

			sfColContainer.unlock();





			// paint it

			//sfHead.paint();
		});
		gridRef.head.sf.unlock();
		
		//gridRef.head.sf.paint();
		
		
	}	


	this._renderFoot = function( gridInfo, gridRef )
	{
		var self = this;

		gridRef.foot.sf.onUnlock( function( sfFoot ) {

			//sfFoot.setCssClass( 'blue' );			
			sfFoot.expand( true, false );

			var cbTmp = 0;

			if( gridInfo.controlBarPosition == 'bottom' ) {
				cbTmp = gridRef.dim.vert.controlBar;
			}

			sfFoot.setHeight( 
				gridRef.dim.vert.horzScrollBar +
				cbTmp
			);

			sfFoot.vAlign( sfAlign_bottom );

			sfFoot.lock();
			sfFoot.show();
			sfFoot.complete();
			sfFoot.unlock();

			// row caption padding

			var sfRowCaptionPadding = gridRef.foot.rowCaptionPadding.sf;

			sfRowCaptionPadding.setCssClass( 'grid-rowCaptionPadding' );
			sfRowCaptionPadding.setWidth( gridRef.dim.horz.rowSelect + gridRef.dim.horz.rowComment + gridRef.dim.horz.rowCaption  );
			sfRowCaptionPadding.setHeight( gridRef.dim.vert.horzScrollBar );
			sfRowCaptionPadding.hAlign( sfAlign_left );

			sfRowCaptionPadding.lock();
			
			if(
				( ( gridInfo.showRowSelects == true ) || ( gridInfo.showRowComments == true ) || ( gridInfo.showRowCaptions == true ) ) &&
				( gridInfo.showHorizontalScrollBar == true )
			) {
				sfRowCaptionPadding.show();
			}
			//else sfRowCaptionPadding.hide();


			sfRowCaptionPadding.complete();
			sfRowCaptionPadding.unlock();

			// horizontal scroll bar

			var sfHorzScrollBar = gridRef.foot.horzScrollBar.sf;

			sfHorzScrollBar.setCssClass( 'grid-horzScrollBar' );
			sfHorzScrollBar.setX( gridRef.dim.horz.rowSelect + gridRef.dim.horz.rowComment + gridRef.dim.horz.rowCaption );
			sfHorzScrollBar.setWidth( 
				gridRef.sf.getWidth() -
				(
					gridRef.dim.horz.rowSelect +
					gridRef.dim.horz.rowComment +
					gridRef.dim.horz.rowCaption +
					gridRef.dim.horz.vertScrollBar
				)
			);
			sfHorzScrollBar.setHeight( gridRef.dim.vert.horzScrollBar );

			sfHorzScrollBar.lock();

			gridRef.foot.horzScrollBar.instance = new ScrollBar( self.getId() + '_horzScrollBar', scroll_horz, sfHorzScrollBar, self._dbg );

			gridRef.foot.horzScrollBar.instance.addSurface( gridRef.head.colContainer.sf );

			sfHorzScrollBar.onUpdate( function( sfHorzScrollBar ) {
				gridRef.foot.horzScrollBar.instance.paint();
			});

			if( gridInfo.showHorizontalScrollBar == true ) sfHorzScrollBar.show(); else sfHorzScrollBar.hide();
			sfHorzScrollBar.complete();
			sfHorzScrollBar.unlock();

			// foot padding

			var sfFootPadding = gridRef.foot.footPadding.sf;

			sfFootPadding.setCssClass( 'grid-footPadding' );
			sfFootPadding.setWidth( gridRef.dim.horz.vertScrollBar );
			sfFootPadding.setHeight( gridRef.dim.vert.horzScrollBar );
			sfFootPadding.hAlign( sfAlign_right );

			sfFootPadding.lock();
			if( ( gridInfo.showHorizontalScrollBar == true ) && ( gridInfo.showVerticalScrollBar == true ) ) sfFootPadding.show(); else sfFootPadding.hide();
			sfFootPadding.complete();
			sfFootPadding.unlock();


			// control bar

			if( gridInfo.controlBarPosition == 'bottom' ) {
				self._renderControlBar( gridInfo, gridRef );
			}

		});

		//gridRef.foot.sf.update();
		gridRef.foot.sf.unlock();

		//gridRef.foot.sf.paint();

	}

	this._renderControlBar = function( gridInfo, gridRef )
	{
		var sfControlBar = gridRef.controlBar.sf;

		sfControlBar.setCssClass( 'grid-controlBar' );
		sfControlBar.expand( true, false );

		sfControlBar.setHeight( gridRef.dim.vert.controlBar );
		sfControlBar.hAlign( sfAlign_left );


		if( gridInfo.controlBarPosition == 'top' ) {
			sfControlBar.vAlign( sfAlign_top );
		}
		else {
			sfControlBar.vAlign( sfAlign_bottom );
		}

		//sfControlBar.setText( self._recCnt + ' records processed.' );

		//sfControlBar.onUnlock( function( sfControlBar ) {


		if( gridInfo.enablePDF == true ) {
			sfControlBar.setText( '<img class="grid-controlBar-icon" title="Download this grid in .PDF format." src="/images/pdfsmall.png" onclick="pdf(\'' + gridInfo.controlId + '\',__grids);" />' );
		}


		//});


		sfControlBar.lock();
		if( gridInfo.showControlBar == true ) sfControlBar.show(); else sfControlBar.hide();
		sfControlBar.complete();
		sfControlBar.unlock();		
	}

	this._renderBody = function( gridInfo, gridRef, refreshOptions )
	{
		var self = this;

		gridRef.body.sf.onUnlock( function( sfBody ) {

			// body

			//sfBody.setCssClass( 'blue' );			
			sfBody.expand( true, false );

			var cbTmp = 0;

			if( gridInfo.controlBarPosition == 'top' ) {
				cbTmp = gridRef.dim.vert.controlBar;
			}

			sfBody.setHeight( 
				gridRef.sf.getHeight() -
				(
					gridRef.dim.vert.columnGroupCaption +
					gridRef.dim.vert.columnSelect +
					gridRef.dim.vert.columnComment +
					gridRef.dim.vert.columnCaption +
					gridRef.dim.vert.columnSubCaption +
					gridRef.dim.vert.horzScrollBar +
					gridRef.dim.vert.controlBar
				)
			);

			sfBody.setY(
				cbTmp +
				gridRef.dim.vert.columnGroupCaption +
				gridRef.dim.vert.columnSelect +
				gridRef.dim.vert.columnComment +
				gridRef.dim.vert.columnCaption +
				gridRef.dim.vert.columnSubCaption
			);

			sfBody.lock();
			sfBody.show();
			sfBody.complete();
			//sfBody.unlock();

/*
			// vertical scroll bar

			var sfVertScrollBar = gridRef.body.vertScrollBar.sf;

			sfVertScrollBar.setCssClass( 'grid-vertScrollBar' );
			sfVertScrollBar.setWidth( gridRef.dim.horz.vertScrollBar );

			sfVertScrollBar.expand( false, true );
			sfVertScrollBar.hAlign( sfAlign_right );



			sfVertScrollBar.lock();

			gridRef.body.vertScrollBar.instance = new ScrollBar( self.getId() + '_vertScrollBar', scroll_vert, sfVertScrollBar, self._dbg );
			

			sfVertScrollBar.onUpdate( function( sfVertScrollBar ) {
				gridRef.body.vertScrollBar.instance.paint();
			});

			if( gridInfo.showVerticalScrollBar ) sfVertScrollBar.show();// else sfVertScrollBar.hide();
			sfVertScrollBar.complete();
			sfVertScrollBar.unlock();
*/
			// the rows

			var sfRows = gridRef.body.rows.sf;

			//gridRef.body.vertScrollBar.instance.addSurface( sfRows );

			sfRows.onUnlock( function( sfRows, gridRef ) {
		

				sfRows.setCssClass( 'grid-rowContainer' );
				sfRows.setWidth( gridRef.sf.getWidth() - gridRef.dim.horz.vertScrollBar );

				sfRows.expand( false, true );
				sfRows.hAlign( sfAlign_left );

/*
				if( gridInfo.enableQuickRender == true ) {
					self._renderRows_patch( gridInfo, gridRef, sfRows );
				}
*/

				sfRows.lock();

		


				sfRows.onUpdate( function( sfRows, gridRef ) {

					// vertical scroll bar

					var sfVertScrollBar = gridRef.body.vertScrollBar.sf;

					sfVertScrollBar.setCssClass( 'grid-vertScrollBar' );
					sfVertScrollBar.setWidth( gridRef.dim.horz.vertScrollBar );

					sfVertScrollBar.expand( false, true );
					sfVertScrollBar.hAlign( sfAlign_right );



					sfVertScrollBar.lock();

					gridRef.body.vertScrollBar.instance = new ScrollBar( self.getId() + '_vertScrollBar', scroll_vert, sfVertScrollBar, self._dbg );
			

					sfVertScrollBar.onUpdate( function( sfVertScrollBar ) {
						gridRef.body.vertScrollBar.instance.paint();
					});

					if( gridInfo.showVerticalScrollBar ) sfVertScrollBar.show();// else sfVertScrollBar.hide();
					sfVertScrollBar.complete();
					sfVertScrollBar.unlock();

					gridRef.body.vertScrollBar.instance.addSurface( sfRows );

					sfRows.onUnlock( function( sfRows ) {
							
						if( gridInfo.renderMode == 1 ) {
							self._renderRows_sf( gridInfo, gridRef, sfRows );
						}
						else {
							self._renderRows_patch( gridInfo, gridRef, sfRows );
						}



					});

					sfRows.unlock();

				}, gridRef );

				sfRows.show();
			}, gridRef );

			sfRows.unlock();






		});

		gridRef.body.sf.unlock();

		//gridRef.body.sf.paint();

	}




	this._renderRows_patch = function( gridInfo, gridRef, sfRows )
	{
		var self = this;

		var tmp = null;

		if( gridRef.refreshOptions != null ) {
			tmp = gridRef.refreshOptions;
		}
		else {
			tmp = new Object();
		}

		

		tmp.ctlId = this.getId();

		sfRows.patch( this._url, 'rows', tmp, true );
		sfRows.lock();

		sfRows.onPatch( function( sfRows ) {

			sfRows.onUpdate( function( sfRows ) {

				// make sure that the patched table has the right dimensions

				var eTbl = null;
				var eCell = null;
				var eSelect = null;
				var eComment = null;	
				var eCaption = null;
				var eCells = new Array();

				eTbl = getElementById( self.getId() + '_rowsLayout' );
				eSelect = getElementById( self.getId() + '_body_rowGrp_0_row_0_select' );
				eComment = getElementById( self.getId() + '_body_rowGrp_0_row_0_comment' );
				eCaption = getElementById( self.getId() + '_body_rowGrp_0_row_0_caption' );

				$(eTbl).width( sfRows.getWidth() );

/*
				if( $.browser.msie == true ) {

					$(eSelect).width( 30 - 7 );
					$(eComment).width( 30 - 7 );
					$(eCaption).width( gridRef.dim.horz.rowCaption - 9 );

				}
				else {
				}


*/
				if( eSelect ) {
					sfInject( eSelect, self._debugLog );

				

					if( __quirks == true ) {

						var b = eSelect.sf.getBorder().left + eSelect.sf.getBorder().right;
						var p = eSelect.sf.getPadding().left + eSelect.sf.getPadding().right;

						eSelect.sf.setWidth( gridRef.dim.horz.rowSelect - p );

					}
					else {
						eSelect.sf.setWidth( gridRef.dim.horz.rowSelect );
					}
					eSelect.sf.lock();
					eSelect.sf.show();
					eSelect.sf.paint();
				}

				if( eComment ) {
					sfInject( eComment, self._debugLog );

					if( __quirks == true ) {

						var b = eComment.sf.getBorder().left + eComment.sf.getBorder().right;
						var p = eComment.sf.getPadding().left + eComment.sf.getPadding().right;

						eComment.sf.setWidth( gridRef.dim.horz.rowComment - p );

					}
					else {
						eComment.sf.setWidth( gridRef.dim.horz.rowComment );
					}

					eComment.sf.lock();
					eComment.sf.show();
					eComment.sf.paint();
				}

				if( eCaption ) {
					sfInject( eCaption, self._debugLog );

					if( __quirks == true ) {
	
						var b = eCaption.sf.getBorder().left + eCaption.sf.getBorder().right;
						var p = eCaption.sf.getPadding().left + eCaption.sf.getPadding().right;

						eCaption.sf.setWidth( gridRef.dim.horz.rowCaption - p );
					}
					else {
						eCaption.sf.setWidth( gridRef.dim.horz.rowCaption );
					}

					eCaption.sf.lock();
					eCaption.sf.show();
					eCaption.sf.paint();				
				}

				var cellCnt = 0;
				for( var colGrp in gridInfo.columnGroups ) {
					for( var col in gridInfo.columnGroups[ colGrp ].columns ) {		
						eCell = getElementById( self.getId() + '_body_rowGrp_0_row_0_cell_' + cellCnt );

						if( eCell ) {

							eCells.push( eCell );


							sfInject( eCell, self._debugLog );			

							if( __quirks == true ) {

								var b = eCell.sf.getBorder().left + eCell.sf.getBorder().right;
								var p = eCell.sf.getPadding().left + eCell.sf.getPadding().right;

								eCell.sf.setWidth( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] );
							}
							else {
								eCell.sf.setWidth( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] );
							}

							eCell.sf.lock();
							eCell.sf.show();
							eCell.sf.paint();

						}

						cellCnt++;
					}
				}


				if( gridInfo.showRowComments == true ) {

					for( var rowGrp in gridInfo.rowGroups ) {

						for( var row in gridInfo.rowGroups[ rowGrp ].rows ) {

							if( gridInfo.rowGroups[ rowGrp ].rows[ row ].comment.length > 0 ) {
								var tip = new ToolTip(
									'row_tip',
									getElementById( self.getId() + '_body_rowGrp_' + rowGrp + '_row_' + row + '_comment' ),
									self._debugLog
								);

								tip.setText( gridInfo.rowGroups[ rowGrp ].rows[ row ].comment );
							}
						}

					}
				}


				//sfRows.show( 'slow' );
			});
			
			sfRows.show();
			//sfRows.show( 'slow' );
			//sfRows.update();
		});

		sfRows.update();
	}

	this._renderRows_sf = function( gridInfo, gridRef, sfRows )
	{
		sfRows.lock();
		sfRows.complete();

		var lastY = 0;

		for( var rowGrp in gridRef.rowGroups ) {
			lastY += this._renderRowGroup( gridInfo, gridRef, rowGrp, lastY );
		}
	}

	this._renderRowGroup = function( gridInfo, gridRef, rowGrpIndex, rowGrpY )
	{

		var self = this;

		var tmpH = 0;

		if( ( gridRef.rowGroups[ rowGrpIndex ].rows.length > 0 ) || ( !gridInfo.hideEmptyRowGroups ) ) {

			tmpH = gridRef.dim.vert.rowGroups[ rowGrpIndex ].caption;
			for( var row in gridRef.rowGroups[ rowGrpIndex ].rows ) {
				tmpH += ( gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ row ] * 1 );
			}

			sfCellContainer = gridRef.rowGroups[ rowGrpIndex ].cells.sf;
		
	
			sfCellContainer.onUnlock( function( sfCellContainer, gridRef ) {

				var lastY = rowGrpY + gridRef.dim.vert.rowGroups[ rowGrpIndex ].caption;

				// row group caption

				var sfRowGroupCaption = gridRef.rowGroups[ rowGrpIndex ].caption.sf;

				sfRowGroupCaption.setY( rowGrpY );

				sfRowGroupCaption.expand( true, false );
				sfRowGroupCaption.setHeight( gridRef.dim.vert.rowGroups[ rowGrpIndex ].caption );

				sfRowGroupCaption.setCssClass( 'grid-rowGroup-caption' );

				sfRowGroupCaption.setText( gridInfo.rowGroups[ rowGrpIndex ].caption );

				sfRowGroupCaption.lock();
				if( gridInfo.showRowGroupCaptions ) sfRowGroupCaption.show(); // else sfRowGroupCaption.hide();
				sfRowGroupCaption.complete();
				sfRowGroupCaption.unlock();

				// the cell container

				sfCellContainer.setX(
					gridRef.dim.horz.rowSelect +
					gridRef.dim.horz.rowComment +
					gridRef.dim.horz.rowCaption
				);
				sfCellContainer.setY( lastY );

				sfCellContainer.setHeight( tmpH - gridRef.dim.vert.rowGroups[ rowGrpIndex ].caption );
	
				sfCellContainer.setWidth( gridRef.sf.getWidth() - 
					(
						gridRef.dim.horz.rowSelect +
						gridRef.dim.horz.rowComment +
						gridRef.dim.horz.rowCaption +
						gridRef.dim.horz.vertScrollBar
					)
				);

				//sfCellContainer.setCssClass( '' );

				sfCellContainer.lock();

				sfCellContainer.onUpdate( function( sfCellContainer, gridRef ) {
					gridRef.foot.horzScrollBar.instance.addSurface( sfCellContainer );
				}, gridRef );


				sfCellContainer.show();
				sfCellContainer.complete();
				//sfCellContainer.unlock();
			

				var sfRowSelect = null, sfRowComment = null, sfRowCaption = null, sfCell = null;

			

				// the rows

				var lastCellY = 0;

				var css = '';


				for( var row in gridRef.rowGroups[ rowGrpIndex ].rows ) {

				
					if( !gridInfo.globalRowSelects ) {
						if( gridInfo.rowGroups[ rowGrpIndex ].multipleSelections == false ) {
							if( !gridRef.rowGroups[ rowGrpIndex ].hlRow ) {
								gridRef.rowGroups[ rowGrpIndex ].hlRow = row;
							}
						}
					}
					else {
						self._hlRow = row;
					}

					// row select

					sfRowSelect = gridRef.rowGroups[ rowGrpIndex ].rows[ row ].select.sf;

					sfRowSelect.setY( lastY );

					sfRowSelect.setHeight( gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ row ] );
					sfRowSelect.setWidth( gridRef.dim.horz.rowSelect );

					css = 'grid-row-select';

					if( row % 2 != 0 ) {
						css += '-alt';
					}

					sfRowSelect.setCssClass( css ); // don't remove - here to use the surface's revert ability

				
					if( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].selected == true ) {
						if( gridInfo.enableRowHilight == true ) {
							css += '-selected';
							sfRowSelect.setCssClass( css );
						}
					}		

					self._renderRowSelect( sfRowSelect, gridInfo, gridRef, rowGrpIndex, row )

					sfRowSelect.lock();
					if( gridInfo.showRowSelects ) sfRowSelect.show(); //else sfRowSelect.hide();
					sfRowSelect.complete();
					sfRowSelect.unlock();
			
					// row comment

					sfRowComment = gridRef.rowGroups[ rowGrpIndex ].rows[ row ].comment.sf;

					sfRowComment.setX( gridRef.dim.horz.rowSelect );
					sfRowComment.setY( lastY );

					sfRowComment.setHeight( gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ row ] );
					sfRowComment.setWidth( gridRef.dim.horz.rowComment );

					css = 'grid-row-comment';

					if( row % 2 != 0 ) {
						css += '-alt';
					}

					sfRowComment.setCssClass( css ); // don't remove - here to use the surface's revert ability

				
					if( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].selected == true ) {
						if( gridInfo.enableRowHilight == true ) {
							css += '-selected';
							sfRowComment.setCssClass( css );
						}
					}

				


					//FIXME
					if( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].comment.length > 0 ) {
						sfRowComment.setText( '<img src="/images/comment.gif" />&nbsp;' );
					}
					else {
						sfRowComment.setText( '&nbsp;' );
					}

					sfRowComment.lock();


					if( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].comment.length > 0 ) {
						sfRowComment.onUpdate( function( sfRowComment, rowGrpIndex, row ) {

							var tip = new ToolTip(
								sfRowComment.getId() + '_tip',
								sfRowComment,
								self._debugLog
							);

							tip.setText( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].comment );
							gridRef.rowGroups[ rowGrpIndex ].rows[ row ].comment.tip = tip;

						}, rowGrpIndex, row );
					}


					if( gridInfo.showRowComments ) sfRowComment.show(); //else sfRowComment.hide();
					sfRowComment.complete();
					sfRowComment.unlock();
			
					// row caption

					sfRowCaption = gridRef.rowGroups[ rowGrpIndex ].rows[ row ].caption.sf;

					sfRowCaption.setX( gridRef.dim.horz.rowSelect + gridRef.dim.horz.rowComment );
					sfRowCaption.setY( lastY );

					sfRowCaption.setHeight( gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ row ] );
					sfRowCaption.setWidth( gridRef.dim.horz.rowCaption );

					css = 'grid-row-caption';

					if( row % 2 != 0 ) {
						css += '-alt';
					}

					sfRowCaption.setCssClass( css ); // don't remove - here to use the surface's revert ability


					if( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].selected == true ) {
						if( gridInfo.enableRowHilight == true ) {
					
							css += '-selected';
							sfRowCaption.setCssClass( css );
						}
					}
				


					sfRowCaption.setText( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].caption );


					sfRowCaption.lock();

					if( gridInfo.enableRowHilight == true ) {
						sfRowCaption.onUpdate( function( sfRowCaption, self, rowGrpIndex, row ) {
							sfRowCaption.onMouseUp( function( event ) {

								self.__selectRow( rowGrpIndex, row );

							});	
						}, self, rowGrpIndex, row );
					}

					if( gridInfo.showRowCaptions ) sfRowCaption.show(); //else sfRowCaption.hide();
					sfRowCaption.complete();
					sfRowCaption.unlock();
			
					// cells


					var lastCellX = 0;
				
				
					var cell = 0;

					for( var colGrp in gridRef.columnGroups ) {
						for( var col in gridRef.columnGroups[ colGrp ].columns ) {

							sfCell = gridRef.rowGroups[ rowGrpIndex ].rows[ row ].cells[ cell ].sf;

							sfCell.setWidth( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] );
							sfCell.setHeight( gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ row ] );

							sfCell.setX( lastCellX );
							sfCell.setY( lastCellY  );

							css = 'grid-cell';
							if( ( col == 0 ) && ( colGrp > 0 ) ) css += '-first';

							if( row % 2 != 0 ) {
								css += '-alt';
							}

							sfCell.setCssClass( css ); // don't remove - here to use the surface's revert ability


							if( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].selected == true ) {
								if( gridInfo.enableRowHilight == true ) {
							
									css += '-selected';
									sfCell.setCssClass( css );
								}
							}

						

							sfCell.setText( gridInfo.rowGroups[ rowGrpIndex ].rows[ row ].cells[ cell ].value );

							sfCell.lock();

						
							if( gridInfo.enableRowHilight == true ) {
								sfCell.onUpdate( function( sfCell, self, rowGrpIndex, row ) {
									sfCell.onMouseUp( function( event ) {
										self.__selectRow( rowGrpIndex, row );
									});	
								}, self, rowGrpIndex, row );
							}

							sfCell.show();
							sfCell.complete();
							sfCell.unlock();
						
							lastCellX += ( gridRef.dim.horz.columnGroups[ colGrp ].columns[ col ] * 1 );

							cell++;

						}
					}

					lastCellY += ( gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ row ] * 1 );


					lastY += ( gridRef.dim.vert.rowGroups[ rowGrpIndex ].rows[ row ] * 1 );

				}



			}, gridRef );

			sfCellContainer.unlock();
		}


		return tmpH;
	}


	this._renderRowSelect = function( sfRowSelect, gridInfo, gridRef, rowGrpIndex, rowIndex )
	{
		var self = this;

		if( gridInfo.globalRowSelect == false ) {
			if( gridInfo.rowGroups[ rowGrpIndex ].multipleSelections == true ) {

				//FIXME
				if( gridInfo.rowGroups[ rowGrpIndex ].rows[ rowIndex ].selected == true ) {

					sfRowSelect.setText( '<input type="checkbox" checked="true"></input>&nbsp;' );
				}
				else {
					sfRowSelect.setText( '<input type="checkbox"></input>&nbsp;' );
				}
			}
			else {
				//FIXME

				if( gridInfo.rowGroups[ rowGrpIndex ].rows[ rowIndex ].selected == true ) {
					sfRowSelect.setText( '<input type="radio" name="' + self.getId() + '_rowRadioGroup_' + rowGrpIndex +  '" checked=\"true\"></input>&nbsp;' );
				}
				else {
					sfRowSelect.setText( '<input type="radio" name="' + self.getId() + '_rowRadioGroup_' + rowGrpIndex +  '"></input>&nbsp;' );
				}					
			}
		}
		else {
			//FIXME

			if( gridInfo.rowGroups[ rowGrpIndex ].rows[ rowIndex ].selected == true ) {
				sfRowSelect.setText( '<input type="radio" name="' + self.getId() + '_rowRadioGroup" onclick="__grids[\'' + self.getId() + '\'].__setSelectedRow(' + rowGrpIndex + ',' + rowIndex + ');" checked=\"true\"></input>&nbsp;' );		
			}
			else {
				sfRowSelect.setText( '<input type="radio" name="' + self.getId() + '_rowRadioGroup" onclick="__grids[\'' + self.getId() + '\'].__setSelectedRow(' + rowGrpIndex + ',' + rowIndex + ');"></input>&nbsp;' );		
			}
		}
	}

	this._updateScrollBars = function( gridRef )
	{
		gridRef.body.vertScrollBar.instance.update();
		gridRef.foot.horzScrollBar.instance.update();
	}

	this._renderTable = function( gridInfo, gridRef )
	{
		var self = this;

		if( gridInfo.renderMode == 1 ) {
			gridRef.sf.onPaint( function( sfCtl, gridRef ) {

				self._doWait( false, function( self ) {

					sfCtl.onUpdate( function( sfCtl, self ) {
						self._updateScrollBars( gridRef );
					}, self );

					sfCtl.show( 'slow' );
					sfCtl.paint();

				});

			}, gridRef );
		}
		else {

			gridRef.sf.onPaint( function( sfCtl, gridRef ) {


				gridRef.body.rows.sf.onPatch( function( sfRows, gridRef ) {
					self._doWait( false, function( self ) {

						sfCtl.onUpdate( function( sfCtl, self ) {
							self._updateScrollBars( gridRef );
						}, self );

						//self._updateScrollBars( gridRef );

						sfCtl.show( 'slow' );
						sfCtl.paint();
					});
				}, gridRef );

			}, gridRef );
			
		}

		gridRef.sf.onUnlock( function( sfCtl ) {
	
			sfCtl.expand( true, true );

			sfCtl.setCssClass( 'grid-canvas' );

			sfCtl.lock();

			sfCtl.onUpdate( function( sfCtl ) {
				self._renderHead( gridInfo, gridRef );
				self._renderFoot( gridInfo, gridRef );
				self._renderBody( gridInfo, gridRef );
			});

			sfCtl.update();
			sfCtl.complete();


		});
		gridRef.sf.unlock();
		gridRef.sf.paint();

	}

	this._renderLoadingScreen = function()
	{
		this._sfWait = new Surface( 'sf_' + this._parent + '_wait', this._parent, debugLog );			

		this._sfWait.onUnlock( function( sfWait ) {
			sfWait.setCssClass( "wait-control" );
			
			sfWait.expand( true, true );

			sfWait.lock();
			sfWait.update();
		});
	
		this._sfWait.unlock();

		this._sfWait.paint( true );
	}

	this._doWait = function( show, callback )
	{
		var self = this;

		if( show ) {
	
			

			if( callback ) {
				this._sfWait.onShow( function( sfWait ) {
					if( callback != null ) callback( self );
				});
			}

			this._sfWait.show( 'slow' );
		}
		else {
			

			if( callback ) {

				this._sfWait.onHide( function( sfWait ) {
					if( callback != null ) callback( self );
				});
			}

			this._sfWait.hide( 'slow' );
		}

		this._sfWait.paint();
		
	}

	this._lastRefreshOptions = '';
	this.getLastRefreshOptions = function()
	{
		return this._lastRefreshOptions;
	}

	this._render = function( refreshOptions )
	{
		var self = this;

		this._renderLoadingScreen();

		this._doWait( true, function( self ) {

			//var ajaxUrl = self._url + '&get=json&structId=grid';
		
			var tmp = null;

			if( refreshOptions != null ) {
				tmp = refreshOptions;
			}
			else {
				tmp = new Object();
			}

			tmp.ctlId = self.getId();
			tmp.get = 'json';
			tmp.structId = 'grid';

			self._lastRefreshOptions = tmp;

			$.get( self._url, tmp, function( ret, code ) {

				self._sfCtl = new Surface( 'sf_' + self._parent, self._parent, debugLog );
				
				self._sfCtl.onUnlock( function( sfCtl, self ) {

					var gridInfo = parseJSON( ret );


					if( gridInfo != null ) {

						sfCtl.lock();

						if( gridInfo.clientErrorCode == 0 ) {

							

							var gridRef = {

								'sf': sfCtl,
								'refreshOptions': refreshOptions,
								'dim': {
									'horz': {
										'rowSelect': 0,
										'rowComment': 0,
										'rowCaption': 0,
										'vertScrollBar': 0,

										'columnGroups': new Array(),
										'columns': new Array()
									},
									'vert': {
										'columnGroupCaption': 0,
										'columnSelect': 0,
										'columnComment': 0,
										'columnCaption': 0,
										'columnSubCaption': 0,
										'horzScrollBar': 0,
										'controlBar': 0,

										'rowGroups': new Array()
									}

								},

								'head': {

									'sf': new Surface( self.getId() + '_head', self._sfCtl, self._dbg ),

									'rowCaptionHeading': null,
									'headPadding': null,
									'colContainer': null,
									'controlBar': null

								},

								'body': {
									'sf': new Surface( self.getId() + '_body', self._sfCtl, self._dbg ),
									'rows': null,
									'vertScrollBar': null
								},


								'foot': {
									'sf': new Surface( self.getId() + '_foot', self._sfCtl, self._dbg ),

									'rowCaptionPadding': null,
									'footPadding': null,
									'horzScrollBar': null									
								},

								'columnGroups': new Array(),
								'columns': new Array(),
	
								'rowGroups': new Array(),
								'rows': new Array(),

								'controlBar': null
							};

							self._gridRef = gridRef;
							self._gridInfo = gridInfo;

							gridRef.head.sf.lock();
							gridRef.body.sf.lock();
							gridRef.foot.sf.lock();

		

					
							self._preProcess( gridInfo, gridRef );
						}
						else {
							eval( gridInfo.clientErrorHandler + '(' + gridInfo.clientErrorCode + ');' );
						}
					}
					else throw 'No data in grid!';
				}, self );

				self._sfCtl.unlock();

				if( refreshOptions ) {
					self._sfCtl.paint();
				}
			});
		
		});
	}

	this.refresh = function( refreshOptions )
	{

		var self = this;


		this._sfCtl.onHide( function() {

			// first do some clean up
			//sfCleanUp();

			self._sfCtl.kill();

			// now render the grid
			self._render( refreshOptions );
		});

		this._sfCtl.hide( 'slow' );
		this._sfCtl.paint( true );
	}

	this.paint = function( options )
	{
		this._render( options );	
	}


	this.__selectRow = function( rowGroup, row )
	{
		var gridRef = this._gridRef;
		var gridInfo = this._gridInfo;

		if( gridInfo.enableRowHilight == true ) {

			var 
				sfOldCell = null, 
				sfNewCell = null,
				sfOldRowCaption = null,
				sfNewRowCaption = null,
				sfOldRowSelect = null,
				sfNewRowSelect = null,
				sfOldRowComment = null,
				sfNewRowComment = null;

			if( gridInfo.renderMode == 1 ) {

				var hlRow = 0;
				var hlRowGroup = 0;


				var cell = 0;

				if( gridInfo.globalRowSelect == true ) {

					hlRow = this._hlRow;
					hlRowGroup = this._hlRowGroup;

					if( hlRow != row ) {

						this._hlRowGroup = rowGroup;
						this._hlRow = row;

						gridInfo.rowGroups[ rowGroup ].rows[ row ].selected = true;
						gridInfo.rowGroups[ hlRowGroup ].rows[ hlRow ].selected = false;

						sfOldRowCaption = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].caption.sf;
						sfNewRowCaption = gridRef.rowGroups[ rowGroup ].rows[ row ].caption.sf;

						sfOldRowSelect = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].select.sf;
						sfNewRowSelect = gridRef.rowGroups[ rowGroup ].rows[ row ].select.sf;

						sfOldRowComment = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].comment.sf;
						sfNewRowComment = gridRef.rowGroups[ rowGroup ].rows[ row ].comment.sf;
					}
				}
				else {
					hlRowGroup = rowGroup;


					if( gridInfo.rowGroups[ rowGroup ].multipleSelections == true ) {

						hlRow = row;

						gridInfo.rowGroups[ rowGroup ].rows[ row ].selected = !gridInfo.rowGroups[ rowGroup ].rows[ row ].selected;

						if( gridInfo.rowGroups[ rowGroup ].rows[ row ].selected == false ) {
							sfOldRowCaption = gridRef.rowGroups[ rowGroup ].rows[ row ].caption.sf;
							sfOldRowSelect = gridRef.rowGroups[ rowGroup ].rows[ row ].select.sf;
							sfOldRowComment = gridRef.rowGroups[ rowGroup ].rows[ row ].comment.sf;
						}
						else {
							sfNewRowCaption = gridRef.rowGroups[ rowGroup ].rows[ row ].caption.sf;
							sfNewRowSelect = gridRef.rowGroups[ rowGroup ].rows[ row ].select.sf;
							sfNewRowComment = gridRef.rowGroups[ rowGroup ].rows[ row ].comment.sf;
						}

					}
					else {

						if( gridRef.rowGroups[ hlRowGroup ].hlRow ) {

							hlRow = gridRef.rowGroups[ hlRowGroup ].hlRow;
	
							gridInfo.rowGroups[ hlRowGroup ].rows[ hlRow ].selected = false;

							sfOldRowCaption = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].caption.sf;
							sfOldRowSelect = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].select.sf;
							sfOldRowComment = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].comment.sf;
						}
						


						gridInfo.rowGroups[ rowGroup ].rows[ row ].selected = true;

						gridRef.rowGroups[ rowGroup ].hlRow = row;
						
						sfNewRowCaption = gridRef.rowGroups[ rowGroup ].rows[ row ].caption.sf;
						sfNewRowSelect = gridRef.rowGroups[ rowGroup ].rows[ row ].select.sf;
						sfNewRowComment = gridRef.rowGroups[ rowGroup ].rows[ row ].comment.sf;

					}
				}
			}
/*
			else if( gridInfo.renderMode == 2 ) {
				// Rows patch

				if( gridInfo.globalRowSelect == true ) {

					hlRow = this._hlRow;
					hlRowGroup = this._hlRowGroup;

					if( hlRow != row ) {

						this._hlRowGroup = rowGroup;
						this._hlRow = row;

					/*
					sfOldRowCaption = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].caption.sf;
					sfNewRowCaption = gridRef.rowGroups[ rowGroup ].rows[ row ].caption.sf;

					sfOldRowSelect = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].select.sf;
					sfNewRowSelect = gridRef.rowGroups[ rowGroup ].rows[ row ].select.sf;

					sfOldRowComment = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].comment.sf;
					sfNewRowComment = gridRef.rowGroups[ rowGroup ].rows[ row ].comment.sf;
					*


					//id="ctlScrollGrid_body_rowGrp_1_row_1_caption"
					

						sfOldRowCaption = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_caption' ) ).sf;
						sfNewRowCaption = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_caption' ) ).sf;

						sfOldRowSelect = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_select' ) ).sf;
						sfNewRowSelect = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_select' ) ).sf;

						sfOldRowComment = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_comment' ) ).sf;
						sfNewRowComment = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_comment' ) ).sf;
					}

				}
				else {
					hlRowGroup = rowGroup;


					if( gridInfo.rowGroups[ rowGroup ].multipleSelections == true ) {

						hlRow = row;

						gridInfo.rowGroups[ rowGroup ].rows[ row ].selected = !gridInfo.rowGroups[ rowGroup ].rows[ row ].selected;

						if( gridInfo.rowGroups[ rowGroup ].rows[ row ].selected == false ) {
							/*
							sfOldRowCaption = gridRef.rowGroups[ rowGroup ].rows[ row ].caption.sf;
							sfOldRowSelect = gridRef.rowGroups[ rowGroup ].rows[ row ].select.sf;
							sfOldRowComment = gridRef.rowGroups[ rowGroup ].rows[ row ].comment.sf;
							*

							sfOldRowCaption = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_caption' ) ).sf;
							sfOldRowSelect = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_select' ) ).sf;
							sfOldRowComment = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_comment' ) ).sf;

						}
						else {
							/*
							sfNewRowCaption = gridRef.rowGroups[ rowGroup ].rows[ row ].caption.sf;
							sfNewRowSelect = gridRef.rowGroups[ rowGroup ].rows[ row ].select.sf;
							sfNewRowComment = gridRef.rowGroups[ rowGroup ].rows[ row ].comment.sf;
							*

							sfNewRowCaption = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_caption' ) ).sf;
							sfNewRowSelect = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_select' ) ).sf;
							sfNewRowComment = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_comment' ) ).sf;

						}

					}
					else {

						if( gridRef.rowGroups[ hlRowGroup ].hlRow ) {
	
							gridInfo.rowGroups[ hlRowGroup ].rows[ hlRow ].selected = false;

							/*
							sfOldRowCaption = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].caption.sf;
							sfOldRowSelect = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].select.sf;
							sfOldRowComment = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].comment.sf;
							*

							sfOldRowCaption = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_caption' ) ).sf;
							sfOldRowSelect = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_select' ) ).sf;
							sfOldRowComment = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_comment' ) ).sf;
						}
						
						gridInfo.rowGroups[ rowGroup ].rows[ row ].selected = true;

						gridRef.rowGroups[ rowGroup ].hlRow = row;
						
						/*
						sfNewRowCaption = gridRef.rowGroups[ rowGroup ].rows[ row ].caption.sf;
						sfNewRowSelect = gridRef.rowGroups[ rowGroup ].rows[ row ].select.sf;
						sfNewRowComment = gridRef.rowGroups[ rowGroup ].rows[ row ].comment.sf;
						*

						sfNewRowCaption = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_caption' ) ).sf;
						sfNewRowSelect = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_select' ) ).sf;
						sfNewRowComment = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_comment' ) ).sf;

					}
				}

				

			}
*/



			// swap the caption

			if( sfOldRowCaption ) {
				sfOldRowCaption.onUnlock( function( sf ) {
					sf.revertCssClass();			

					sf.lock();
					sf.update();
					sf.unlock();

					sf.paint( true );
				});
				sfOldRowCaption.unlock();
			}
				
			if( sfNewRowCaption ) {
				sfNewRowCaption.onUnlock( function( sf ) {

					sf.setCssClass( sf.getCssClass() + '-selected' );		

					sf.lock();
					sf.update();
					sf.unlock();

					sf.paint( true );
				});
				sfNewRowCaption.unlock();
			}

			// swap the comment
			if( sfOldRowComment ) {
				sfOldRowComment.onUnlock( function( sf ) {

					sf.revertCssClass();			

					sf.lock();
					sf.update();
					sf.unlock();

					sf.paint( true );
				});
				sfOldRowComment.unlock();
			}

			if( sfNewRowComment ) {
				sfNewRowComment.onUnlock( function( sf ) {

					sf.setCssClass( sf.getCssClass() + '-selected' );		

					sf.lock();
					sf.update();
					sf.unlock();

					sf.paint( true );
				});
				sfNewRowComment.unlock();
			}

			// swap the select

			if( sfOldRowSelect ) {
				sfOldRowSelect.onUnlock( function( sf, self, rowGroup, row ) {

					sf.revertCssClass();			

					self._renderRowSelect( sf, gridInfo, gridRef, rowGroup, row )

					sf.lock();
					sf.update();
					sf.unlock();

					sf.paint( true );
				}, this, hlRowGroup, hlRow );
				sfOldRowSelect.unlock();
			}

			if( sfNewRowSelect ) {

				sfNewRowSelect.onUnlock( function( sf, self, rowGroup, row ) {

					sf.setCssClass( sf.getCssClass() + '-selected' );		

					self._renderRowSelect( sf, gridInfo, gridRef, rowGroup, row )

					sf.lock();
					sf.update();
					sf.unlock();

					sf.paint( true );
				}, this, rowGroup, row );
				sfNewRowSelect.unlock();
			}


			// swap the cells

			for( var colGrp in gridRef.columnGroups ) {
				for( var col in gridRef.columnGroups[ colGrp ].columns ) {

					if( gridInfo.renderMode == 1 ) {


						if( gridInfo.globalRowSelect == true ) {
							sfOldCell = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].cells[ cell ].sf;
							sfNewCell = gridRef.rowGroups[ rowGroup ].rows[ row ].cells[ cell ].sf;
						}
						else {

							if( gridInfo.rowGroups[ rowGroup ].multipleSelections == true ) {
								if( gridInfo.rowGroups[ rowGroup ].rows[ row ].selected == false ) {

									sfOldCell = gridRef.rowGroups[ rowGroup ].rows[ row ].cells[ cell ].sf;
									sfNewCell = null;
	
								}
								else {
									sfOldCell = null;
									sfNewCell = gridRef.rowGroups[ rowGroup ].rows[ row ].cells[ cell ].sf;
								}
							}
							else {
								sfOldCell = gridRef.rowGroups[ hlRowGroup ].rows[ hlRow ].cells[ cell ].sf;
								sfNewCell = gridRef.rowGroups[ rowGroup ].rows[ row ].cells[ cell ].sf;
							}
						}
					}
					else if( gridInfo.renderMode == 2 ) {
/*
						//id="ctlScrollGrid_body_rowGrp_0_row_2_cell_2"

						if( gridInfo.globalRowSelect == true ) {
							sfOldCell = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_cell_' + cell ) ).sf;
							sfNewCell = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_cell_' + cell ) ).sf;
						}
						else {

							if( gridInfo.rowGroups[ rowGroup ].multipleSelections == true ) {
								if( gridInfo.rowGroups[ rowGroup ].rows[ row ].selected == false ) {

									sfOldCell = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_cell_' + cell ) ).sf;
									sfNewCell = null;
	
								}
								else {
									sfOldCell = null;
									sfNewCell = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_cell_' + cell ) ).sf;
								}
							}
							else {
								sfOldCell = sfInject( getElementById( this.getId() + '_body_rowGrp_' + hlRowGroup + '_row_' + hlRow + '_cell_' + cell ) ).sf;
								sfNewCell = sfInject( getElementById( this.getId() + '_body_rowGrp_' + rowGroup + '_row_' + row + '_cell_' + cell ) ).sf;
							}
						}
*/
					}
						


					if( sfOldCell ) {
						sfOldCell.onUnlock( function( sfOldCell ) {

							sfOldCell.revertCssClass();			

							sfOldCell.lock();
							sfOldCell.update();
							sfOldCell.unlock();

							sfOldCell.paint( true );
						});
						sfOldCell.unlock();
					}


						

					if( sfNewCell ) {
						sfNewCell.onUnlock( function( sfNewCell ) {

							sfNewCell.setCssClass( sfNewCell.getCssClass() + '-selected' );

							sfNewCell.lock();
							sfNewCell.update();
							sfNewCell.unlock();

							sfNewCell.paint( true );
						});
						sfNewCell.unlock();
					}

					cell++;
				}
			}
		}
	}

	this.getSelectedRows = function()
	{
/*
		return {
	
			rowGroup: this._selectedRowGroup,
			row: this._selectedRow

		};
*/
	}


	this.getSelectedColumns = function( colGroup )
	{

	}

	this.construct( id, parent, opt, debugLog );
}
