
Type.registerNamespace("Infragistics.Web.UI");

$IG.WebDataGrid = function(element)
{
	/// <summary>
	/// Grid's main DOM object.
	/// </summary>
	$IG.WebDataGrid.initializeBase(this, [element]);
}

$IG.WebDataGrid.prototype =
{
	_thisType: "webDataGrid",

	initialize: function()
	{
		///<summary>
		///Initializes the WebDataGrid object.
		///</summary>
		this._auxRowsBottom = [];
		this._auxRowsTop = [];

		this._initializeBehaviors = $IG.IGridBehaviorContainer.prototype._initializeBehaviors;
		$IG.WebDataGrid.callBaseMethod(this, "initialize");

		this._eventHandlerHash = new Object();
		this._eventHandlerHash.length = 0;
		this._eventHandlerHash.handlers = {};

		this._isWidthEmpty = this._get_clientOnlyValue("we") == "true";
		if (this._isWidthEmpty)
		{
			var width = $util.getPropFromCss(this._element, "width");
			this._hasWidth = (width != "" && width != "auto");
		}
		else
			this._hasWidth = true;
		this._enableAjax = this._get_clientOnlyValue("ea") == "true";
		this._enabled = this._get_clientOnlyValue("en") == "true";

		var pool = this._editorProvidersPool = document.getElementById(this._element.id + "_eppool");

		var cont = this._container = this._elements["container"];
		/* VS 10/02/2009 Bug 22677: avoid scrollable parent (this._container) of editor. */
		/* Move pool into pool-holder DIV, which will be located in parent of this._container */
		if (pool && cont)
		{
			pool = this._poolHolder = document.createElement('DIV');
			pool.style.position = 'absolute';
			cont.parentNode.insertBefore(pool, cont);
			this._ensureEditorProvidersPool(pool);
		}

		this._actionList = new $IG.GridActionTransactionList();

		this._gridUtil = new $IG.GridUtility(this);

		this._initializeObjects();

		if (/*this._isWidthEmpty && */this._get_clientOnlyValue('sv') == '1')
		{
			this._element.style.visibility = 'visible';
			if (this._elements.hdn)
			{
				if (this._elements.hdn.length)
				{
					for (var i = 0; i < this._elements.hdn.length; i++)
					{
						this._elements.hdn[i].style.visibility = "visible";
					}
				}
				else
					this._elements.hdn.style.visibility = "visible";
			}
		}

		this._initializeMargins();

		this._adjustGridLayout();

		if (this._thisType == "webDataGrid")
			this._raiseClientEvent('Initialize');

		/* OK 10/21/2009 23330 - TabIndex of data grid always set to 0*/
		if (this._get_clientOnlyValue("ti") >= 0)					
			this._element.tabIndex = this._get_clientOnlyValue("ti");		

		this.__handleClientEvents();

		this.__handleOnSelectstart(); // this has to go last since we don't want to cancel somebody's mousedown
		/* NOTE: DO NOT DELETE. VS 10/14/2009 grid._marginTop can be set by VirtualScrolling and it is used by Activation and other behaviors */
		this._marginTop = 0;
	},
	_createBehaviorObject: function(objName, i, objProps, control, parentCollection)
	{
		/// <summary>
		/// Gets the child behavior collection.
		/// </summary>
		return new $IG[objName]((objName + i), objProps, control, parentCollection);
	},
	__handleClientEvents: function()
	{
		this._onKeyDownHandler = Function.createDelegate(this, this._onKeyDown);
		$addHandler(this._element, 'keydown', this._onKeyDownHandler);

		this._onKeyPressHandler = Function.createDelegate(this, this._onKeyPress);
		$addHandler(this._element, 'keypress', this._onKeyPressHandler);

		this._onKeyUpHandler = Function.createDelegate(this, this._onKeyUp);
		$addHandler(this._element, 'keyup', this._onKeyUpHandler);

		if (this._clientEvents["MouseOver"])
		{
			this._onMouseOverHandler = Function.createDelegate(this, this._onMouseOver);
			$addHandler(this._element, 'mouseover', this._onMouseOverHandler);
		}

		if (this._clientEvents["MouseOut"])
		{
			this._onMouseOutHandler = Function.createDelegate(this, this._onMouseOut);
			$addHandler(this._element, 'mouseout', this._onMouseOutHandler);
		}

		if (this._clientEvents["MouseMove"])
		{
			this._onMouseMoveHandler = Function.createDelegate(this, this._onMouseMove);
			$addHandler(this._element, 'mousemove', this._onMouseMoveHandler);
		}

		if (this._clientEvents["MouseDown"])
		{
			this._onMouseDownHandler = Function.createDelegate(this, this._onMouseDown);
			$addHandler(this._element, 'mousedown', this._onMouseDownHandler);
		}

		if (this._clientEvents["MouseUp"])
		{
			this._onMouseUpHandler = Function.createDelegate(this, this._onMouseUp);
			$addHandler(this._element, 'mouseup', this._onMouseUpHandler);
		}

		if (this._clientEvents["ContextMenu"])
		{
			this._onContextMenuHandler = Function.createDelegate(this, this._onContextMenu);
			$addHandler(this._element, 'contextmenu', this._onContextMenuHandler);
		}

		if (this._clientEvents["Click"])
		{
			this._onClickHandler = Function.createDelegate(this, this._onClick);
			$addHandler(this._element, 'click', this._onClickHandler);
		}

		if (this._clientEvents["DoubleClick"])
		{
			this._onDblClickHandler = Function.createDelegate(this, this._onDblClick);
			$addHandler(this._element, 'dblclick', this._onDblClickHandler);
		}
	},

	_onKeyDown: function(event)
	{
		var eventArgs = new $IG.BrowserEventArgs(event);
		if (this._clientEvents["KeyDown"])
			this._raiseSenderClientEventStart(this, this._clientEvents["KeyDown"], eventArgs);
		if (eventArgs.get_cancel() || this._gridUtil._fireEvent(this, "KeyDown", event))
		{
			$util.cancelEvent(event);
			if ($util.IsOpera)
				this._cancelKeyDownOpera = true;
			return;
		}
		return;
		/*var actBeh = this.get_behaviors().getBehaviorByName('Activation');
		if (actBeh && actBeh.get_activeCell())
		return;
		var editBeh = this.get_behaviors().getBehaviorFromInterface($IG.IEditingBehavior);
		if (editBeh)
		editBeh = editBeh.get_behaviors();
		editBeh = (editBeh && editBeh.get_cellEditing) ? editBeh.get_cellEditing() : null;
		if (editBeh && editBeh.get_cellInEditMode())
		return;*/
		var key = event.keyCode;
		if (key == 39 || key == 37)/*right/left*/
		{
			$util.cancelEvent(event);
			return;
		}
		var top = this._container.scrollTop;
		var height = this._container.offsetHeight - 20, max = this._vScrBar ? this._vScrBar.scrollHeight : 0;
		if (height + 21 > max)
			return;
		if (key == 33)/*pageUp*/
			top -= height;
		else if (key == 34)/*pageDown*/
			top += height;
		else if (key == 36)/*home*/
			top = 0;
		else if (key == 35)/*end*/
			top = max;
		else if (key == 38)/*up*/
			top -= 20;
		else if (key == 40)/*down*/
			top += 20;
		else
			return;
		$util.cancelEvent(event);
		this._container.scrollTop = (top < 0) ? 0 : top;
	},
	_onKeyPress: function(event)
	{
		if (this._cancelKeyDownOpera)
		{
			$util.cancelEvent(event);
			this._cancelKeyDownOpera = false;
			return;
		}
		var eventArgs = new $IG.BrowserEventArgs(event);
		if (this._clientEvents["KeyPress"])
			this._raiseSenderClientEventStart(this, this._clientEvents["KeyPress"], eventArgs);
		if (eventArgs.get_cancel() || this._gridUtil._fireEvent(this, "KeyPress", event))
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onKeyUp: function(event)
	{
		var eventArgs = new $IG.BrowserEventArgs(event);
		if (this._clientEvents["KeyUp"])
			this._raiseSenderClientEventStart(this, this._clientEvents["KeyUp"], eventArgs);
		if (eventArgs.get_cancel() || this._gridUtil._fireEvent(this, "KeyUp", event))
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onMouseOver: function(event)
	{
		var eventArgs = new $IG.ItemEventArgs(event, this);

		this._raiseSenderClientEventStart(this, this._clientEvents["MouseOver"], eventArgs);

		if (eventArgs.get_cancel()/* AK not raising internal event since this handler is used only when the evnt is handled externally*/)
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onMouseOut: function(event)
	{
		var eventArgs = new $IG.ItemEventArgs(event, this);

		this._raiseSenderClientEventStart(this, this._clientEvents["MouseOut"], eventArgs);

		if (eventArgs.get_cancel()/* AK not raising internal event since this handler is used only when the evnt is handled externally*/)
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onMouseMove: function(event)
	{
		var eventArgs = new $IG.ItemEventArgs(event, this);

		this._raiseSenderClientEventStart(this, this._clientEvents["MouseMove"], eventArgs);

		if (eventArgs.get_cancel()/* AK not raising internal event since this handler is used only when the evnt is handled externally*/)
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onMouseDown: function(event)
	{
		var eventArgs = new $IG.ItemEventArgs(event, this);

		this._raiseSenderClientEventStart(this, this._clientEvents["MouseDown"], eventArgs);

		if (eventArgs.get_cancel()/* AK not raising internal event since this handler is used only when the evnt is handled externally*/)
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onMouseUp: function(event)
	{
		var eventArgs = new $IG.ItemEventArgs(event, this);

		this._raiseSenderClientEventStart(this, this._clientEvents["MouseUp"], eventArgs);

		if (eventArgs.get_cancel()/* AK not raising internal event since this handler is used only when the evnt is handled externally*/)
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onContextMenu: function(event)
	{
		var eventArgs = new $IG.ItemEventArgs(event, this);

		this._raiseSenderClientEventStart(this, this._clientEvents["ContextMenu"], eventArgs);

		if (eventArgs.get_cancel()/* AK not raising internal event since this handler is used only when the evnt is handled externally*/)
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onClick: function(event)
	{
		var eventArgs = new $IG.ItemEventArgs(event, this);

		this._raiseSenderClientEventStart(this, this._clientEvents["Click"], eventArgs);

		if (eventArgs.get_cancel()/* AK not raising internal event since this handler is used only when the evnt is handled externally*/)
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_onDblClick: function(event)
	{
		var eventArgs = new $IG.ItemEventArgs(event, this);

		this._raiseSenderClientEventStart(this, this._clientEvents["DoubleClick"], eventArgs);

		if (eventArgs.get_cancel()/* AK not raising internal event since this handler is used only when the evnt is handled externally*/)
		{
			$util.cancelEvent(event);
			return;
		}
	},
	_adjustGridLayout: function()
	{
		if (this._element.offsetHeight > 0)
		{
			var startHeight = null;
			if (!this._oncePainted)
			{
				startHeight = this._element.clientHeight;
				if (this._elements.outerTbl)
					this._elements.outerTbl.style.display = '';
				this._oncePainted = true;
			}
			if (this._adjustTimerId)
			{
				clearInterval(this._adjustTimerId);
				this._adjustTimerId = null;
			}
			this._gridUtil._fireEvent(this, "InitializingLayout");
			/* VS 10/01/2008: this._elements.vsb[1].style.display='' used by _onResize,_adjustTable */
			/* That action can reset offsetWidth of vsb[1] <table> and that will affect this._container.firstChild.offsetWidth. */
			/* I saw that when VirtualScrolling was used, grid was scrolled to the middle and full postback was triggered. */
			/* I can not explain different behavior compare to state without vertical scroll: generated htmls were exactly the same. */
			/* So, save value of this._container.firstChild.offsetWidth before call to _onResize */
			/* VS 10/01/2008 6:30 PM: After other changes in grid in the middle of this fix, there is also another breaking action happened. */
			/* When this._gridUtil._fireEvent(this, "HorizontalScrollBarWidthInit", this._hScrBar) is called by _initVScrBar */
			/* then this._container.firstChild.offsetWidth is reset to full width of browser window (similar side effect as for vsb[1].style.display=''). */
			/* It means that tblWidth should be calculated before _onResize and before _initVScrBar. */
			var tblWidth = (this._elements.dataTbl) ? this._elements.dataTbl.offsetWidth : -1;

			this._initializeScrollbar();
			this._onResize({ "clientHeight": startHeight ? startHeight : this._element.clientHeight }, true);

			if (this._isWidthEmpty && tblWidth > 1)
			{
				var dataTblHeight = this._elements.dataTbl.offsetHeight;
				this._element.style.width = (tblWidth + (this._vScrBar ? this._vScrBar.offsetWidth : 0)) + "px";
				this._gridUtil._fireEvent(this, "GridWidthChanged", this._element.style.width);
				this.__setHScrBarVisibility();
				/* OK 10/20/2009 23987 - IE8 is weired setting the width above changes the offsetHeight
				of the dataTable so have to re-adjust it here */
				if ($util.IsIE8 && dataTblHeight != this._elements.dataTbl.offsetHeight)
				{
					var elementStyleHeight = $util.getPropFromCss(this._element, "height");
					var dtaHeight = this._elements.dataTbl.offsetHeight;
					if (dtaHeight > 0 && (elementStyleHeight == "" || elementStyleHeight == "auto"))
						this._container.style.height = dtaHeight + "px";

				}
			}
			//this._element.style.width = this._element.firstChild.offsetWidth + "px";

			/* OK 10/14/2008 8854 - if the data table resizes because of user interaction (such as applying styles to an active cell)
			we'll have to resize the whole grid */
			if (this._elements.dataTbl)
				this._notifyBehaviorTData = new $IG.NotifySizeChangedBehavior(this._elements.dataTbl, Function.createDelegate(this, this._onDataTblResize));

			this._notifyBehavior = new $IG.NotifySizeChangedBehavior(this._element, Function.createDelegate(this, this._onResize), null, true);

			/* OK 5/10/2009 17295 - IE8 does not remember scroll position after the grid is hidden (ie. if a webpanel is collapsed)*/
			if ($util.IsIEStandards)
				this._notifyBehaviorZeroDimen = new $IG.NotifySizeChangedFromZeroBehavior(this._element, Function.createDelegate(this, this._restoreScroll));

			this._gridUtil._fireEvent(this, "InitializedLayout");
		}
		else
		{
			if (this._adjustTimerId == null)
				this._adjustTimerId = setInterval(Function.createDelegate(this, this._adjustGridLayout), 100);
		}
	},

	_restoreScroll: function()/* OK 5/10/2009 17295 - IE8, Chrome, Safari do not remember scroll position after the grid is hidden (ie. if a webpanel is collapsed)*/
	{
		if (this._hScrBar && this._hScrBar.scrollLeft != this.get_scrollLeft())
		{
			this._ignoreCScroll = true;
			this._hScrBar.scrollLeft = this.get_scrollLeft();
			delete this._ignoreCScroll;
		}

		if (this._vScrBar && this._vScrBar.scrollTop != this.get_scrollTop())
		{
			this._ignoreCScroll = true;
			this._vScrBar.scrollTop = this.get_scrollTop();
			delete this._ignoreCScroll;
		}
	},

	_onResize: function(e, init)
	{
		/* OK 5/10/2009 17295 - IE8, Chrome, Safari do not remember scroll position after the grid is hidden (ie. if a webpanel is collapsed)*/
		if (!init)
			this._restoreScroll();

		var height = e.clientHeight;
		this._adjustTable();

		/* OK 10/10/2008 8794 - the captions need to be aligned before we initialize the scrollbars 
		so the header and footer scrollLeft can take effect.*/
		this.alignCaptions();

		var elementStyle = $util.getRuntimeStyle(this._element);
		//if (this._element.style.height == "" || this._element.style.height == "auto")
		if (elementStyle.height == "" || elementStyle.height == "auto")
		{
			/* The height of the header and footer may have changed based on how the captions were aligned 
			if so we need to determine what the new height should be */
			height = this._element.clientHeight;
		}

		/* OK 10/10/2008 8858 - we need to adjust the height of the vertical cross bar intersection rows
		to what the height of the header and footer rows have been rendered to*/
		/*if (this._vScrBar)
		{
		if (this._header && this._header.childNodes.length == 2)
		this._alignVScrIntersection(this._header, "headerContent");

			if (this._footer && this._footer.childNodes.length == 2)
		this._alignVScrIntersection(this._footer, "footerContent");
		}*/

		if (this._elements.beforeContent)
			height -= this._elements.beforeContent.offsetHeight;
		if (this._elements.afterContent)
			height -= this._elements.afterContent.offsetHeight;

		var hscrVis = (this._hScrBar && this._elements.hScrHeight.style.display != "none");
		if (height > 0 && this._vScrBar)
			this._vScrBar.style.height = height - (hscrVis ? this._scrollBarWidth : 0) + "px";

		var elementStyleHeight = $util.getPropFromCss(this._element, "height");
		if (this._elements.dataTbl.offsetHeight > 0 && (elementStyleHeight == "" || elementStyleHeight == "auto"))
		{
			var dtaHeight = this._elements.dataTbl.offsetHeight;
			//var hscrVis = (this._hScrBar && this._elements.hScrHeight.style.display != "none");
			this._container.style.height = dtaHeight /*- (hscrVis ? this._scrollBarWidth : 0)*/ + "px";
		}
		else
		{
			if (this._headingArea)
				height -= this._headingArea.offsetHeight;
			if (this._footingArea)
				height -= this._footingArea.offsetHeight;

			if (height > 0)
				this._container.style.height = height - (hscrVis ? this._scrollBarWidth : 0) + "px";
		}

		this._initVScrBar();
		this._initHScrBar();


		if (!init)
			this._gridUtil._fireEvent(this, "Resize");
	},

	_onDataTblResize: function(e, timer)
	{
		/* OK 10/14/2008 8854 - if the data table resizes because of user interaction (such as applying styles to an active cell)
		and there was not width set on the grid originally we need to let the outter grid DIV
		resize, hence setting the width to 100% temporarely to allow the resize */
		if (this._isWidthEmpty)
		{
			this._element.style.width = "100%";
			this._gridUtil._fireEvent(this, "GridWidthChanged", this._element.style.width);
		}

		var height = e.clientHeight;
		this._adjustTable();

		/* OK 10/10/2008 8794 - the captions need to be aligned before we initialize the scrollbars 
		so the header and footer scrollLeft can take effect.*/
		this.alignCaptions();


		/* OK 10/10/2008 8858 - we need to adjust the height of the vertical cross bar intersection rows
		to what the height of the header and footer rows have been rendered to*/
		/*if (this._vScrBar)
		{
		if (this._header && this._header.childNodes.length == 2)
		this._alignVScrIntersection(this._header, "headerContent");

			if (this._footer && this._footer.childNodes.length == 2)
		this._alignVScrIntersection(this._footer, "footerContent");
		}*/

		/* OK 10/14/2008 8854 - if the data table resizes because of user interaction (such as applying styles to an active cell)
		since we are setting the size on the outter DIV during initialize no matter if the width
		was set at design time, we'll alway get the change for a height here, but since the grid should
		be allowed to grow in width, we should not accept the height change here but grow in width instead */
		/* ***********************************************
		
		OK 7/08/2009 - FireFox is currently broken when you get getRuntimeStyle, in this case if the height
		is set to auto, it starts returning the clientHeight, which breaks this whole logic. So I am going to 
		use getPropFromCss for now.
		
		var elementStyle = $util.getRuntimeStyle(this._element);		
		if (this._elements.dataTbl.offsetHeight > 0 && (elementStyle.height == "" || elementStyle.height == "auto"))
		*********************************************** */
		var elementStyleHeight = $util.getPropFromCss(this._element, "height");
		if (this._elements.dataTbl.offsetHeight > 0 && (elementStyleHeight == "" || elementStyleHeight == "auto"))
		{
			var dtaHeight = this._elements.dataTbl.offsetHeight;
			var hscrVis = (this._hScrBar && this._elements.hScrHeight.style.display != "none");
			this._container.style.height = dtaHeight /*- (hscrVis ? this._scrollBarWidth : 0)*/ + "px";

			if (this._headingArea)
				dtaHeight += this._headingArea.offsetHeight;
			if (this._footingArea)
				dtaHeight += this._footingArea.offsetHeight;

			if (this._vScrBar)
				this._vScrBar.style.height = dtaHeight - (hscrVis ? this._scrollBarWidth : 0) + "px";
		}

		this._initVScrBar();
		this._initHScrBar();

		/* OK 10/14/2008 8854 - now that the grid has resized we need to put the new width on the outer
		DIV of the control (we previously set it to 100% in the begining of the method). */
		var tblWidth = this._elements.dataTbl.offsetWidth;
		if (this._isWidthEmpty && tblWidth > 1)
		{
			this._element.style.width = (tblWidth + (this._vScrBar ? this._vScrBar.offsetWidth : 0)) + "px";
			this._gridUtil._fireEvent(this, "GridWidthChanged", this._element.style.width);
		}

	},

	/* OK 10/10/2008 8858 - adjust the height of the vertical cross bar intersection rows
	to what the height of the header and footer rows have been rendered to */
	/*_alignVScrIntersection: function(captionArea, contentName)
	{
	var content = this._elements[contentName];
	var contentRows = content ? $util.getRows(content) : null;
	var intersectionRows = (captionArea.childNodes[1].childNodes.length > 0) ? $util.getRows(captionArea.childNodes[1].childNodes[0]) : null;
	if (contentRows && intersectionRows && contentRows.length && intersectionRows.length)
	{
	for (var i = 0; i < contentRows.length && i < intersectionRows.length; i++)
	{
	var cell = intersectionRows[i].cells[0];
	if (cell)
	{
	cell.style.height = contentRows[i].offsetHeight + "px";
	var adjustment = (contentRows[i].offsetHeight + (contentRows[i].offsetHeight - cell.offsetHeight));
	if (adjustment > 0)
	cell.style.height = adjustment + "px";

	// FireFox2 needs to be made to refresh the table cell
	if ($util.IsFireFox2)
	{
	var cellHeight = cell.style.height;
	cell.style.height = "0px";
	setTimeout($util.createDelegate(this, this._refreshCellHeight, [cell, cellHeight]), 0);
	}
	}
	}
	}
	},*/

	_refreshCellHeight: function(cell, height)
	{
		cell.style.height = height;
	},

	_setupCollections: function()
	{
		//
		this._columns = this._collectionsManager.register_collection(0, $IG.ColumnCollection);
		this._editorProviders = this._collectionsManager.register_collection(1, $IG.ObjectCollection);
		var collectionItems = this._collectionsManager._collections[1];
		for (var i in collectionItems)
		{
			var editorProvider = collectionItems[i];
			this._editorProviders._addObject(eval(editorProvider[1]["c"]["coc"]), document.getElementById(this._id + "_" + editorProvider[0][0]), i);
		}
		/*var epp = this._element.previousSibling;
		if (epp && typeof (epp.tagName) != "undefined" && epp.tagName == "DIV" && epp.id.indexOf("_eppool") >= 0 && epp._editorProviders)
		{
		var epps = epp._editorProviders;
		for (var eppItem in epps._items)
		{
		this._editorProviders
		}
		epp._editorProviders = null;
		}*/

	},

	_initializeMargins: function()
	{
		this._headingArea = this._elements["headingArea"];
		this._header = this._elements["header"];
		if (this._header)
			this._headerContainer = this._header.firstChild.firstChild;
		this._footingArea = this._elements["footingArea"];
		this._footer = this._elements["footer"];
		if (this._footer)
			this._footerContainer = this._footer.firstChild.firstChild;
		this._columnHeaderRow = this._elements["columnHeaderRow"];
	},

	_get_marginHeight: function()
	{
		if (typeof (this._marginHeight) == "undefined" || !this._marginHeight)
		{
			this._marginHeight = 0;
			if (this._headingArea)
				this._marginHeight += this._headingArea.offsetHeight;
			if (this._footingArea)
				this._marginHeight += this._headingArea.offsetHeight;
			/*if (this._hScrBar && this._elements.hScrHeight.style.display != "none")
			this._marginHeight += this._elements.hScrHeight.offsetHeight;*/
		}
		return this._marginHeight;
	},

	_initializeScrollbar: function()
	{
		// init scrollbars
		/*if(this.get_scrollbarType()==0)
		{*/
		var vsbElem = this._elements["vsb"];
		if (vsbElem)
		{
			for (var i = 0; i < vsbElem.length; i++)
			{
				if (vsbElem[i].getAttribute("sub"))
					this["_" + vsbElem[i].getAttribute("sub")] = vsbElem[i];
			}
		}
		this._vScrBar = this._elements["vScrBar"];
		this._hScrBar = this._elements["hScrBar"];

		//this._vScrWidth = this._elements["vScrWidth"];
		//this._hScrHeight = this._elements["hScrHeight"];

		if ((this._vScrBar || this._hScrBar) /*&& Sys.Browser.agent != Sys.Browser.Safari*/)
		{
			this._scrollBarWidth = this._determineScrollbarWidth();

			if (this._vScrBar)
			{
				this._vScrBar.style.width = this._scrollBarWidth + 1 + "px";
				if (this._vScrWidth)
					this._vScrWidth.style.width = this._vScrBar.style.width;
			}
			if (this._hScrBar)
			{
				/*
				DK 25 Sept 2008
				Bug 8128 : Slow horizontal scrolling in WebDataGrid
				For some odd reason, this was the line that caused the problem.  In the verical
				we added 
				+1 but here we did not do it for horizontal.  I think setting the height smaller then the
				original was causing the problem
				*/
				this._hScrBar.style.height = this._scrollBarWidth + 1 + "px";
				if (this._hScrHeight)
					this._hScrHeight.style.height = this._hScrBar.style.height;
			}
		}

		if (this._vScrBar)
		{
			this._initVScrBar();
			if (this._enabled)
				$addHandler(this._vScrBar, "scroll", Function.createDelegate(this, this._onVScrollHandler));
			if (Sys.Browser.agent == Sys.Browser.Firefox)
				$addHandler(this._container, "DOMMouseScroll", Function.createDelegate(this, this._onMouseWheel));
			else
				$addHandler(this._container, "mousewheel", Function.createDelegate(this, this._onMouseWheel));
		}
		if (this._hScrBar)
		{
			this._initHScrBar();
			if (this._enabled)
				$addHandler(this._hScrBar, "scroll", Function.createDelegate(this, this._onHScrollHandler));
		}

		if ((this._vScrBar || this._hScrBar) && this._enabled)
			$addHandler(this._container, "scroll", Function.createDelegate(this, this._onCScrollHandler));
		/*}
		else
		{
		this._vScrBarObj=$find(this.get_id()+"_vsb");
		if(this._vScrBarObj)
		{
		this._vScrBar=this._vScrBarObj._element;
		this._elements["vScrWidth"].style.width = this._vScrBar.offsetWidth + "px";
		this._vScrBarObj.addClientEventHandler("BarMoved", Function.createDelegate(this, this._onVScrollHandler));
		}
		this._hScrBarObj=$find(this.get_id()+"_hsb");
		if(this._hScrBarObj)
		{
		this._hScrBar=this._vScrBarObj._element;
		this._elements["hScrHeight"].style.height = this._hScrBar.offsetWidth + "px";
		this._hScrBarObj.addClientEventHandler("BarMoved", Function.createDelegate(this, this._onHScrollHandler));
		}
		}*/
	},

	_initVScrBar: function()
	{
		if (this._vScrBar)
		{
			if (!this._gridUtil._fireEvent(this, "VerticalScrollBarHeightInit", this._vScrBar))
			{
				/* OK 8854 10/17/08 - for some reason IE doesn't refresah the scrollHeight of the
				container until after scrollTop is set, therefore we need to set it twice */
				/* OK 18491 6/17/09 - Vertical scroll position not kept in DataGrid over postback in IE 8*/
				if ($util.IsIE && !$util.IsIEStandards)
					this._container.scrollTop = this._vScrBar.scrollTop = this.get_scrollTop();
				var show = this._container.scrollHeight > this._container.offsetHeight;
				var shown = this._elements.vsb[0].style.display == "";
				if (show ? !shown : shown)
				{
					for (var i = 0; i < this._elements.vsb.length; i++)
						this._elements.vsb[i].style.display = (show ? "" : "none");
					/* OK 16234 3/31/2008 - once the vertical scrolbar shows up there is less space available for the header
					and we have to resize again ;-( */
					this._onResize({ "clientHeight": this._element.clientHeight }, false);
				}
				/* OK 9501, 9550 10/27/08 - adjustment needs to occur before we set the scrol height */
				if (this._header && this._header.childNodes.length == 2)
					this._alignVScrIntersection(this._header, "headerContent");

				if (this._footer && this._footer.childNodes.length == 2)
					this._alignVScrIntersection(this._footer, "footerContent");

				/* VS 11/25/2008. Bug 10811. (Firefox2)+(grid stretched to container by %)=(vert scrollbar outside of bounds of control==not visible) */
				/* :shift scroll bar DIV inside of bounds of control */
				var td = this._vScrBar.parentNode, width = this._vScrBar.offsetWidth;
				if (width > 5 && td.offsetWidth < 5)
					this._vScrBar.style.marginLeft = -width + 'px';

				this._vScrBar.firstChild.style.height = (show ? this._vScrBar.offsetHeight + this._container.scrollHeight - this._container.offsetHeight + "px" : "");
				this._container.scrollTop = this._vScrBar.scrollTop = this.get_scrollTop();
			}
		}
	},

	_initHScrBar: function()
	{
		if (this._hScrBar)
		{
			if (!this._gridUtil._fireEvent(this, "HorizontalScrollBarWidthInit", this._hScrBar))
			{
				/*OK 10/9/2008 8795 - if there are no rows we'll have to use the header or the footer to determine the scroll width*/
				var scrollContainer;
				if (this._rows.get_length() < 1 && (this._elements["headerContent"] || this._elements["footerContent"]))
					scrollContainer = this._elements["headerContent"] ? this._elements["headerContent"] : this._elements["footerContent"];
				else
					scrollContainer = this._container;
				/* OK 8854 10/17/08 - for some reason IE doesn't refresah the scrollWidth of the
				container until after scrollLeft is set, therefore we need to set it twice */
				if ($util.IsIE)
					scrollContainer.scrollLeft = this._hScrBar.scrollLeft = this.get_scrollLeft();
				this._hScrBar.firstChild.style.width = scrollContainer.scrollWidth + "px";
				scrollContainer.scrollLeft = this._hScrBar.scrollLeft = this.get_scrollLeft();
				/* OK 8854 10/17/08 - just setting the scrollLeft of the container doesn't always cause the onScroll event to fire
				calling the handler here so the Tada table can be re-aligned with the header */
				this._onHScrollHandler();
			}
		}
	},

	_determineScrollbarWidth: function()
	{
		/*An exotic way to get the scrollbar width*/
		var testDiv = document.createElement("DIV");
		document.body.insertBefore(testDiv, document.body.firstChild);
		testDiv.style.visibility = "hidden";
		testDiv.style.position = "absolute";
		testDiv.style.overflow = "auto";
		testDiv.style.width = "100px";
		testDiv.style.height = "100px";
		var testChildDiv = document.createElement("DIV");
		testDiv.appendChild(testChildDiv);
		testChildDiv.style.width = "200px";
		testChildDiv.style.height = "200px";

		var wdth = testDiv.offsetWidth - testDiv.clientWidth;

		/*D.M. Bug 9267 - We can only call removeNode() in IE.*/
		testDiv.removeChild(testChildDiv);
		if ($util.IsIE)
			testChildDiv.removeNode();
		testChildDiv = null;
		document.body.removeChild(testDiv);
		if ($util.IsIE)
			testDiv.removeNode();
		testDiv = null;
		return wdth;
	},

	_onHScrollHandler: function(evnt)
	{
		if (this._gridUtil._fireEvent(this, "ScrollLeftChange"))
			return;
		this._ignoreCScroll = true;
		var scrLeft = this._hScrBar.offsetHeight > 0 ? this._hScrBar.scrollLeft : this.get_scrollLeft();
		this._container.scrollLeft = scrLeft;
		var margin = "-" + scrLeft + "px";
		var div = this._headerContainer;
		if (div)
		{
			div.firstChild.style.marginLeft = margin;
			/* VS 10/08/2009 Bug 23265. addRow area is shifted to left */
			if (div.scrollLeft != 0)
				div.scrollLeft = 0;
		}
		if (div = this._footerContainer)
		{
			div.firstChild.style.marginLeft = margin;
			/* VS 10/08/2009 Bug 23265. addRow area is shifted to left */
			if (div.scrollLeft != 0)
				div.scrollLeft = 0;
		}
		if (div = this._poolHolder)
		{
			div.style.marginLeft = margin;
			/* VS 10/08/2009 Bug 23265. addRow area is shifted to left */
			if (div.scrollLeft != 0)
				div.scrollLeft = 0;
		}
		/*OK 10/10/2008 8794 - need to set the scrollLeft so here so it can be remembered on postback or callback */
		if (this._hScrBar.offsetHeight > 0)
			this.set_scrollLeft(scrLeft);
		delete this._ignoreCScroll;
	},

	_onVScrollHandler: function(evnt)
	{
		if (this._gridUtil._fireEvent(this, "ScrollTopChange"))
			return;
		this.set_scrollTop(this._vScrBar.scrollTop);
		this._adjustScrollTop();
	},


	_adjustScrollTop: function()
	{
		this._ignoreCScroll = true;
		this._container.scrollTop = this._vScrBar.scrollTop;
		delete this._ignoreCScroll;
	},

	_onMouseWheel: function(evnt)
	{
		var evt = evnt ? evnt.rawEvent : null;
		if (!evt)
			return;
		if (this._get_isAjaxCallInProgress())
			return;
		if (this._enabled)
		{
			var delta = evt.wheelDelta;
			if (delta)
				delta /= -3;
			else if (delta = evt.detail)
				delta *= 13;
			if (!delta)
				return;
			this._container.scrollTop += delta;
		}
		$util.cancelEvent(evnt);
		this._gridUtil._fireEvent(this, "MouseWheel");
	},

	_onCScrollHandler: function(evnt)
	{
		var util = this._gridUtil;
		if (!util || this._ignoreCScroll)
			return false;
		if (this._vScrBar)
			this._vScrBar.scrollTop = this._container.scrollTop;
		if (this._hScrBar)
		{
			/* VS 09/24/2009. Bug 22547. Get around bugs in IE6/7 which may set internally focus to a parent DIV */
			/* when focus was requested for cell-TD. In that situation IE scrolls grid-container to 0/left */
			/* and that method adjusted _hScrBar for that. */
			/* Note: values of _noScrollTime, _noScrollLeft were set in GridUtility.scrollCellIntoViewIE() */
			var time = util._noScrollTime, noLeft = util._noScrollLeft, left = this._container.scrollLeft;
			if (time && time + 1000 > (new Date()).getTime()) if ((noLeft = Math.max(0, noLeft)) != left)
			/* set scroll of container back to its location calculated by scrollCellIntoViewIE */
				this._container.scrollLeft = left = noLeft;
			if (this._hScrBar.scrollLeft == left)
				return;
			/* OK 5/11/2009 17398 - Scrolling vertically in grid with Column Fixing on resets horizontal scroll position*/
			var evntArgs = { event: evnt, containerScrollLeft: left };
			if (util._fireEvent(this, "CScrollLeftChange", evntArgs))
				return;
			this._hScrBar.scrollLeft = evntArgs.containerScrollLeft;
		}
	},

	__handleOnSelectstart: function()
	{
		var selectStart = ($util.IsIE ? "selectstart" : "mousedown");
		$addHandler(this._element, selectStart, Function.createDelegate(this, this._onSelectstartContainer));
		if (this._columnHeaderRow)
		{
			if (this._columnHeaderRow.length)
			{
				for (var i = 0; i < this._columnHeaderRow.length; i++)
					$addHandler(this._columnHeaderRow[i], selectStart, Function.createDelegate(this, this._onSelectstartHeader));
			}
			else
				$addHandler(this._columnHeaderRow, selectStart, Function.createDelegate(this, this._onSelectstartHeader));
		}
	},

	__removeOnSelectstart: function()
	{
		/*
		DK 24 Oct 2008
		Bug 9544 : JS error when you close IE browser when WebCalendar is being displayed as an editor
		Check that element is not null before clearing handlers on it.
		*/
		if (this._element)
			$clearHandlers(this._element);
		if (this._columnHeaderRow)
		{
			if (this._columnHeaderRow.length)
			{
				for (var i = 0; i < this._columnHeaderRow.length; i++)
					$clearHandlers(this._columnHeaderRow[i]);
			}
			else
				$clearHandlers(this._columnHeaderRow);
		}
	},

	_onSelectstartContainer: function(evnt)
	{
		this._gridUtil._fireEvent(this, "SelectStartContainer", evnt);
	},

	_onSelectstartHeader: function(evnt)
	{
		$util.cancelEvent(evnt);
	},

	_createItem: function(element, adr, itemCount)
	{
		//this._itemCollection.addObject($IG.GridRow, element, adr);
	},

	_rows: null,

	get_rows: function()
	{
		///<summary>
		///Returns the grid's rows collection.
		///</summary>
		return this._rows;
	},

	//////////////////////// AUX ROWS /////////////////////////////

	_get_auxRows: function(alignment)
	{
		if (alignment == $IG.GridAuxRows.Top)
			return this._auxRowsTop;
		if (alignment == $IG.GridAuxRows.Bottom)
			return this._auxRowsBottom;
		return this._auxRowsTop.concat(this._auxRowsBottom);
	},

	_isAuxRow: function(row, alignment)
	{
		if (typeof (alignment) == "undefined")
			return this._isAuxRow(row, $IG.GridAuxRows.Top) || this._isAuxRow(row, $IG.GridAuxRows.Bottom);

		var auxRows = this._get_auxRows(alignment);
		for (var i = 0; i < auxRows.length; i++)
			if (auxRows[i] == row)
			return true;
		return false;
	},

	_get_auxRowIndex: function(row, alignment)
	{
		if (typeof (alignment) == "undefined")
			throw "Must indicate alignment of the aux rows";
		var auxRows = this._get_auxRows(alignment);
		for (var i = 0; i < auxRows.length; i++)
			if (auxRows[i] == row)
			return i;
		return -1;
	},

	_registerAuxRow: function(row, alignment)
	{
		if (typeof (alignment) == "undefined")
			throw "Must indicate alignment of the aux rows";
		var auxRows = this._get_auxRows(alignment);
		auxRows[auxRows.length] = row;
		row._element.setAttribute("auxRow", alignment);
		row._element.setAttribute("adr", auxRows.length - 1);
	},

	//////////////////////// END AUX ROWS /////////////////////////////

	_columns: null,

	get_columns: function()
	{
		return this._columns;
	},

	_initializeObjects: function()
	{
		var rawColumns = this._columns._manager._collections[0];
		for (var index in rawColumns)
		{
			if (!isNaN(parseInt(index)))
			{
				var column = this._columns._addObject($IG.GridColumn, null, index);
				column._parentCollection = this._columns;
			}
		}

		this._rows = new $IG.GridRowCollection(this._elements["rows"], [this._get_value($IG.WebDataGridProps.RowCount)], this);

		if (this._enabled)
		{
			// initialize behavior container
			this._initializeBehaviors(this._objectsManager._objects, this, this.get_behaviors());
			// initialize behavior collection and notify all behaviors about initializeComplete
			this.get_behaviors()._initializeBehaviors();

			this._initializeBehaviorComplete(this.get_behaviors());
		}
	},

	_initializeBehaviorComplete: function(behaviors)
	{
		for (var i = 0; i < behaviors._behaviors.length; i++)
		{
			var behavior = behaviors._behaviors[i];
			if (behavior)
			{
				behavior._initializeComplete();
				if ($IG.IGridBehaviorContainer.isInstanceOfType(behavior))
				{
					var subBehCollection = behavior.get_behaviors();
					if (subBehCollection)
						this._initializeBehaviorComplete(subBehCollection);
				}
			}
		}
	},

	_behaviors: null,
	get_behaviors: function()
	{
		///<summary>
		///Returns the grid's behavior collection.
		///All of the grid behaviors are contained by this collection.
		///</summary>
		if (this._behaviors == null)
			this._behaviors = new $IG.GridBehaviorCollection(this);
		return this._behaviors;
	},

	_saveAdditionalClientState: function()
	{
		//
		return this._actionList.get_list();
	},

	/* IE fails to handle focus/keyboard when old focus element was moved to another parent. */
	/* It means that shared/hierarchical editor cant be moved to original parent within EditorProvider.hideEditor(). */
	/* The "move" action with delay after hideEditor has other side effects (arrow keys lost). */
	/* Bug 20943 is one of those side effects. */
	/* So, original parent element of editorProvider should be restored later: on startEdit or dispose. */
	_oldParent_IEBug: function(elem)
	{
		/* elem._oldParent_IEBug is a flag to perform move */
		if (!elem || !elem._oldParent_IEBug)
			return;
		elem._oldParent_IEBug = null;
		/* _oldParent is reference to original parent html element of editor */
		var old = elem._oldParent, parent = elem.parentNode;
		if (old && old != parent) try
		{
			parent.removeChild(elem);
			old.appendChild(elem);
		}
		catch (old) { }
	},

	dispose: function()
	{
		///<summary>
		///Disposes of the grid object.
		///</summary>
		if (this._adjustTimerId)
		{
			clearInterval(this._adjustTimerId);
			this._adjustTimerId = null;
		}
		if (this._notifyBehavior)
			this._notifyBehavior.dispose();
		if (this._notifyBehaviorTData)
			this._notifyBehaviorTData.dispose();
		this.__removeOnSelectstart();
		if (this.get_element())
			$clearHandlers(this.get_element());
		if (this._container)
			$clearHandlers(this._container);
		var rows = this.get_rows();
		if (rows)
			rows.dispose();
		if (this._headingArea)
			$clearHandlers(this._headingArea);
		if (this._footingArea)
			$clearHandlers(this._footingArea);
		if (this._vScrBar)
			$clearHandlers(this._vScrBar);
		if (this._hScrBar)
			$clearHandlers(this._hScrBar);
		this._auxRowsTop = null;
		this._auxRowsBottom = null;
		this._poolHolder = null;

		if (this._container)
			$clearHandlers(this._container);
		delete this._onKeyDownHandler;
		delete this._onKeyPressHandler;
		delete this._onKeyUpHandler;
		if (this["_onMouseOverHandler"])
			delete this._onMouseOverHandler;
		if (this["_onMouseOutHandler"])
			delete this._onMouseOutHandler;
		if (this["_onMouseMoveHandler"])
			delete this._onMouseMoveHandler;
		if (this["_onMouseDownHandler"])
			delete this._onMouselickHandler;
		if (this["_onMouseUpHandler"])
			delete this._onMouseUpHandler;
		if (this["_onContextMenuHandler"])
			delete this._onContextMenuHandler;
		if (this["_onClickHandler"])
			delete this._onClickHandler;
		if (this["_onDblClickHandler"])
			delete this._onDblClickHandler;

		if (this._actionList)
			this._actionList.dispose();

		if (this._gridUtil)
			this._gridUtil.dispose();
		/* restore original parents of shared and hierarchical editor providers */
		var pool = this._editorProvidersPool;
		pool = pool ? pool.childNodes : null;
		var i = pool ? pool.length : 0;
		while (i-- > 0)
			this._oldParent_IEBug(pool[i]);
		this._editorProvidersPool = null;
		this._container = null;
		this._headingArea = null;
		this._header = null;
		this._headerContainer = null;
		this._footingArea = null;
		this._footer = null;
		this._footerContainer = null;
		this._columnHeaderRow = null;
		this._vScrBar = null;
		this._hScrBar = null;
		this._vScrWidth = null;
		this._hScrHeight = null;

		if (this._behaviors)
		{
			this._behaviors.dispose();
			this._behaviors = null;
		}

		var ele = this._element;
		$IG.WebDataGrid.callBaseMethod(this, "dispose");

		/*#if DEBUG*/
		//this.__detectAttachedHandlers(ele);
		//this.__detectAttachedElements(this);
		//this.__detectCircularRefs(this, "grid", new Array());
		//this.__detectDOMRefs(ele, ele.tagName + " " + ele.id);
		//this.__detectInternalEventHandlers();
		/*#endif*/
	},

	/*#if DEBUG
	__detectAttachedHandlers: function(ele)
	{
	if (ele._events)
	{
	for (var evt in ele._events)
	if (ele._events[evt].length)
	debugger;
	}
	if (ele._object) debugger;
	if (ele.control) debugger;

	for (var i = 0; i < ele.childNodes.length; i++)
	{
	this.__detectAttachedHandlers(ele.childNodes[i]);
	}
	},

	__detectAttachedElements: function(obj)
	{
	if (obj.__processed__)
	return;
	obj.__processed__ = true;
	for (var p in obj)
	{
	if (typeof (obj[p]) == "object")
	{
	if (typeof (obj[p].tagName) != "undefined")
	delete obj[p];
	else
	this.__detectAttachedElements(obj[p]);
	}
	}
	},

	__detectCircularRefs: function(obj, name, stack)
	{
	if (!obj)
	return;
	if (typeof (obj.tagName) != "undefined")
	{
	for (var p in obj)
	{
	if (typeof (obj[p]) == "object" && obj[p] && !this.__isExcludedProperty(p))
	{
	var stackTrace = this.__checkStack(obj[p], stack);
	if (stackTrace)
	{
	alert("An object is causing circular reference: " + p + "\r\n" + stackTrace + name);
	debugger;
	return;
	}
	}
	}
	return;
	}
	for (var p in obj)
	{
	if (typeof (obj[p]) == "object" && obj[p])
	{
	var stackTrace = this.__checkStack(obj[p], stack);
	if (stackTrace)
	{
	alert("An object is causing circular reference: " + p + "\r\n" + stackTrace + name);
	debugger;
	return;
	}
	stack.push({ "obj": obj, "name": name });
	this.__detectCircularRefs(obj[p], p, stack);
	stack.pop();
	}

	}
	},

	__detectCircularRefs: function(obj, name, stack)
	{
	},

	__isExcludedProperty: function(p)
	{
	var propsHtml = ["all", "attributes", "behaviorUrns", "childNodes", "children", "currentStyle",
	"document", "filters", "firstChild", "lastChild", "nextSibling", "offsetParent",
	"ownerDocument", "parentElement", "parentNode", "parentTextEdit", "previousSibling",
	"runtimeStyle", "style", "cells", "rows", "tBodies", "form"];
	var propsAjax = ["_events"];
	for (var i = 0; i < propsHtml.length; i++)
	{
	if (p == propsHtml[i])
	{
	return true;
	}
	}
	for (var i = 0; i < propsAjax.length; i++)
	{
	if (p == propsAjax[i])
	{
	return true;
	}
	}
	return false;
	},

	__checkStack: function(obj, stack)
	{
	var str = "";
	for (var i in stack)
	{
	str += stack[i].name + "\r\n";
	if (stack[i].obj === obj)
	{
	return str;
	}
	}
	return null;
	},

	__detectDOMRefs: function(e, history)
	{
	for (var p in e)
	{
	if (typeof (e[p]) == "object" && e[p] && !this.__isExcludedProperty(p))
	{
	alert("DOM reference is detected: " + p + "\r\n" + history);
	debugger;
	}
	else if (p.substr(0, 2) == "on" && e[p])
	{
	alert("Event handler is not detached: " + p + "\r\n" + history);
	debugger;
	}
	}
	if (typeof (e.attributes) != "undefined" && e.attributes)
	{
	for (var attr = 0; attr < e.attributes.length; attr++)
	{
	var v = e.attributes[attr].nodeValue;
	var name = e.attributes[attr].nodeName;
	if (v && name != "_events" && (typeof (v) != "number" && typeof (v) != "string" && typeof (v) != "boolean"))
	{
	alert("Attribute references an object: " + name + " " + attr + "\r\n" + history);
	debugger;
	}
	}
	}
	for (var i = 0; i < e.childNodes.length; i++)
	{
	this.__detectDOMRefs(e.childNodes[i], history + "\r\n" + e.childNodes[i].tagName + " " + i + " " + e.childNodes[i].id);
	}
	},

	__detectInternalEventHandlers: function()
	{
	for (var evnt in this._internaleEventListeners)
	debugger;
	},


	/*#endif*/

	alignCaptions: function()
	{
		///<summary>
		///Aligns the captions with the data columns of the grid. The method can be
		///called if you're using the grid in an unusual environment and the 
		///cells are getting misaligned from the headers.
		///</summary>
		this._adjustTable();

		if (this._header)
			this._alignStatCaption("headerContent");
		if (this._footer)
			this._alignStatCaption("footerContent");
		if (this._rows.get_length() < 1)
			this._alignFooter();
	},
	_adjustTableWidth: function()
	{
		//debugger;
		var tables = [this._elements["headerContent"], this._elements["dataTbl"], this._elements["footerContent"]];
		for (var i = 0; i < tables.length; i++)
		{
			var table = tables[i];
			if (table && table.rows.length > 0)
			{
				var tableWidth = table.style.width;
				if (tableWidth && (tableWidth + "").indexOf("px") != -1)
				{
					var row = table.rows[0];
					tableWidth = 0;
					for (var j = 0; j < row.cells.length; j++)
					{
						var cell = row.cells[j];
						if (!$util.IsIEStandards || $util.getPropFromCss(cell, "display") != "none")
							tableWidth += cell.offsetWidth;
					}
					if (tableWidth > 0)
						table.style.width = tableWidth + "px";
				}
				/* IE8 refuses to update the table width
				else if (tableWidth == "100%")
				{
				debugger;
				table.style.width = table.offsetWidth + "px";
				setTimeout($util.createDelegate(this, this._refreshTableWidth, [table, "100%"]), 0);
				}*/
			}
		}
	},
	/*_refreshTableWidth: function(table, width)
	{
	debugger;
	table.style.width = width;
	},*/
	_adjustTable: function()
	{
		this.__setHScrBarVisibility();
		if (this._elements.vsb)
		{
			var show = this._container.scrollHeight > this._container.offsetHeight;
			for (var i = 0; i < this._elements.vsb.length; i++)
				this._elements.vsb[i].style.display = (show ? "" : "none");
		}
	},
	__setHScrBarVisibility: function()
	{
		if (this._elements.hScrHeight)
		{
			/*OK 10/9/2008 8795 - if there are no rows we'll have to use the header or 
			the footer to determine if the horizontal scroll bar should be displayed */
			var scrollContainer;
			if (this._rows.get_length() < 1 && (this._elements["headerContent"] || this._elements["footerContent"]))
				scrollContainer = this._elements["headerContent"] ? this._elements["headerContent"] : this._elements["footerContent"];
			else
				scrollContainer = this._elements.dataTbl;
			if (!this._gridUtil._fireEvent(this, "ShowHorizontalScrollBar", { "scrollBar": this._elements.hScrHeight, "scrollContainer": scrollContainer, "container": this._container }))
				this._elements.hScrHeight.style.display = (scrollContainer.offsetWidth > this._container.offsetWidth ? "" : "none");
		}
	},
	_alignStatCaption: function(captionProperty)
	{
		if (this._gridUtil._fireEvent(this, "AlignStatCaption", captionProperty))
			return;
		var capElem = this._elements[captionProperty];
		if (capElem.style.tableLayout == "fixed")
			capElem.style.tableLayout = "fixed";


		if (this._elements.dataTbl)
		{
			var dataTblStyle = this._elements.dataTbl.style;
			var existingTableWidth = dataTblStyle.width;
			if (existingTableWidth && (existingTableWidth + "").indexOf("px") != -1)
			{
				capElem.style.width = dataTblStyle.width;
			}
			else if (this._isWidthEmpty && !($util.IsIE && !$util.IsIEStandards))
			{
				/* OK 5/13/2009 17368 - In grid with no column or grid width set, the column headers don't line up with cells*/
				capElem.style.tableLayout = "auto";
				capElem.style.width = this._elements.dataTbl.clientWidth + "px";
				capElem.style.tableLayout = "fixed";
			}
		}

		var row = this._rows.get_row(0);
		if (row)
		{
			var rowElem = row.get_element();
			/* OK 8854 10/21/08 - we have to make two passes and first adjust the captions which columns have width,
			and then adjust the captions whose columns that don't width set on them. This will allow the columns 
			that don't have width set on them to take up the rest of the space in the table.*/
			for (var i = 0; i < rowElem.childNodes.length; i++)
			{
				var cell = rowElem.childNodes[i];
				if (cell.style.width != "" && cell.style.width.indexOf("%") < 0 && cell.offsetWidth > 0)
				{
					/* OK 8854 10/21/08 - this is a hack, but for some reason setting the width to A and then back to
					B makes the browser adjust the offset and client width of the element appropreatly */
					var pxIndex = cell.style.width.indexOf("px");
					if (pxIndex > -1 && existingTableWidth)
					{
						var neededWidth = parseInt(cell.style.width.substring(0, pxIndex));
						if (!isNaN(neededWidth))
						{
							cell.style.width = neededWidth + 1 + "px";
							cell.style.width = neededWidth + "px";
						}
					}

					var rows = $util.getRows(capElem);
					var caption = rows && rows.length ? rows[0].childNodes[i] : null;

					if (caption)
					{
						/* OK 3/26/2009 15321 - we no longer seem to need to adjust the offsetWidth by -1 for non IE browsers */
						$util.setAbsoluteWidth(caption, cell.offsetWidth);
					}
				}
				/* OK 8854 10/21/08 - have to set the caption width to "" if there is no width set on the column
				so it will take up the left over space */
				else
				{
					var rows = $util.getRows(capElem);
					var caption = rows && rows.length ? rows[0].childNodes[i] : null;

					if (caption)
						caption.style.width = "";
				}
			}
			/* OK 8854 10/21/08 - Now adjusting the captions whose columns don't have width set on them. */
			for (var i = 0; i < rowElem.childNodes.length; i++)
			{
				var cell = rowElem.childNodes[i];
				if (cell.style.width == "" || cell.style.width.indexOf("%") > -1 && cell.offsetWidth > 0)
				{
					var rows = $util.getRows(capElem);
					var caption = rows && rows.length ? rows[0].childNodes[i] : null;

					if (caption)
					{
						/* OK 3/26/2009 15321 - we no longer seem to need to adjust the offsetWidth by -1 for non IE browsers */
						$util.setAbsoluteWidth(caption, cell.offsetWidth, this._isWidthEmpty); /* OK 5/13/2009 17368 - In grid with no column or grid width set, the column headers don't line up with cells*/
					}
				}
			}

		}
	},

	/* If there are no data rows and both the header and footer exist we need to align the footer to the 
	header, so the cells of both are equal width */
	_alignFooter: function()
	{
		if (this._gridUtil._fireEvent(this, "AlignFooter"))
			return;
		var headerRows = $util.getRows(this._elements["headerContent"]);
		var headerRow = (headerRows && headerRows.length) ? headerRows[0] : null;
		var footerRows = $util.getRows(this._elements["footerContent"]);

		if (headerRow && footerRows && footerRows.length)
		{
			for (var i = 0; i < headerRow.childNodes.length; i++)
			{
				var headerCell = headerRow.childNodes[i];
				if (headerCell.offsetWidth > 0)
				{
					var footerCell = footerRows[0].childNodes[i];
					/* OK 3/26/2009 15321 - we no longer seem to need to adjust the offsetWidth by -1 for non IE browsers */
					if (footerCell)
						$util.setAbsoluteWidth(footerCell, headerCell.offsetWidth);
				}
			}
		}
	},
	_responseComplete: function(callbackObject, responseObject, browserResponseObject)
	{
		//

		$IG.WebDataGrid.callBaseMethod(this, '_responseComplete', [callbackObject, responseObject, browserResponseObject]);

		var grid = this;
		var responseOptions = Sys.Serialization.JavaScriptSerializer.deserialize(responseObject.context[0]);

		if (responseOptions.fullRender)
		{
			/* VS 10/27/2008 Bug 9647: moved from request. */
			this._parkEditorProvidersPool();
			grid._gridUtil._fireEvent(grid, "BeforeAsyncRender");
			grid = this._renderOnAsyncResponse(responseObject.context[1], responseObject.context[2]);
		}
		else
		{
			grid._gridUtil._fireEvent(grid, "BeforeAsyncRender");
			var behaviorName = callbackObject.serverContext["behavior"];
			if (behaviorName)
			{
				var behavior = this.get_behaviors().getBehaviorByName(behaviorName);
				behavior._responseComplete(callbackObject, responseOptions);
			}
		}
		this._set_isAjaxCallInProgress(false);

		grid._raiseClientEvent("AJAXResponse", "AJAXResponse", browserResponseObject, responseOptions.gridResponse);
	},
	_responseCompleteError: function(callbackObject, browserResponseObject, timedOut)
	{
		this._actionList.clear();
		this._gridUtil._fireEvent(this, "PostBackFailed");
		var args = this._raiseClientEvent("AJAXResponse", "CancelAJAXResponse", browserResponseObject, timedOut);
		if (!args || !args.get_cancel())
		{
			if (timedOut)
				alert("Server does not respond.");
			else
			{
				var errorMessage = browserResponseObject.responseText;
				if (errorMessage.substr(0, 6) == "<html>")
				{
					var indexStart = errorMessage.indexOf("<!--");
					var indexEnd;
					if (indexStart > 0)
					{
						indexStart += 4;
						indexEnd = errorMessage.indexOf("-->", indexStart);
						if (indexEnd < 0)
							indexEnd = errorMessage.length;
						errorMessage = errorMessage.substr(indexStart, indexEnd - indexStart);
					}

				}
				alert(errorMessage);
			}
		}
		this._set_isAjaxCallInProgress(false);
	},
	_renderOnAsyncResponse: function(props, html)
	{
		//
		var props = eval(props);

		var div = document.createElement("DIV");
		div.innerHTML = html;
		var id = this.get_id();
		var name = this.get_name();
		var element = this._element;

		// Have to extract table and put it in the same place.
		// If we don't do so the WebResizingExtender disappears after asynch call
		var newElement = div.firstChild;
		while (newElement)
		{
			if (newElement.id == id)
				break;
			newElement = newElement.nextSibling;
		}

		this._gridUtil._fireEvent(this, "AsyncRendering", { newElement: newElement, gridElement: element, tableElement: this._elements.outerTbl });
		newElement = newElement.firstChild;
		while (newElement)
		{
			if (newElement.tagName == "TABLE" && newElement.id.indexOf("outerTbl"))
				break;
			newElement = newElement.nextSibling;
		}

		var parent = newElement.parentNode;
		parent.removeChild(newElement);

		var tableElement = this._elements.outerTbl;

		this.dispose();

		var tableNextSibling = tableElement.nextSibling;
		element.removeChild(tableElement);
		if ($util.IsIE)
			tableElement.removeNode();

		if (tableNextSibling)
			element.insertBefore(newElement, tableNextSibling);
		else
			element.appendChild(newElement);

		if ($util.IsIE)
			div.removeNode();

		return $create($IG.WebDataGrid, { "id": id, "name": name, "props": props }, null, null, $get(id));
	},
	_cell_index_offset: 0,
	_get_cellIndexOffset: function()
	{
		return this._cell_index_offset;
	},
	_incrementCellIndexOffset: function()
	{
		this._cell_index_offset++;
	},
	_decrementCellIndexOffset: function()
	{
		if (this._cell_index_offset == 0)
			return;
		this._cell_index_offset--;
	},
	_notifyPost: function(eventArgs, postBack)
	{
		var cancel = false;
		if (postBack == 2)
			cancel = this._gridUtil._fireEvent(this, "AjaxPostBackStart");
		if (!cancel && (postBack == 1 || postBack == 2))
			cancel = this._gridUtil._fireEvent(this, "PostBackStart");
		if (cancel)
		{
			if (typeof (eventArgs.set_cancel) != "undefined")
				eventArgs.set_cancel(true);
		}
		return cancel;
	},
	_raiseSenderClientEventStart: function(sender, clientEvent, eventArgs)
	{
		if (!this._notifyPost(eventArgs, clientEvent.postBack))
			eventArgs = $IG.WebDataGrid.callBaseMethod(this, '_raiseSenderClientEventStart', [sender, clientEvent, eventArgs]);
		return eventArgs;
	},
	_raiseClientEventStart: function(eventArgs)
	{
		if (!this._notifyPost(eventArgs, eventArgs._props ? eventArgs._props[1] : 0))
			eventArgs = $IG.WebDataGrid.callBaseMethod(this, '_raiseClientEventStart', [eventArgs]);
		return eventArgs;
	},
	_raiseClientEventEnd: function(eventArgs)
	{
		if (!this._get_isAjaxCallInProgress())
		{
			if (eventArgs._props && eventArgs._props[1] == 2)
			{
				this._set_isAjaxCallInProgress(true);
				this._asyncPostStart();
			}
			eventArgs = $IG.WebDataGrid.callBaseMethod(this, '_raiseClientEventEnd', [eventArgs]);
		}
		return eventArgs;
	},
	_get_isAjaxCallInProgress: function()
	{
		return this._isAjaxCallInProgress;
	},
	_set_isAjaxCallInProgress: function(value)
	{
		this._isAjaxCallInProgress = value;
	},
	_asyncPostStart: function()
	{
		/* VS 10/27/2008 Bug 9647: moved into response. */
		/*this._parkEditorProvidersPool();*/
	},

	_ensureEditorProvidersPool: function(container)
	{
		var epp = this._editorProvidersPool;
		/* get around bugs in IE related to locked location of absolute child after parent-scroll */
		/* That does not happen if wrapper-container <div> of <input> does not have absolute position
		var vert = this._container.scrollTop, horiz = this._container.scrollLeft;
		if(!epp || (container.firstChild == epp && vert == this._lastScrollTop && horiz == this._lastScrollLeft))
		return;
		this._lastScrollTop = vert;
		this._lastScrollLeft = horiz;
		*/
		if (!epp || container.firstChild == epp)
			return;
		if (epp.parentNode)
			epp.parentNode.removeChild(epp);
		container.insertBefore(epp, container.firstChild);
		epp.style.display = "";
	},

	_parkEditorProvidersPool: function()
	{
		var pool = this._poolHolder, elem = this._element;
		if (!pool || !elem)
			return;
		pool.parentNode.removeChild(pool);
		elem.parentNode.insertBefore(pool, elem);
		for (var ep in this._editorProviders._items)
		{
			if (!isNaN(parseInt(ep)))
				this._editorProviders._items[ep]._editor = null;
		}
	},

	_addElementEventHandler: function(element, eventType, handler)
	{
		///<summary>
		///Adds an element event handler to the behavior collection hash.
		///</summary>
		///<returns>
		///Boolean. Indicates whether the handler was successfully added.
		///</returns>

		var key = this.__resolveKey(element, eventType);

		var resolvedHashItem = this._eventHandlerHash[key];
		if (!resolvedHashItem)
		{
			resolvedHashItem = this._eventHandlerHash[key] = [];
			this._eventHandlerHash.length++;
		}

		for (var i = 0; i < resolvedHashItem.length; i++)
		{
			if (resolvedHashItem[i] == handler)
				return false;
		}

		if (resolvedHashItem.length == 0)
		{
			var internalHandler = this._eventHandlerHash.handlers[key] = Function.createDelegate(resolvedHashItem, this._elementEventHandler);
			$addHandler(element, eventType, internalHandler);
		}

		resolvedHashItem[resolvedHashItem.length] = handler;

		return true;
	},

	_removeElementEventHandler: function(element, eventType, handler)
	{
		///<summary>
		///Removes an element event handler from the behavior collection hash.
		///</summary>
		///<returns>
		///Boolean. Indicates whether the handler was successfully removed.
		///</returns>

		var key = this.__resolveKey(element, eventType);

		var resolvedHashItem = this._eventHandlerHash[key];
		if (!resolvedHashItem)
			return false;

		for (var i = 0; i < resolvedHashItem.length; i++)
		{
			if (resolvedHashItem[i] == handler)
			{
				resolvedHashItem.splice(i, 1);
				if (resolvedHashItem.length == 0)
				{
					try
					{
						$removeHandler(element, eventType, this._eventHandlerHash.handlers[key]);
					} catch (e) { };
					delete this._eventHandlerHash[key];
					delete this._eventHandlerHash.handlers[key];
					//Could decrease the length but that will potentially introduce the ehh_id collision
					//this._eventHandlerHash.length--;
				}
				return true;
			}
		}
		return false;
	},

	__resolveKey: function(element, eventType)
	{
		if (!element)
			return null;
		var ehh_id = element.id;
		if (element.getAttribute)
		{
			if (!ehh_id)
				ehh_id = element.getAttribute("_ehh_id_" + eventType);
			if (!ehh_id)
			{
				ehh_id = "_ehh_id_" + this._eventHandlerHash.length;
				element.setAttribute("_ehh_id_" + eventType, ehh_id);
			}
		}
		else
		{
			ehh_id = element._ehh_id;
			if (!ehh_id)
				ehh_id = element._ehh_id = "_ehh_id_" + this._eventHandlerHash.length;
		}

		return ehh_id + "_" + eventType;
	},
	/* returns reference to top/main container grid within hierarchical grid. */
	/* that method is implemented by ContainerGrid */
	_getTopGrid: function()
	{
		return null;
	},

	_elementEventHandler: function(evnt)
	{
		var resolvedHashItem = this;
		for (var i = 0; i < resolvedHashItem.length; i++)
			resolvedHashItem[i](evnt);
	},
	get_scrollTop: function()
	{
		return this._get_value($IG.WebDataGridProps.ScrollTop);
	},
	set_scrollTop: function(value)
	{
		this._set_value($IG.WebDataGridProps.ScrollTop, value);
	},
	get_scrollLeft: function()
	{
		return this._get_value($IG.WebDataGridProps.ScrollLeft);
	},
	set_scrollLeft: function(value)
	{
		this._set_value($IG.WebDataGridProps.ScrollLeft, value);
	}
}

$IG.WebDataGrid.registerClass('Infragistics.Web.UI.WebDataGrid', $IG.NavControl, $IG.IGridBehaviorContainer);

$IG.GridAuxRows = new function()
{
	this.Top = 0;
	this.Bottom = 1;
};

/******************************************WebDataGridProps ENUM************************************/
$IG.WebDataGridProps = new function()
{
	var propCount = $IG.ControlMainProps.Count;
	this.RowCount = [propCount++, 0];
	this.ScrollTop = [propCount++, 0];
	this.ScrollLeft = [propCount++, 0];
	this.Count = propCount;
};
/******************************************END WebDataGridProps ENUM********************************/

/******************************************GridBehaviorCollection************************************/
$IG.GridBehaviorCollection = function(control)
{
	/// <summary>
	/// Grid behavior collections. Contains helper properties for explicit access to the behaviors.
	/// </summary>
	$IG.GridBehaviorCollection.initializeBase(this, [control]);
}

$IG.GridBehaviorCollection.prototype =
{
	_paging: null,
	get_paging: function()
	{
		/// <summary>
		/// Returns reference to the paging behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._paging;
	},

	_selection: null,
	get_selection: function()
	{
		/// <summary>
		/// Returns reference to the selection behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._selection;
	},

	_activation: null,
	get_activation: function()
	{
		/// <summary>
		/// Returns reference to the activation behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._activation;
	},

	_rowSelectors: null,
	get_rowSelectors: function()
	{
		/// <summary>
		/// Returns reference to the row selectors behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._rowSelectors;
	},

	_columnResizing: null,
	get_columnResizing: function()
	{
		/// <summary>
		/// Returns reference to the column resizing behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._columnResizing;
	},

	_columnMoving: null,
	get_columnMoving: function()
	{
		/// <summary>
		/// Returns reference to the column moving behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._columnMoving;
	},

	_editingCore: null,
	get_editingCore: function()
	{
		/// <summary>
		/// Returns reference to the editing core behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._editingCore;
	},

	_sorting: null,
	get_sorting: function()
	{
		/// <summary>
		/// Returns reference to the sorting behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._sorting;
	},

	_filtering: null,
	get_filtering: function()
	{
		/// <summary>
		/// Returns reference to the filtering behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._filtering;
	},

	_virtualScrolling: null,
	get_virtualScrolling: function()
	{
		/// <summary>
		/// Returns reference to the virtual scrolling behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._virtualScrolling;
	},

	_columnFixing: null,
	get_columnFixing: function()
	{
		/// <summary>
		/// Returns reference to the column fixing behavior if one exists in the collection. 
		/// Null if the behavior is not added or not enabled on the server.
		/// </summary>
		return this._columnFixing;
	},

	dispose: function()
	{
		this._paging = null;
		this._selection = null;
		this._activation = null;
		this._rowSelectors = null;
		this._columnResizing = null;
		this._editingCore = null;
		this._sorting = null;
		this._filtering = null;
		this._virtualScrolling = null;
		this._columnFixing = null;
		$IG.GridBehaviorCollection.callBaseMethod(this, "dispose");
	}
}

$IG.GridBehaviorCollection.registerClass('Infragistics.Web.UI.GridBehaviorCollection', $IG.BehaviorCollectionBase);
/******************************************END GridBehaviorCollection************************************/

/******************************************Column Collection************************************/
$IG.ColumnCollection = function(control, clientStateManager, index, manager)
{
	/// <summary>
	/// Column collection object. Contains the grid's columns.
	/// </summary>
	$IG.ColumnCollection.initializeBase(this, [control, clientStateManager, index, manager]);
}

$IG.ColumnCollection.prototype =
{
	/*_createNewCollection:function()
	{
		
	return new $IG.ColumnCollection(this._control, this._csm, this._index, this._manager);
	},*/

	/*_addObject:function(navItemType, element, adr)
	{
		
	var object = null;
	var newCollection = this._createNewCollection();
	var indexes = adr.split('.');
	if(indexes.length == 1)
	{
	var val = parseInt(adr);
	if(val.toString() != "NaN")
	object = this._items[val] = new navItemType(adr, element, this._csm.get_itemProps(adr), this._control, this._csm, newCollection, null);
	}
	else
	{
	var parent = this._items[indexes[0]];
	for(var i = 1; i < indexes.length - 1; i++)
	{
	if(parent != null)
	parent = parent.getItems().get_objectByIndex(indexes[i]);
	}
             
	if(parent != null)
	object = parent.getItems()._items[indexes[indexes.length-1]] = new navItemType(adr, element, this._csm.get_itemProps(adr), this._control, this._csm, newCollection, parent);
	}
	this._manager.addObject(this._index, adr, object);
	return object;
	}*/
	get_column: function(index)
	{
		/// <summary>
		/// Gets a column from the collection by its index.
		/// </summary>
		return this._items[index];
	},
	get_columnFromKey: function(key)
	{
		/// <summary>
		/// Gets a column from the collection by its key.
		/// </summary>
		for (var i = 0; i < this._items.length; i++)
		{
			var column = this.get_column(i);
			if (column.get_key() == key)
				return column;
		}
		return null;
	},

	get_columnFromIDPair: function(idPair)
	{
		/// <summary>
		/// Gets a column from the collection by its ID pair.
		/// </summary>
		var column = null;
		if (idPair.key && idPair.key.length)
			column = this.get_columnFromKey(idPair.key[0]);
		if (!column)
			column = this.get_column(idPair.index);
		return column;
	}

};

$IG.ColumnCollection.registerClass('Infragistics.Web.UI.ColumnCollection', $IG.ObjectCollection);
/******************************************END Column Collection************************************/

/******************************************Column************************************/
$IG.GridColumn = function(adr, element, props, owner, csm)
{
	/// <summary>
	/// Grid column object.
	/// </summary>

	$IG.GridColumn.initializeBase(this, [adr, element, props, owner, csm]);
	//
	this._key = this._get_clientOnlyValue("key");
	this._visibleIndex = this._get_clientOnlyValue("vIndex");
	this._headerElement = this._findHeaderElement(owner._elements["header"], this._key, this._visibleIndex);
	this._footerElement = this._findHeaderElement(owner._elements["footer"], this._key, this._visibleIndex);
	this._type = this._get_clientOnlyValue("type");
	this._nullable = this._get_clientOnlyValue("nullable");
}

$IG.GridColumn.prototype =
{
	get_key: function()
	{
		/// <summary>
		/// Gets the key of the column.
		/// </summary>
		return this._key;
	},

	get_isTemplated: function()
	{
		/// <summary>
		/// Gets a boolean value that indicates true if the column is a templated column.  Returns false otherwise.
		/// </summary>
		var tmpl = this._get_clientOnlyValue("tmpl");
		return tmpl == "1" ? true : false;
	},

	get_type: function()
	{
		/// <summary>
		/// Gets the type of the column.
		/// </summary>
		return this._type;
	},

	get_nullable: function()
	{
		/// <summary>
		/// Indicates whether the column's type is nullable.
		/// </summary>
		return this._nullable;
	},

	get_nullText: function()
	{
		return "";
	},

	_parentCollection: null,
	get_index: function()
	{
		/// <summary>
		/// Gets the index of the column inside of its container collection.
		/// </summary>
		if (this._parentCollection == null)
			return -1;
		return this._parentCollection.get_indexOf(this);
	},

	get_header: function()
	{
		if (!this._headerElement)
			return null;
			
		if (!this["_header"])
			this._header = new $IG.GridColumnCaption(this, "header");

		return this._header;
	},

	get_footer: function()
	{
		if (!this._footerElement)
			return null;

		if (!this["_footer"])
			this._footer = new $IG.GridColumnCaption(this, "footer");

		return this._footer;
	},

	get_headerElement: function()
	{
		/// <summary>
		/// Returns the element assoicated with the column header. 
		/// </summary>
		return this._headerElement;
	},

	get_footerElement: function()
	{
		/// <summary>
		/// Returns the element assoicated with the column footer. 
		/// </summary>
		return this._footerElement;
	},

	get_headerText: function()
	{
		/// <summary>
		/// Text of the column header.
		/// </summary>		
		return this._get_clientOnlyValue("headTxt");
	},

	get_footerText: function()
	{
		/// <summary>
		/// Text of the column footer.
		/// </summary>		
		return this._get_clientOnlyValue("footTxt");
	},

	get_dataType: function()
	{
		/// <summary>Data type in column.</summary>
		/// <returns type="Infragistics.Web.UI.GridDataType">Returns one of the integer values defined in Infragistics.Web.UI.GridDataType.</returns>
		return this._get_clientOnlyValue("type2");
	},

	get_hidden: function()
	{
		/// <summary>
		/// Makes the column to be hidden from view.
		/// </summary>
		var dbHidden = this._get_value($IG.ColumnProps.Hidden, 0);
		return dbHidden == 1; // it's a defaultable boolean on the server
	},

	set_hidden: function(value)
	{
		var oldValue = this.get_hidden();
		if (oldValue == value)
			return;

		var style = this._get_hiddenStyleSheet();

		style.display = value ? "none" : "";

		this._set_value($IG.ColumnProps.Hidden, value ? 1 : 2); // it's a defaultable boolean on the server

		this._owner._adjustTableWidth();
		if ($util.IsIEStandards)
			this._owner._onDataTblResize({ "clientHeight": this._owner._elements.dataTbl.clientHeight }, null);
		this._owner._onResize({ "clientHeight": this._owner._element.clientHeight }, false);

		var args = { column: this };
		this._owner._gridUtil._fireEvent(this._owner, "HideColumn", args);
	},

	_get_hiddenCss: function()
	{
		return this._get_value($IG.ColumnProps.HiddenCssClass);
	},

	_set_hiddenCss: function(value)
	{
		this._set_value($IG.ColumnProps.HiddenCssClass, value);
	},

	_get_hiddenStyleSheet: function()
	{
		var css = this._get_hiddenCss();

		if (!css)// To avoid going through all of the cells, the Hidden property should be assigned on the server to generate a css class for it
		{
			css = this._owner.get_id() + "_col" + this.get_index() + "_hidden";
			var lastSS = document.styleSheets[document.styleSheets.length - 1];
			if (typeof (lastSS.addRule) != "undefined")
				lastSS.addRule("." + css);
			else
				lastSS.insertRule("." + css + "{}", lastSS.length);

			if (this._headerElement)
				this._headerElement.className += (this._headerElement.className ? " " : "") + css;

			var rows = this._owner.get_rows();
			for (var i = 0; i < rows.get_length(); i++)
			{
				var cell = rows.get_row(i).get_cellByColumn(this);
				var elem = cell.get_element();
				if (elem)
					elem.className += (elem.className ? " " : "") + css;
			}

			rows = this._owner._get_auxRows();
			for (var i = 0; i < rows.length; i++)
			{
				var cell = rows[i].get_cellByColumn(this);
				var elem = cell.get_element();
				if (elem)
					elem.className += (elem.className ? " " : "") + css;
			}

			if (this._footerElement)
				this._footerElement.className += (this._headerElement.className ? " " : "") + css;

			this._set_hiddenCss(css);
		}

		return $util.getStyleSheet(css);
	},

	_findHeaderElement: function(element, key, index)
	{
		if (!element || typeof (element.getAttribute) == "undefined")
			return null;
		var idx = element.getAttribute("idx");
		var hKey = element.getAttribute("key");
		if (hKey)
		{
			if (hKey == key)
				return element;
			return null;
		}
		else if (idx)
		{
			if (idx == index)
				return element;
			return null;
		}
		for (var i = 0; i < element.childNodes.length; i++)
		{
			var hdr = this._findHeaderElement(element.childNodes[i], key, index);
			if (hdr)
				return hdr;
		}
		return null;
	},
	get_idPair: function()
	{
		/// <summary>
		/// Gets the ID pair of the column.
		/// </summary>
		if (!this._idPair)
			this._idPair = new $IG.IDPair(this.get_index(), this.get_key());
		return this._idPair;
	},
	/*
	DK 8 Oct 2008
	Bug 8798 :Cannot change column width in client
	Changed get_width / set_widtht to public members.
	*/
	get_width: function()
	{
		/// <summary>
		/// Gets the width of the Column
		/// </summary>
		return this._get_value($IG.ColumnProps.Width, "");
	},
	set_width: function(value)
	{
		/// <summary>
		/// Sets the width of the column
		/// </summary>
		/// <param>
		/// the unit based value that the column should be set to 
		/// </param>
		var oldValue = this.get_width();
		this._set_value($IG.ColumnProps.Width, value);

		var args = { column: this, width: value, cancel: false };
		this._owner._gridUtil._fireEvent(this._owner, "SetColumnWidth", args);

		if (!args.cancel)
		{
			// need to set it on the header, the footer and on the row object that defines width
			if (this._headerElement)
				this._headerElement.style.width = value;
			if (this._footerElement)
				this._footerElement.style.width = value;
			if (this._owner.get_rows().get_length() > 0)
			{
				var rowZero = this._owner.get_rows().get_row(0);
				rowZero.get_cellByColumn(this).get_element().style.width = value;
			}
			/*
			DK 8 Oct 2008
			When you set the column width, you need to change the scrollbar width
			*/
			if (value && (value + "").indexOf("px") != -1)
			{
				var dataTblStyle = this._owner._elements.dataTbl.style;
				var existingTableWidth = dataTblStyle.width;
				if (existingTableWidth && (existingTableWidth + "").indexOf("px") != -1)
				{
					if (oldValue && (oldValue + "").indexOf("px") != -1)
					{
						dataTblStyle.width = (parseInt(existingTableWidth) + parseInt(value) - parseInt(oldValue)) + "px";

						//					this._owner._initHScrBar();
						//					this._owner.alignCaptions();

						/*
						DK 9 Oct 2008
						Bug 8821 : Resizing column width in client does not make horizontal scroll bar appear.
						Call this so that the grid will reset itself
						*/
						this._owner._onResize({ "clientHeight": this._owner._element.clientHeight }, false);
					}
				}
				else
				{
					/* OK 8854 10/20/08 - we need to resize the grid no matter what kind of width the dataTbl has
					since one of the columns will be getting a new width */
					this._owner._onResize({ "clientHeight": this._owner._element.clientHeight }, false);
				}
			}
		}
	},
	_get_dataFormatString: function()
	{
		var format = this._get_clientOnlyValue("cf");
		/*
		DK 2 Oct 2008
		Bug 8258 : DateTime Format is different before and after cell is in Edit mode.
		We are going to use "d" as an undercover default, as this is supported by the MSFT AJAX library as a valid date format
		*/
		if (!format && this.get_type() == "date")
			format = this._defaultDateFormat;
		return format;
	},
	_formatMethod: null,
	get_formatMethod: function()
	{
		///<summary>
		///Holds a reference to a custom formatting method. The method must accept a single parameter
		///through which the raw value is going to be passed. The return value must be a formatted string.
		///</summary>
		return this._formatMethod;
	},
	set_formatMethod: function(value)
	{
		this._formatMethod = value;
	},
	_defaultDateFormat: "{0:d}",
	_formatValue: function(value)
	{
		if (value == null && this.get_nullable())
			return this.get_nullText();
		if (this._formatMethod != null)
			return this._formatMethod(value);
		var format = this._get_dataFormatString();
		if (format)
		{
			/* O.K. 9/17/2008 7555 - in order to convert a date to the provided format we have to make the 
			value a date first and then apply the format string */
			/* OK 9001 10/21/2008 - have to parse the date with the current culture in mind, changed 
			to use Date.parseLocale instead of just new Date(value) */
			/* AK 10/22/2008 There is more to dates formattin:
			passed value can be either string, or date, or something else */
			if (this.get_type() === "date" && value)
			{
				/*OK 10/23/08 9543 - typeof will return "object" for null and then the getMonth function will cause a JS error*/
				if (value == null)
					return "";
				if (typeof (value) == "string")
					return String.localeFormat(format, Date.parseLocale(value));
				else if (typeof (value) == "object" && typeof (value.getMonth) != "undefined")
					return String.localeFormat(format, value);
				else
					return String.localeFormat(format, new Date(value));
			}
			else
				return String.localeFormat(format, value);
		}
		/* AK 1/13/2009 Bug 12204 Culture formats. That would fix a bug, but value will have default like 2 decimals, etc. */
		/* so, it will distroy the rest of decimals or add 2 zeros to int.
		The number of decimals is defined on the server by the CultureInfo. So the customer can tackle it if s/he 
		needs to adjust the number. */
		else if (typeof value == 'number')
		{
			/* AK May-5-2009 17452 Default formatting {0:n} is adding .00, not a desired outcome for the customers. Changing to {0:d} */
			var num = '' + value, val = String.localeFormat('{0:d}', value);
			if (num == 'NaN')
				return '';
			/* VS 09/22/2009 Bug 22477. String.localeFormat('{0:d}',value) returns same value as default num */
			/* if it happens, then use decimal separator from CultureInfo */
			if (num == val && val.indexOf('.') > 0) try
			{
				var sep = Sys.CultureInfo.CurrentCulture.numberFormat.NumberDecimalSeparator;
				if (sep && sep.length == 1 && val.indexOf(sep) < 0)
					val = val.replace('.', sep);
			}
			catch (num) { }
			return val;
		}


		/* D.M. 9/29/2008 8111 - If the value is null we should convert it to an empty string before trying
		call toString() on it.*/
		if (value == null)
			value = "";
		return value.toString();
	},

	get_visibleIndex: function()
	{
		return this._visibleIndex;
	},

	dispose: function()
	{
		this._headerElement = null;
		this._footerElement = null;
		this._parentCollection = null;
		$IG.GridColumn.callBaseMethod(this, "dispose");
	}
}
$IG.GridColumn.registerClass('Infragistics.Web.UI.GridColumn', $IG.UIObject);

$IG.GridColumnCaption = function(column, type)
{
	/// <summary>
	/// Grid column caption (header or footer) object.
	/// </summary>

	this._column = column;
	this._type = type;
}

$IG.GridColumnCaption.prototype =
{
	get_column: function()
	{
		return this._column;
	},
	get_type: function()
	{
		return this._type;
	},
	get_text: function()
	{
		return this._column["get_" + this._type + "Text"]();
	},
	get_element: function()
	{
		return this._column["get_" + this._type + "Element"]();
	}
}
$IG.GridColumnCaption.registerClass('Infragistics.Web.UI.GridColumnCaption');
/******************************************End Column************************************/

/******************************************ColumnProps ENUM************************************/
$IG.ColumnProps = new function()
{
	var count = $IG.ObjectBaseProps.Count;
	this.Hidden = [count++, false];
	this.HiddenCssClass = [count++, ""];
	this.Width = [count++, ""];
	this.Count = count;
};
/******************************************END ColumnProps ENUM********************************/

/******************************************Row Collection************************************/

$IG.GridRowCollection = function(element, props, owner)
{
	/// <summary>
	/// Row collection object. Contains the grid's rows.
	/// </summary>
	this._rows = [];

	/* DK 19 Sept 2008
	Implemented a HashTree to see if we can get better performance than using a psudotree structure.
	*/
	// this._keyIndexTree = {};
	this._keyIndexTree = new $IG.HashTree();

	$IG.GridRowCollection.initializeBase(this, [null, element, props, owner, null]);

	//	$addHandler(this.get_element(), "mouseover", Function.createDelegate(this, this._onMouseOver));

	$addHandler(this._owner._element, "mouseover", Function.createDelegate(this, this._onMouseOver));
}

$IG.GridRowCollection.prototype =
{
	initialize: function()
	{
		/// <summary>
		/// Initializes the collection. The method is called automatically by the framework.
		/// </summary>
		$IG.GridRowCollection.callBaseMethod(this, 'initialize');
	},

	dispose: function()
	{
		/// <summary>
		/// Disposes of the collection object. The method is called automatically by the framework.
		/// </summary>
		for (var rowIndex in this._rows)
		{
			if (!isNaN(parseInt(rowIndex)))
			{
				var row = this._rows[rowIndex];
				if (row)
					row.dispose();
			}
		}
		if (this.get_element())
			$clearHandlers(this.get_element());
		if (this._keyIndexTree)
			this._keyIndexTree.dispose();
		$IG.GridRowCollection.callBaseMethod(this, 'dispose');
	},

	get_grid: function()
	{
		/// <summary>
		/// Returns reference to the grid that owns the collection.
		/// </summary>
		return this._owner;
	},

	get_length: function()
	{
		///<summary>
		///Returns actual number of rows in the collection
		///regardless of how many were instantiated.
		///</summary>
		return this._props[$IG.RowCollectionProps.RowCount];
	},

	_set_length: function(newRowCount)
	{
		this._props[$IG.RowCollectionProps.RowCount] = newRowCount;
	},

	get_row: function(index, skipKeyIndexing)
	{
		///<summary>
		///Returns a row by its index. If the row is not instantiated yet it is being created and returned.
		///</summary>
		///<param name="index" type="integer">
		///Index of the row to return.
		///</param>
		if (index < 0 || index >= this.get_length())
			return null;

		var returnRow = this._rows[index];
		if (!returnRow)
		{
			// get the row element by index
			// for hierarchical implementation wil have to override this method and use index*2 to account for the hidden TRs
			returnRow = this._rows[index] = this._create_item(index);
		}
		/*
		DK 23 Sept 2008
		Bug 7978 : Column Selection is slow
		Ok so we are adding an overload for the get_row method that will accept a second parameter
		If true then we will not automatically index the row using the hashTree.  This should allow 
		for faster actions like selection, HOWEVER if you prevent key indexing, then sooner or later you will
		end up having to index.  This merely delays the penalty, does not erase it completely.
		*/
		if (!skipKeyIndexing)
		{
			if (returnRow)
			{
				if (!returnRow._get_isKeyIndexed())
				{
					this._keyIndexTree.add(returnRow);
					returnRow._set_isKeyIndexed(true);
				}
			}
		}

		return returnRow;
	},

	get_rowFromKey: function(dataKey)
	{
		///<summary>
		///Returns a row by its data key. If the row is not instantiated yet it is being created and returned.
		///</summary>
		///<param name="dataKey" type="array">
		///Data key of the row to return. The data key is expected to be provided as an array, 
		///in the case of a single data key field it should be an array with a single item.
		///</param>

		if (!dataKey || !dataKey.length)
			return null;

		/*
		DK 19 Sept 2008
		Changed to use the HashTree implementation
		*/
		var row = this._keyIndexTree.findByKey(dataKey);
		/*var row = this._resolveIndexedKey(dataKey, this._keyIndexTree);*/
		if (row)
			return row;

		for (var i = 0; i < this.get_length(); i++)
		{
			row = this.get_row(i);
			if (row && row.isDataKeyEqual(dataKey))
				return row;
		}
		return null;
	},

	get_rowFromIDPair: function(idPair)
	{
		///<summary>
		///Returns a row by its ID pair. If the row is not instantiated yet it is being created and returned.
		///</summary>
		///<param name="idPair" type="Infragistics.Web.UI.IDPair">
		///ID pair of the row to return. The ID pair is an object of type Infragistics.Web.UI.IDPair.
		///</param>
		///<remarks>
		///The method attempts to find the row by the data key provided in the ID pair.
		///If the attempt fails the row is sought and returned by its index.
		///</remarks>

		if (idPair.index < 0)
			return null;

		var row = this.get_rowFromKey(idPair.key);
		if (!row)
			row = this.get_row(idPair.index);
		return row;
	},

	get_cellFromIDPair: function(idPair)
	{
		///<summary>
		///Returns a cell by its ID pair. If the cell is not instantiated yet it is being created and returned.
		///</summary>
		///<param name="idPair" type="Infragistics.Web.UI.CellIDPair">
		///ID pair of the cell to return. The ID pair is an object of type Infragistics.Web.UI.CellIDPair which 
		///contains two ID pairs of the cell's row and column.
		///</param>
		///<remarks>
		///The method attempts to find the row and column by their ID pairs and return the cell on the crosshair if successful.
		///</remarks>
		var cell = null;
		var row = this.get_rowFromIDPair(idPair.rowIDPair);
		if (row)
		{
			var column = this.get_grid().get_columns().get_columnFromIDPair(idPair.columnIDPair);
			if (column)
				cell = row.get_cellByColumn(column);
		}
		return cell;
	},
	/*_indexRow: function(row, indexTree)
	{
	var dataKey = row.get_dataKey();
	if (!dataKey)
	return;
	if (indexTree.dataKey == undefined)
	{
	indexTree.dataKey = dataKey;
	indexTree.row = row;
	indexTree.left = {};
	indexTree.right = {};
	return;
	}
	if (this._compareDataKeys(dataKey, indexTree.dataKey) < 0)
	return this._indexRow(row, indexTree.left);
	if (this._compareDataKeys(dataKey, indexTree.dataKey) > 0)
	return this._indexRow(row, indexTree.right);
	throw "Rows must have unique DataKeys. This key appears more than once: " + dataKey;
	},*/

	_compareDataKeys: function(key1, key2)
	{
		if (!key1 || !key2 || key1.length == undefined || key2.length == undefined || key1.length != key2.length)
			throw "Incorrect keys: " + key1.toString() + " " + key2.toString();

		for (var i = 0; i < key1.length; i++)
		{
			if (key1[i] < key2[i])
				return -i - 1;
			if (key1[i] > key2[i])
				return i + 1;
		}

		return 0;
	},

	_resolveIndexedKey: function(dataKey, indexTree)
	{
		if (indexTree.dataKey == undefined)
			return null;

		if (this._compareDataKeys(indexTree.dataKey, dataKey) == 0)
			return indexTree.row;

		var row = this._resolveIndexedKey(dataKey, indexTree.left);
		if (!row)
			row = this._resolveIndexedKey(dataKey, indexTree.right);
		return row;
	},

	_create_item: function(index)
	{
		/* Making sure that the element exists before we create the row */
		var rows = $util.getRows(this.get_element());
		var rowElem = rows ? rows[index] : null;
		if (!rowElem)
			return null;

		var row = new $IG.GridRow(index, rowElem, [], this.get_grid(), null);

		//this._indexRow(row, this._keyIndexTree);
		// RowSelector behavior needs this to tag the row selector elements when the row is created
		this._owner._gridUtil._fireEvent(this, "RowCreated", row);
		return row;
	},

	_onMouseOver: function(e)
	{
		var target = e.target;

		// Make sure that the element that we're over is actually a Grid Cell
		target = this._owner._gridUtil._getGridCellFromElement(target);

		// Marke the Cell as a Grid Cell so that behaviors have a way to determine a cell via the UI.	
		if (target && (target.tagName == "TD" || target.tagName == "TH")) //TH for row selectors
		{
			var row = target.parentNode;
			this._onMouseOverCell(target, row);
		}
	},
	_onMouseOverCell: function(target, row)
	{
		var adr = row.getAttribute("adr");
		if (adr === null && row.id.indexOf("adr") >= 0)
		{
			$util._initAttr(row);
			adr = row.getAttribute("adr");
		}
		if (adr !== null && row.getAttribute("type") == null)
		{
			var index = parseInt(adr, 10);
			if (!this._rows[index])
				this._rows[index] = this._create_item(row.rowIndex);
		}

		if (!target.getAttribute("adr") && target.tagName == "TD")
		{
			var idx = this._owner._gridUtil.getCellIndexFromElem(target);
			if (idx < 0) /* This means its not a cell, its a row selector or some other HTML TD */
				return;
			target.setAttribute("idx", idx);
			target.setAttribute("adr", this._owner._gridUtil._getColumnAdrFromVisibleIndex(idx));
			target.setAttribute("type", "cell");
		}
	},
	addRowCreatedEventHandler: function(handler)
	{
		/// <summary>
		/// Adds a listener to the RowCreated internal event.
		/// </summary>

		this._owner._gridUtil._registerEventListener(this, "RowCreated", handler);
	},

	add: function(cellValues)
	{
		/// <summary>
		/// Creates and adds a row to the collection.
		/// </summary>
		/// <param name="cellValues" type="Array">
		/// Array of the new row values.
		/// </param>
		/// <remarks>The <c>cellValues</c> parameter can also optionally contain an array of json objects
		/// in the format <c>{ 'Value': '<Value>', 'DataKeyField': '<DataKeyField>' }</c>.
		/// </remarks>

		var editing = this.get_grid().get_behaviors().getBehaviorFromInterface($IG.IEditingBehavior);
		if (!editing)
			alert("The Editing behavior must be present for the 'add' method to function.");
		this.get_grid()._gridUtil._fireEvent(this.get_grid(), "RowAdded", { "cellValues": cellValues });
	},

	remove: function(row, noncommitting)
	{
		/// <summary>
		/// Removes a row from the collection.
		/// </summary>
		/// <param name="row" type="GridRow">
		/// Row to remove from the collection.
		/// </param>

		var editing = this.get_grid().get_behaviors().getBehaviorFromInterface($IG.IEditingBehavior);
		if (!editing)
			alert("The Editing behavior must be present for the 'remove' method to function.");
		this.get_grid()._gridUtil._fireEvent(this.get_grid(), "RowsDeleted", { "row": row, "commit": (noncommitting ? false : true) });
	}
}

$IG.GridRowCollection.registerClass('Infragistics.Web.UI.GridRowCollection', $IG.UIObject);

/******************************************END Row Collection************************************/


/******************************************RowCollectionProps ENUM************************************/
$IG.RowCollectionProps = new function()
{
	this.RowCount = 0;
	this.Count = 1;
};
/******************************************END RowCollectionProps ENUM********************************/

/******************************************Row************************************/

$IG.GridRow = function(adr, element, props, owner, csm)
{
	/// <summary>
	/// Grid row object.
	/// </summary>
	this._index = parseInt(adr);
	this._cells = [];
	$util._initAttr(element);
	element.setAttribute("type", "row");
	$IG.GridRow.initializeBase(this, [adr, element, props, owner, csm]);
	this._isKeyIndexed = false;
}

$IG.GridRow.prototype =
{
	initialize: function()
	{
		/// <summary>
		/// Initializes the row. The method is called automatically by the framework.
		/// </summary>
		$IG.GridRow.callBaseMethod(this, 'initialize');
	},

	dispose: function()
	{
		/// <summary>
		/// Final clean up method. The method is called automatically by the framework.
		/// </summary>
		var ele = this.get_element();
		if (ele) $clearHandlers(ele);
		for (var cell in this._cells)
		{
			if (!isNaN(parseInt(cell)))
			{
				if (this._cells[cell])
					this._cells[cell].dispose();
				this._cells[cell] = null;
			}
		}
		$IG.GridRow.callBaseMethod(this, 'dispose');
	},

	get_grid: function()
	{
		/// <summary>
		/// Returns reference to the grid that owns the row.
		/// </summary>

		return this._owner;
	},

	get_cell: function(index)
	{
		/// <summary>
		/// Returns a cell by its index.
		/// </summary>
		/// <param name="index" type="Number" integer="true">
		/// Index of the cell in the row.
		/// </param>
		if (index < 0 || index >= this.get_cellCount())
			throw "CellCollection: Out of bounds exception.";

		if (!this._cells[index])
		{
			var adr = index;
			index = this.get_grid().get_columns().get_column(adr).get_visibleIndex();
			this._cells[adr] = this._create_item(adr, index);
			index = adr;
		}

		return this._cells[index];
	},

	get_cellByColumnKey: function(columnKey)
	{
		/// <summary>
		/// Returns a cell by its column key.
		/// </summary>
		/// <param name="columnKey" type="string">
		/// Key of the column the cell belongs to. If a invalid key is passed null will be returned.
		/// </param>

		var column = this.get_grid().get_columns().get_columnFromKey(columnKey);
		if (column)
			return this.get_cell(column.get_index());
		return null;
	},

	get_cellByColumn: function(column)
	{
		/// <summary>
		/// Returns a cell by its column.
		/// </summary>
		/// <param name="column" type="GridColumn">
		/// Column the cell belongs to.
		/// </param>
		return this.get_cell(column.get_index());
	},

	_get_cellElementByIndex: function(rowElement, index)
	{
		var args = { rowElement: rowElement, index: index, cellElement: null, cancel: false };
		this._owner._gridUtil._fireEvent(this._owner, "GetCellElementByIndex", args);

		if (!args.cancel)
			return rowElement.childNodes[index];
		else
			return args.cellElement;
	},

	_create_item: function(adr, index)
	{
		var cellIndex = parseInt(index) + this._owner._get_cellIndexOffset();
		var cell = new $IG.GridCell(this, adr, this._get_cellElementByIndex(this.get_element(), cellIndex), [], this.get_grid(), null);
		cell._column = this._owner._columns._getObjectByIndex(adr);
		return cell;
	},

	get_cellCount: function()
	{
		/// <summary>
		/// Returns number of cells in the row.
		/// </summary>
		return this.get_grid().get_columns().get_length();

		/*
		DK 21 Aug 2008
		BR35405: JS runtime error when you launch the row edit template. 
		This code counts only the cells, does not exclude row selectors
		*/
	},

	get_index: function()
	{
		/// <summary>
		/// Returns index of the row inside of its container collection.
		/// </summary>
		return this._index;
	},
	__colon: ":",
	__colonSubs: "~$~",
	get_dataKey: function()
	{
		/// <summary>
		/// Returns data key of the row. It is always an array of objects even in a case of a single data key field.
		/// </summary>
		var dataKey = this._element.getAttribute("key");
		if (dataKey)
		{
			dataKey = Sys.Serialization.JavaScriptSerializer.deserialize(dataKey.replace(this.__colonSubs, this.__colon));
			return dataKey;
		}
		return [];
	},
	isDataKeyEqual: function(dataKey)
	{
		///<summary>
		///Compares provided data key with the row's data key and returns a 
		///boolean value indicating whether these are equal.
		///</summary>
		///<param name="dataKey">
		///A data key to compare with the row's one.
		///</param>
		///<returns>
		///Boolean value indicating whether the passed in data key is equal to the row's one.
		///</returns>

		var rowDataKey = this.get_dataKey();
		if (rowDataKey && dataKey && rowDataKey.length == dataKey.length)
		{
			for (var i = 0; i < dataKey.length; i++)
				if (rowDataKey[i] != dataKey[i])
				return false;
			return true;
		}
		return false;
	},
	get_idPair: function()
	{
		if (!this._idPair)
			this._idPair = new $IG.IDPair(this.get_index(), this.get_dataKey());
		return this._idPair;
	},
	get_tag: function()
	{
		///<summary>
		///Returns the Tag property value that is set on the server.
		///</summary>
		if (this._element.getAttribute("tag"))
			return Sys.Serialization.JavaScriptSerializer.deserialize(this._element.getAttribute("tag").replace(this.__colonSubs, this.__colon));
		return null;
	},
	_get_isKeyIndexed: function()
	{
		return this._isKeyIndexed;
	},
	_set_isKeyIndexed: function(value)
	{
		this._isKeyIndexed = value;
	}
}

$IG.GridRow.registerClass('Infragistics.Web.UI.GridRow', $IG.UIObject);

/******************************************END Row************************************/

/******************************************Cell************************************/

$IG.GridCell = function(row, adr, element, props, owner, csm)
{
	/// <summary>
	/// Grid cell object.
	/// </summary>
	this._row = row;
	$IG.GridCell.initializeBase(this, [adr, element, props, owner, csm]);

	if (!element.getAttribute("wlkd"))
	{
		$util._initAttr(element);
		element.setAttribute("adr", adr);
		element.setAttribute("idx", owner._gridUtil.getCellIndexFromElem(element));
		element.setAttribute("type", "cell");
		element.setAttribute("wlkd", "1");
	}
}

$IG.GridCell.prototype =
{
	initialize: function()
	{
		/// <summary>
		/// The method is called during initialization of the cell. Contains initializing code for the cell.
		/// </summary>
		$IG.GridCell.callBaseMethod(this, 'initialize');
	},

	dispose: function()
	{
		/// <summary>
		/// Called whenever the object is being disposed of.
		/// </summary>
		var ele = this.get_element();
		if (ele)
			$clearHandlers(ele);
		$IG.GridCell.callBaseMethod(this, 'dispose');
	},

	get_grid: function()
	{
		/// <summary>
		/// Gets reference to the grid object that contains the cell.
		/// </summary>
		return this._owner;
	},
	get_row: function()
	{
		/// <summary>
		/// Gets reference to the row object that contains the cell.
		/// </summary>
		return this._row;
	},
	get_column: function()
	{
		/// <summary>
		/// Gets reference to the column object that contains the cell.
		/// </summary>
		return this._column;
	},

	get_index: function()
	{
		/// <summary>
		/// Gets index of the cell inside of its collection.
		/// </summary>
		if (!this.get_column())
			return -1;
		return this.get_column().get_idPair().index;
	},
	get_idPair: function()
	{
		/// <summary>
		/// Gets ID pair of the cell.
		/// </summary>
		if (!this._idPair)
			this._idPair = new $IG.CellIDPair(this.get_row().get_idPair(), this.get_column().get_idPair());
		return this._idPair;
	},
	get_value: function()
	{
		///<summary>
		///Gets the cell's value.
		///</summary>		
		var value = this._element.getAttribute("val");
		if (value)
		{
			/* OK 4/27/2009 17043 - for w3c compliance characters were removed from the date value, no we have to put them back before deserialization */
			if (this.get_column().get_type() == "date")
			{
				if (value == "\"\"")
					return null;
				value = "\"\\/Date(" + value + ")\\/\"";
			}
			return Sys.Serialization.JavaScriptSerializer.deserialize(value);
		}
		var origValue = this.get_text();
		var column = this.get_column();

		if (column.get_nullable() && origValue == column.get_nullText())
			return null;

		if (column.get_type() == "number")
		{
			/* AK 1/13/2009 Bug 12204. Culture formats. That would fix a bug, but value will have default like 2 decimals, etc. */
			/* so, it will distroy the rest of decimals or add 2 zeros to int.
			The number of decimals is defined on the server by the CultureInfo. So the customer can tackle it if s/he 
			needs to adjust the number. */
			value = Number.parseLocale(origValue);
			if (isNaN(value))
				value = parseFloat(origValue);
			if (isNaN(value))
				value = origValue;
			if (isNaN(value) || !value)
				value = 0;
		}
		else if (column.get_type() == "boolean")
		{
			if (origValue.length > 0)
				value = (origValue.toString().toLowerCase() == "true");
			else
				value = origValue;
		}
		else
			value = origValue;
		return value;
	},
	set_value: function(value, text)
	{
		///<summary>
		///Sets the cell's value and text.
		///</summary>
		///<param name="value">
		///Value of the cell to set.
		///</param>
		///<param name="text">
		///Optional. If the cell's text differs from its value this parameter should contain the
		///text to render in the cell element.
		///</param>
		var oldValue = this.get_value();
		this._set_value_internal(value, text);

		if (!this.__overrideCellUpdate)
			this.get_grid()._gridUtil._fireEvent(this.get_grid(), "CellValueChanged", { "cell": this, "oldValue": oldValue });
	},

	_set_value_internal: function(value, text)
	{
		value = this.__parseValue(value);
		var val = this._element.getAttribute("val");
		if (val !== null || this.get_column()._formatMethod != null || this.get_column()._get_dataFormatString())
		{
			val = Sys.Serialization.JavaScriptSerializer.serialize(value);
			if (this.get_column().get_type() == "date")
			{
				val = val.replace("\"\\/Date(", "");
				val = val.replace(")\\/\"", "");
			}
			this._element.setAttribute("val", val);
		}
		if (typeof (text) == "undefined")
			text = this.get_column()._formatValue(value);
		this.set_text(text);
	},

	__parseValue: function(value)
	{
		var column = this.get_column();
		if (column.get_nullable() && column.get_nullText() == value)
			return null;
		switch (column.get_type())
		{
			case "number":
				if (typeof (value) != "number")
				{
					/* AK 1/13/2009 Bug 12204. Culture formats. That would fix a bug, but value will have default like 2 decimals, etc. */
					/* so, it will distroy the rest of decimals or add 2 zeros to int.
					The number of decimals is defined on the server by the CultureInfo. So the customer can tackle it if s/he 
					needs to adjust the number. */
					/* VS 09/18/2009. Bug 22312: Number.parseLocale(null) raises exception */
					var val = value ? Number.parseLocale(value) : 0;
					if (isNaN(val))
						val = parseFloat(value);
					if (isNaN(value = val))
						value = 0;
				}
				break;
			case "boolean":
				if (typeof (value) != "boolean")
				{
					if (value && value.toString().toLowerCase() == "true")
						value = true;
					else
						value = false;
				}
				break;
			case "date":
				/*OK 10/23/08 9543 - typeof will return "object" for null and then the getMonth function will cause a JS error*/
				if (typeof (value) != "object" || (value != null && typeof (value.getMonth) == "undefined"))
					value = Date.parseLocale(value);
				break;
		}
		return value;
	},

	__set_overrideCellUpdate: function(val)
	{
		this.__overrideCellUpdate = val;
	},

	get_text: function()
	{
		///<summary>
		///Gets/sets the cell's text.
		///</summary>
		/* OK 10/8/2008 8685 - need to unescpase HTML special characters */
		return $util.htmlUnescapeCharacters(this._element.innerHTML);
	},
	set_text: function(value)
	{
		/* OK 10/8/2008 8685 - need to escpase HTML special characters */
		this._element.innerHTML = $util.htmlEscapeCharacters(value);

		this.get_grid()._gridUtil._fireEvent(this.get_grid(), "CellContentChanged", { "cell": this });
	},
	scrollToView: function()
	{
		///<summary>
		///Scrolls the cell into view inside of the grid's internal container element.
		///</summary>
		var grid = this.get_grid();
		var elem = this.get_element();
		var cellPos = $util.getPosition(elem);
		var cellRect = { x: (cellPos.x - cellPos.scrollX), y: (cellPos.y - cellPos.scrollY), width: elem.offsetWidth, height: elem.offsetHeight };
		var cntrPos = $util.getPosition(grid._container);
		var cntrRect = { x: (cntrPos.x - cntrPos.scrollX), y: (cntrPos.y - cntrPos.scrollY), width: grid._container.offsetWidth, height: grid._container.offsetHeight };
		var xAdjusted = false;
		var yAdjusted = false;
		if (cellRect.x < cntrRect.x)
		{
			grid._container.scrollLeft -= (cntrRect.x - cellRect.x);
			xAdjusted = true;
		}
		if (cellRect.y < cntrRect.y)
		{
			grid._container.scrollTop -= (cntrRect.y - cellRect.y);
			yAdjusted = true;
		}
		if (!xAdjusted && cellRect.x + cellRect.width > cntrRect.x + cntrRect.width + 1)
		{
			if (cellRect.width < grid._container.offsetWidth)
				grid._container.scrollLeft += (cellRect.x + cellRect.width - (cntrRect.x + cntrRect.width));
			else
				grid._container.scrollLeft += (cellRect.x + cntrRect.x);
		}
		if (!yAdjusted && cellRect.y + cellRect.height > cntrRect.y + cntrRect.height)
		{
			if (cellRect.height < grid._container.offsetHeight)
				grid._container.scrollTop += (cellRect.y + cellRect.height - (cntrRect.y + cntrRect.height));
			else
				grid._container.scrollTop += (cellRect.y + cntrRect.y);
		}
	}
}

$IG.GridCell.registerClass('Infragistics.Web.UI.GridCell', $IG.UIObject);

/******************************************END Cell************************************/

/******************************************CELLIDPAIR***********************************/
$IG.CellIDPair = function(rowIDPair, columnIDPair)
{
	this.rowIDPair = rowIDPair;
	this.columnIDPair = columnIDPair;
};

$IG.CellIDPair.prototype =
{
	rowIDPair: null,
	columnIDPair: null
}

// $IG.CellIDPair.registerClass('Infragistics.Web.UI.CellIDPair');
/******************************************END CELLIDPAIR***********************************/

/******************************************EVENTARGS**************************************************/

$IG.CancelAJAXResponseEventArgs = function()
{
	/// <summary>
	/// Event arguments object that is passed into the AJAXResponse event handler when the AJAX request fails. It is cancelable so the default error message can be prevented.
	/// </summary>
	$IG.CancelAJAXResponseEventArgs.initializeBase(this);
}
$IG.CancelAJAXResponseEventArgs.prototype =
{
	get_browserResponseObject: function()
	{
		/// <summary>
		/// Returns the browser's response object. The object contains information about the error.
		/// </summary>
		return this._props[0];
	},
	get_requestTimedOut: function()
	{
		/// <summary>
		/// Boolean indication whether the request is being timed out.
		/// </summary>
		return this._props[1];
	}
}
$IG.CancelAJAXResponseEventArgs.registerClass('Infragistics.Web.UI.CancelAJAXResponseEventArgs', $IG.CancelEventArgs);


$IG.AJAXResponseEventArgs = function()
{
	/// <summary>
	/// Event arguments object that is passed into the AJAXResponse event handler.
	/// </summary>
	$IG.AJAXResponseEventArgs.initializeBase(this);
}
$IG.AJAXResponseEventArgs.prototype =
{
	get_browserResponseObject: function()
	{
		/// <summary>
		/// Returns the browser's response object.
		/// </summary>
		return this._props[0];
	},
	get_gridResponseObject: function()
	{
		/// <summary>
		/// Returns the grid's response object. The objects properties are set on the server.
		/// </summary>
		return this._props[1];
	}
}
$IG.AJAXResponseEventArgs.registerClass('Infragistics.Web.UI.AJAXResponseEventArgs', $IG.EventArgs);

$IG.BrowserEventArgs = function(event)
{
	/// <summary>
	/// Event arguments object that is passed into the browser event handler when an event occurs.
	/// This event is cancelable and if it is canceled,
	/// the event will not be processed by the grid. 
	/// </summary>
	$IG.BrowserEventArgs.initializeBase(this);
	this._props[0] = event;
}
$IG.BrowserEventArgs.prototype =
{	
}
$IG.BrowserEventArgs.registerClass('Infragistics.Web.UI.BrowserEventArgs', $IG.CancelEventArgs);

$IG.ItemEventArgs = function(event, grid)
{
	/// <summary>
	/// Event arguments object that is passed into the browser event handler when an event occurs.
	/// Also if a grid's object such as cell, header, footer is availale, a reference to it is provided through
	/// the event arguments.
	/// This event is cancelable and if it is canceled,
	/// the event will not be processed by the grid. 
	/// </summary>
	$IG.ItemEventArgs.initializeBase(this, [event]);
	this._props[1] = null;
	this._props[2] = null;
	this._grid = grid;
}
$IG.ItemEventArgs.prototype =
{
	__createItemType: function()
	{
		var event = this._props[0];
		var type = "cell";
		var item = this._grid._gridUtil.getCellFromElem(event.target);
		if (!item)
		{
			item = this._grid._gridUtil.getRowFromCellElem(event.target);
			type = "row";
		}
		if (!item)
		{
			item = this._grid._gridUtil.getHeaderFromElem(event.target);
			type = "header";
		}
		if (!item)
		{
			item = this._grid._gridUtil.getFooterFromElem(event.target);
			type = "footer";
		}
		if (!item)
			type = "";
		this._props[1] = item;
		this._props[2] = type;
	},

	get_item: function()
	{
		/// <summary>
		/// Reference to the object that is associated with the event.
		/// </summary>
		if (this._props[2] == null)
			this.__createItemType();
		return this._props[1];
	},
	get_type: function()
	{
		/// <summary>
		/// Type of the object that is associated with the event.
		/// </summary>
		if (this._props[2] == null)
			this.__createItemType();
		return this._props[2];
	}
}

$IG.ItemEventArgs.registerClass('Infragistics.Web.UI.ItemEventArgs', $IG.BrowserEventArgs);

$IG.RowEventArgs = function(row)
{
	/// <summary>
	/// Event arguments object that is passed into an event handler that is related to a row.
	/// </summary>
	$IG.RowEventArgs.initializeBase(this);
	this._props[0] = row;
}
$IG.RowEventArgs.prototype =
{
	get_row: function()
	{
		return this._props[0];
	}
}
$IG.RowEventArgs.registerClass('Infragistics.Web.UI.RowEventArgs', $IG.EventArgs);

$IG.CancelRowEventArgs = function(row, context)
{
	/// <summary>
	/// Event arguments object that is passed into an event handler that is related to a row.
	/// This event is cancelable. 
	/// </summary>
	$IG.CancelRowEventArgs.initializeBase(this);
	this._props[0] = row;
	this._context = context;
}
$IG.CancelRowEventArgs.prototype =
{
	get_row: function()
	{
		return this._props[0];
	}
}
$IG.CancelRowEventArgs.registerClass('Infragistics.Web.UI.CancelRowEventArgs', $IG.CancelEventArgs);


/******************************************END EVENTARGS**********************************************/

$IG.HashTree = function()
{
	/// <summary>
	/// A simple tree stucture using Javascript objects 
	///</summary>
	$IG.HashTree.initializeBase(this);

	this._tree = {};
}
$IG.HashTree.prototype =
{
	add: function(row)
	{
		/// <summary>
		/// Adds a row object to the HashTree by it's DataKey value. 
		/// Throws exception if you attempt to add a row to the tree that shares a particular datakey value.
		/// </summary>
		if (!row) return;
		var dataKey = row.get_dataKey();
		var currentHash = this._tree;

		for (var i = 0; i < dataKey.length; i++)
		{
			var stepDataKey = dataKey[i];
			if (i < dataKey.length - 1)
			{
				if (currentHash[stepDataKey] == null)
				{
					currentHash = currentHash[stepDataKey] = {};
				}
				else
				{
					currentHash = currentHash[stepDataKey];
				}
			}
			else
			{
				if (currentHash[stepDataKey] == null)
				{
					currentHash[stepDataKey] = row;
				}
				else
				{
					throw "Rows must have unique DataKeys. This key appears more than once: " + dataKey;
				}
			}
		}
	},
	remove: function(row)
	{
		/// <summary>
		/// Removes a row object from the HashTree
		/// </summary>
		/// <returns>0 if the row is removed from the collection, -1 if the row could not be found </returns>
		if (!row) return;
		var dataKey = row.get_dataKey();
		var currentHash = this._tree;

		for (var i = 0; i < dataKey.length; i++)
		{
			var stepDataKey = dataKey[i];
			if (i < dataKey.length - 1)
			{
				if (this._tree[stepDataKey] == null)
				{
					return 1; // if we don't find a part of the hash for now just return 1 indicating error				
				}
				else
				{
					currentHash = this._tree[stepDataKey];
				}
			}
			else
			{
				if (currentHash && currentHash[stepDataKey] != null)
				{
					/* VS 07/06/2009. Bug 18405. Removed validations for element and its type */
					delete currentHash[stepDataKey];
					return 0;
				}
				return -1;
			}
		}
		return -1;
	},
	contains: function(row)
	{
		/// <summary>
		/// Determines if the row object is in the HashTree
		/// </summary>
		/// <returns>True if found, false otherwise</returns>
		return this.findByKey(row.get_dataKey()) != null;
	},
	findByKey: function(dataKey)
	{
		///<summary>
		/// Determines if a particular dataKey value is in the HashTree
		///</summary>
		/// <returns>the row if found, null otherwise</returns>
		if (!dataKey) return;
		var currentHash = this._tree;
		for (var i = 0; i < dataKey.length; i++)
		{
			var stepDataKey = dataKey[i];
			if (i < dataKey.length - 1)
			{
				if (this._tree[stepDataKey] == null)
				{
					return null;
				}
				else
				{
					currentHash = this._tree[stepDataKey];
				}
			}
			else
			{
				var row = currentHash[stepDataKey];
				/* VS 07/06/2009 row.get_element() can return null */
				var el = (row && row.get_element) ? row.get_element() : null;
				if (!el || el.type != "row")
				{
					row = null;
				}
				return row;
			}
		}
		return null;
	}
}
$IG.HashTree.registerClass('Infragistics.Web.UI.HashTree', $IG.ObjectBase);

/******************************************Orientation ENUM******************************/
$IG.GridDataType = function () 
{
    ///<summary>
    /// Specifies the type of data in a column of WebDataGrid.
    ///</summary>
}
$IG.GridDataType.prototype = 
{
	Unknown:-1,
	String:0,
	Double:1,
	Float:2,
	Decimal:3,
	Long:4,
	Ulong:5,
	Int:6,
	Uint:7,
	Short:8,
	Ushort:9,
	Sbyte:10,
	Byte:11,
	Date:12,
	Boolean:13,
	Char:14
};
$IG.GridDataType.registerEnum("Infragistics.Web.UI.GridDataType");
/******************************************END Orientation ENUM**************************/

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();