
$IG.Selection = function(obj, objProps, control, parentCollection, hierarchical)
{
	///<summary>
	///Selection behavior object of the grid.
	///</summary>
	$IG.Selection.initializeBase(this, [obj, objProps, control, parentCollection]);
	this._hierarchical = hierarchical;
	
	this._selectedCellCss = this._get_clientOnlyValue("sc");
	this._selectedRowSelectorCss = this._get_clientOnlyValue("sr");
	this._selectedRowSelectorImageCss = this._get_clientOnlyValue("si");
	this._selectedHeaderCss = this._get_clientOnlyValue("sh");
	this._enableHiddenSelection = this._get_clientOnlyValue("ehs");

	this._container = control._elements["container"];
	this._header = control._elements["columnHeaderRow"];
	this._gridElement = control._element;

	this._containerMouseMoveHandler = Function.createDelegate(this, this._onMousemoveHandler);
	this._containerMouseDownHandler = Function.createDelegate(this, this._onMousedownHandler);
	this._headerMouseDownHandler = Function.createDelegate(this, this._onHeaderMousedownHandler);
	this._documentMouseUpHandler = Function.createDelegate(this, this._onMouseupHandler);
	this._gridElementSelectStartHandler = Function.createDelegate(this, this._onSelectstartHandler);
	this._gridElementKeyDownHandler = Function.createDelegate(this, this._onKeydownHandler);

	this._grid._addElementEventHandler(this._container, "keydown", this._gridElementKeyDownHandler);

	this._grid._addElementEventHandler(this._container, "mousemove", this._containerMouseMoveHandler);
	this._grid._addElementEventHandler(this._container, "mousedown", this._containerMouseDownHandler);

	if (this._header != null)
	{
		if (this._header.length)
		{
			for (var i = 0; i < this._header.length; i++)
				this._grid._addElementEventHandler(this._header[i], "mousedown", this._headerMouseDownHandler);
		}
		else
			this._grid._addElementEventHandler(this._header, "mousedown", this._headerMouseDownHandler);
	}
	this._grid._addElementEventHandler(document, "mouseup", this._documentMouseUpHandler);
	//this._parentCollection._addElementEventHandler(this._gridElement, "selectstart", this._gridElementSelectStartHandler);
	this._grid._gridUtil._registerEventListener(this._grid, "SelectStartContainer", this._gridElementSelectStartHandler);

	this._mouseDown = false;

	this._rows = this._owner.get_rows();

}

$IG.Selection.prototype =
{
	/************************************PROPERTIES******************************/
	get_cellClickAction: function()
	{
		/// <summary>
		/// Returns/sets the action athat will occur when a cell is clicked on the WebDataGrid.
		/// </summary>
		return this._get_value($IG.GridSelectionProps.CellClickAction);
	},
	set_cellClickAction: function(val) { this._set_value($IG.GridSelectionProps.CellClickAction, val); },

	get_cellSelectType: function()
	{
		/// <summary>
		/// Determines how many cells can be selected at any given time.
		/// </summary>
		return this._get_value($IG.GridSelectionProps.CellSelectType);
	},
	set_cellSelectType: function(val) { this._set_value($IG.GridSelectionProps.CellSelectType, val); },

	get_rowSelectType: function()
	{
		/// <summary>
		/// Determines how many rows can be selected at any given time.
		/// </summary>
		return this._get_value($IG.GridSelectionProps.RowSelectType);
	},
	set_rowSelectType: function(val) { this._set_value($IG.GridSelectionProps.RowSelectType, val); },

	get_columnSelectType: function()
	{
		/// <summary>
		/// Determines how many columns can be selected at any given time.
		/// </summary>
		return this._get_value($IG.GridSelectionProps.ColumnSelectType);
	},
	set_columnSelectType: function(val) { this._set_value($IG.GridSelectionProps.ColumnSelectType, val); },

	get_selectedCells: function()
	{
		/// <summary>
		/// A collection of cells that are currently selected in the WebDataGrid. 
		/// To select a cell, use the Add method off of the Collection.
		/// To unselect a cell, use the Remove method off of the Collection.
		/// </summary>
		return this._selectedCellCollection;
	},
	get_selectedCellsCollections: function()
	{
		/// <summary>
		/// An array of selected cells collections which are currently selected 
		/// in WebDataGrid or in the WebHierarchicalDataGrid. 
		/// To select a cell, use the Add method off of the Collection.
		/// To unselect a cell, use the Remove method off of the Collection.
		/// </summary>

		var selectedCells = [];
		if (!this._hierarchical)
			selectedCells[selectedCells.length] = this.get_selectedCells();
		else
		{
			var mainGrid = this._grid._get_mainGrid();
			var selectedGrids = mainGrid.__selectedGridsArray;
			for (var i = 0; i < selectedGrids.length; i++)
			{
				var selGrid = ig_controls[selectedGrids[i]];
				if (selGrid)
				{
					var selection = selGrid.get_behaviors().get_selection();
					var collection = selection.get_selectedCells();
					if (collection.get_length() > 0)
						selectedCells[selectedCells.length] = collection;
				}
			}
		}
		return selectedCells;
	},
	get_selectedCellsResolved: function()
	{
		/// <summary>
		/// An array of cells that are currently selected in the WebDataGrid or the WebHierarchicalDataGrid. 		
		/// </summary>
		var selectedGrids = [];
		if (!this._hierarchical)
			selectedGrids[0] = this._grid._id;
		else
		{
			var mainGrid = this._grid._get_mainGrid();
			selectedGrids = mainGrid.__selectedGridsArray;
		}

		var selectedCells = [];
		for (var i = 0; i < selectedGrids.length; i++)
		{
			var selGrid = ig_controls[selectedGrids[i]];
			if (selGrid)
			{
				var selection = selGrid.get_behaviors().get_selection();
				var selectedCellCollection = selection.get_selectedCells();
				for (var j = 0; j < selectedCellCollection.get_length(); j++)
					selectedCells[selectedCells.length] = selectedCellCollection.getItem(j);
			}
		}
		return selectedCells;
	},
	get_selectedRows: function()
	{
		/// <summary>
		/// A collection of rows that are currently selected in the WebDataGrid. 
		/// To select a row, use the Add method off of the Collection.
		/// To unselect a row, use the Remove method off of the Collection.
		/// </summary>
		return this._selectedRowCollection;
	},
	get_selectedRowsCollections: function()
	{
		/// <summary>
		/// An array of selected rows collections which are currently selected 
		/// in WebDataGrid or in the WebHierarchicalDataGrid. 
		/// To select a row, use the Add method off of the Collection.
		/// To unselect a row, use the Remove method off of the Collection.
		/// </summary>

		var selectedRows = [];
		if (!this._hierarchical)
			selectedRows[selectedRows.length] = this.get_selectedRows();
		else
		{
			var mainGrid = this._grid._get_mainGrid();
			var selectedGrids = mainGrid.__selectedGridsArray;
			for (var i = 0; i < selectedGrids.length; i++)
			{
				var selGrid = ig_controls[selectedGrids[i]];
				if (selGrid)
				{
					var selection = selGrid.get_behaviors().get_selection();
					var collection = selection.get_selectedRows();
					if (collection.get_length() > 0)
						selectedRows[selectedRows.length] = collection;
				}
			}
		}
		return selectedRows;
	},
	get_selectedRowsResolved: function()
	{
		/// <summary>
		/// An array of rows that are currently selected in the WebDataGrid or the WebHierarchicalDataGrid. 		
		/// </summary>
		var selectedGrids = [];
		if (!this._hierarchical)
			selectedGrids[0] = this._grid._id;
		else
		{
			var mainGrid = this._grid._get_mainGrid();
			selectedGrids = mainGrid.__selectedGridsArray;
		}

		var selectedRows = [];
		for (var i = 0; i < selectedGrids.length; i++)
		{
			var selGrid = ig_controls[selectedGrids[i]];
			if (selGrid)
			{
				var selection = selGrid.get_behaviors().get_selection();
				var selectedRowsCollection = selection.get_selectedRows();
				for (var j = 0; j < selectedRowsCollection.get_length(); j++)
					selectedRows[selectedRows.length] = selectedRowsCollection.getItem(j);
			}
		}
		return selectedRows;
	},
	get_selectedColumns: function()
	{
		/// <summary>
		/// A collection of columns that are currently selected in the WebDataGrid. 
		/// To select a column, use the Add method off of the Collection.
		/// To unselect a column, use the Remove method off of the Collection.
		/// </summary>
		return this._selectedColumnCollection;
	},

	get_selectedColumnsCollections: function()
	{
		/// <summary>
		/// An array of selected columns collections which are currently selected 
		/// in WebDataGrid or in the WebHierarchicalDataGrid. 		
		/// To select a column, use the Add method off of the Collection.
		/// To unselect a column, use the Remove method off of the Collection.
		/// </summary>
		var selectedColumns = [];
		if (!this._hierarchical)
			selectedColumns[selectedColumns.length] = this.get_selectedColumns();
		else
		{
			var mainGrid = this._grid._get_mainGrid();
			var selectedGrids = mainGrid.__selectedGridsArray;
			for (var i = 0; i < selectedGrids.length; i++)
			{
				var selGrid = ig_controls[selectedGrids[i]];
				if (selGrid)
				{
					var selection = selGrid.get_behaviors().get_selection();
					var collection = selection.get_selectedColumns();
					if (collection.get_length() > 0)
						selectedColumns[selectedColumns.length] = collection;

				}
			}
		}
		return selectedColumns;
	},
	get_selectedColumnsResolved: function()
	{
		/// <summary>
		/// An array of columns that are currently selected in the WebDataGrid or the WebHierarchicalDataGrid. 		
		/// </summary>
		var selectedGrids = [];
		if (!this._hierarchical)
			selectedGrids[0] = this._grid._id;
		else
		{
			var mainGrid = this._grid._get_mainGrid();
			selectedGrids = mainGrid.__selectedGridsArray;
		}

		var selectedColumns = [];
		for (var i = 0; i < selectedGrids.length; i++)
		{
			var selGrid = ig_controls[selectedGrids[i]];
			if (selGrid)
			{
				var selection = selGrid.get_behaviors().get_selection();
				var selectedColumnsCollection = selection.get_selectedColumns();
				for (var j = 0; j < selectedColumnsCollection.get_length(); j++)
					selectedColumns[selectedColumns.length] = selectedColumnsCollection.getItem(j);
			}
		}
		return selectedColumns;
	},
	/*********************************END PROPERTIES******************************/

	/************************************EVENTHANDLERS******************************/
	_onHeaderMousedownHandler: function(evnt)
	{		
		/* OK 10/21/2009 18645 - if column resizing is happening we have to ignore the header click */
		if (evnt.button == 0 && !(this._columnResizing && this._columnResizing._isColumnResizingInProgress()))
		{
			var index = evnt.target.getAttribute("adr");
			if (index != null)
			{
				var columnSelectType = this.get_columnSelectType();

				if (columnSelectType != $IG.SelectType.None)
				{
					/* OK 4/20/2009 9961 - have to clear things when shift if held as well */
					this.__clearBasedOnCtrlKey(evnt.ctrlKey, "column");
					if (evnt.shiftKey && columnSelectType == $IG.SelectType.Multiple)
						this._selectedColumnCollection._selectRange(index, evnt.ctrlKey);
					else
						this._selectedColumnCollection._select(index, evnt.ctrlKey);
				}
			}
		}
	},

	_onMousedownHandler: function(evnt)
	{
		this._handled = null;
		if (evnt.button == 0)
		{
			var cell = this._grid._gridUtil.getCellFromElem(evnt.target);
			if (cell != null)
			{
				/* OK 9/24/2009 22304 - mouseDown needs to be set to true only if we actually clicked on a cell
				and not just somewhere in the grid. */
				this._mouseDown = true;
				if (this.get_cellClickAction() == $IG.CellClickAction.Cell)
				{
					var cellSelectType = this.get_cellSelectType();
					if (cellSelectType != $IG.SelectType.None)
					{
						var cellElem = cell.get_element();
						if (evnt.shiftKey && cellSelectType == $IG.SelectType.Multiple)
						{
							this.__clearBasedOnCtrlKey(evnt.ctrlKey, "cell");
							this._selectedCellCollection._selectRange(cell.get_index(), cellElem, evnt.ctrlKey);
						}
						else
						{
							this.__clearBasedOnCtrlKey(evnt.ctrlKey, "cell");
							var row = cell.get_row();
							this._selectedCellCollection._select(row.get_index(), cell.get_index(), cellElem, evnt.ctrlKey);
						}
						this._handled = cellElem;
					}
				}
				else
				{
					var rowSelectType = this.get_rowSelectType();
					if (rowSelectType != $IG.SelectType.None)
					{
						if (evnt.shiftKey && rowSelectType == $IG.SelectType.Multiple)
						{
							this.__clearBasedOnCtrlKey(evnt.ctrlKey, "row");
							this._selectedRowCollection._selectRange(cell.get_row(), evnt.ctrlKey);
						}
						else
						{
							this.__clearBasedOnCtrlKey(evnt.ctrlKey, "row");
							this._selectedRowCollection._select(cell.get_row(), evnt.ctrlKey);
						}
						this._handled = cell.get_element();
					}
				}
			}
		}
	},

	_onMousemoveHandler: function(evnt)
	{
		if (this._mouseDown && !evnt.ctrlKey)
		{
			var cell = this._grid._gridUtil.getCellFromElem(evnt.target);
			if (cell != null)
			{
				var cellElem = cell.get_element();
				if (this._handled == cellElem)
					return;
				if (this.get_cellClickAction() == $IG.CellClickAction.Cell && this.get_cellSelectType() == $IG.SelectType.Multiple)
					this._selectedCellCollection._selectRange(cell.get_index(), cellElem, evnt.ctrlKey);
				else if (this.get_cellClickAction() == $IG.CellClickAction.Row && this.get_rowSelectType() == $IG.SelectType.Multiple)
					this._selectedRowCollection._selectRange(cell.get_row(), evnt.ctrlKey);
				this._handled = cellElem;
			}
		}
	},

	_onKeydownHandler: function(evnt)
	{
		if (this._activation != null)
		{
			var key = evnt.keyCode;
			if (key == Sys.UI.Key.space)
			{
				var cell = this._activation.get_activeCell();
				if (cell != null)
				{
					if (this.get_cellSelectType() == $IG.SelectType.Multiple)
					{
						this.__clearBasedOnCtrlKey(evnt.ctrlKey, "cell");
						var row = cell.get_row();
						this._selectedCellCollection._select(row.get_index(), cell.get_index(), cell.get_element(), evnt.ctrlKey);
					}

					if (this.get_rowSelectType() == $IG.SelectType.Multiple)
					{
						this.__clearBasedOnCtrlKey(evnt.ctrlKey, "row");
						this._selectedRowCollection._select(cell.get_row(), evnt.ctrlKey);
					}
				}
			}
		}
	},

	_activeCellChanged: function(args)
	{
		var cell = args.cell;
		var cellSelectType = this.get_cellSelectType();
		var rowSelectType = this.get_rowSelectType();
		var cellClickAction = this.get_cellClickAction();
		var cancelUpdateCellSelection = (cellClickAction != $IG.CellClickAction.Cell && args.howInvoked == "mousedown") || (args.howInvoked == "rowSelector");
		var cancelUpdateRowSelection = (cellClickAction != $IG.CellClickAction.Row && args.howInvoked == "mousedown") || (args.howInvoked == "rowSelector");
		if (cell)
		{
			if (cellSelectType != $IG.SelectType.None && !cancelUpdateCellSelection)
			{
				if (cellSelectType == $IG.SelectType.Single || ((!args.shiftKey && !args.ctrlKey) && !args.rowCollapsing))
				{
					var row = cell.get_row();
					this._selectedCellCollection._select(row.get_index(), cell.get_index(), cell.get_element(), false);
				}
				else if (cellSelectType == $IG.SelectType.Multiple)
				{
					if (cellClickAction == $IG.CellClickAction.Cell && args.howInvoked == "mousedown")
						return;

					if (args.shiftKey)
					{
						this._selectedCellCollection._selectRange(cell.get_index(), cell.get_element(), args.ctrlKey);
					}
				}
			}

			if (rowSelectType != $IG.SelectType.None && !cancelUpdateRowSelection)
			{
				var row = cell.get_row();
				if (rowSelectType == $IG.SelectType.Single || (!args.shiftKey && !args.ctrlKey && !args.rowCollapsing))
				{
					this._selectedRowCollection._select(row, false);
				}
				else if (rowSelectType == $IG.SelectType.Multiple)
				{
					if (cellClickAction == $IG.CellClickAction.Row && args.howInvoked == "mousedown")
						return;

					if (args.shiftKey)
					{
						this._selectedRowCollection._selectRange(row, args.ctrlKey);
					}
				}
			}
		}
	},

	_onMouseupHandler: function(evnt)
	{
		this._mouseDown = false;
		this._handled = null;
	},

	_onSelectstartHandler: function(evnt)
	{
		var cell = this._grid._gridUtil.getCellFromElem(evnt.target);
		if (cell != null)
			$util.cancelEvent(evnt);
	},

	_rowSelectorClicked: function(args)
	{
		var evnt = args.evnt;
		var row = args.row;
		var rowSelectType = this.get_rowSelectType();

		if (rowSelectType != $IG.SelectType.None)
		{
			if (evnt.shiftKey && rowSelectType == $IG.SelectType.Multiple)
			{
				this.__clearBasedOnCtrlKey(evnt.ctrlKey, "row");
				this._selectedRowCollection._selectRange(row, args.ctrlKey);
			}
			else
			{
				this.__clearBasedOnCtrlKey(evnt.ctrlKey, "row");
				this._selectedRowCollection._select(row, evnt.ctrlKey);
			}
			var column = this._grid._gridUtil._findFirstVisibleColumn();
			if (column)
			{
				var firstCellIndex = column.get_index();
				this._handled = row.get_cell(firstCellIndex).get_element();
			}
		}
	},
	addInternalColumnSelectionChangingHandler: function(handler)
	{
		this._grid._gridUtil._registerEventListener(this, "_SelectedColumnChanging", handler);
	},
	/*******************************END EVENTHANDLERS******************************/

	/*******************************PRIVATE METHODS *******************************/
	__clearAll: function()
	{
		this._selectedCellCollection._onClear();
		this._selectedRowCollection._onClear();
		this._selectedColumnCollection._onClear();
	},

	__clearBasedOnCtrlKey: function(ctrlKey, type)
	{
		if (!ctrlKey)
		{
			if (type == "cell")
			{
				this._selectedRowCollection._onClear();
				this._selectedColumnCollection._onClear();
			}
			else if (type == "row")
			{
				this._selectedCellCollection._onClear();
				this._selectedColumnCollection._onClear();
			}
			else if (type == "column")
			{
				this._selectedCellCollection._onClear();
				this._selectedRowCollection._onClear();
			}

		}
		else
		{
			/* D.M. Bug 9961 11/7/2008 - When using single selection on either rows, columns, or cells, you should not be able
			to have multiple elements selected while an element with SelectType.Single is also selected. */
			if (type == "cell")
			{
				if (this.get_columnSelectType() == $IG.SelectType.Single)
					this._selectedColumnCollection._onClear();
				if (this.get_rowSelectType() == $IG.SelectType.Single)
					this._selectedRowCollection._onClear();
				if (this.get_cellSelectType() == $IG.SelectType.Single)
				{
					this._selectedColumnCollection._onClear();
					this._selectedRowCollection._onClear();
				}
			}
			else if (type == "row")
			{
				if (this.get_cellSelectType() == $IG.SelectType.Single)
					this._selectedCellCollection._onClear();
				if (this.get_columnSelectType() == $IG.SelectType.Single)
					this._selectedColumnCollection._onClear();
				if (this.get_rowSelectType() == $IG.SelectType.Single)
				{
					this._selectedColumnCollection._onClear();
					this._selectedCellCollection._onClear();
				}
			}
			else if (type == "column")
			{
				if (this.get_cellSelectType() == $IG.SelectType.Single)
					this._selectedCellCollection._onClear();
				if (this.get_rowSelectType() == $IG.SelectType.Single)
					this._selectedRowCollection._onClear();
				if (this.get_columnSelectType() == $IG.SelectType.Single)
				{
					this._selectedRowCollection._onClear();
					this._selectedCellCollection._onClear();
				}
			}

		}
	},
	/*******************************END PRIVATE METHODS ***************************/

	/*******************************OVERRIDES**************************************/
	_initializeComplete: function()
	{
		this._rowSelectors = this._parentCollection.getBehaviorFromInterface($IG.IRowSelectorsBehavior);
		if (this._rowSelectors)
			this._rowSelectors.addRowSelectorClickedEventHandler(Function.createDelegate(this, this._rowSelectorClicked));

		this._selectedRowCollection = new $IG.GridSelectedRowCollection(this._selectedCellCss, this, $IG.GridSelectionProps.SelectedRows, this._rows, this._hierarchical);
		this._selectedCellCollection = new $IG.GridSelectedCellCollection(this._selectedCellCss, this, $IG.GridSelectionProps.SelectedCells, this._rows, this._hierarchical);
		this._selectedColumnCollection = new $IG.GridSelectedColumnCollection(this._selectedCellCss, this, $IG.GridSelectionProps.SelectedColumns, this._rows, this._hierarchical);

		if (this._hierarchical && (this.get_selectedRows().get_length() > 0 ||
			this.get_selectedColumns().get_length() > 0 || this.get_selectedCells().get_length() > 0))
		{
			var mainGrid = this._grid._get_mainGrid();
			mainGrid._registerSlectedGrid(this._grid);
		}
		this._activation = this._grid.get_behaviors().getBehaviorFromInterface($IG.IActivationBehavior);
		if (this._activation)
			this._activation._addActiveCellChangedEventHandler(Function.createDelegate(this, this._activeCellChanged));
		this._columnResizing = this._grid.get_behaviors().getBehaviorFromInterface($IG.IColumnResizingBehavior);
	},

	dispose: function()
	{
		if (!this._grid)
			return;
		this._grid._removeElementEventHandler(this._container, "mousemove", this._containerMouseMoveHandler);
		this._grid._removeElementEventHandler(this._container, "mousedown", this._containerMouseDownHandler);
		if (this._header != null)
			this._grid._removeElementEventHandler(this._header, "mousedown", this._headerMouseDownHandler);
		this._grid._removeElementEventHandler(document, "mouseup", this._documentMouseUpHandler);
		//this._parentCollection._removeElementEventHandler(this._gridElement, "selectstart", this._gridElementSelectStartHandler);
		this._grid._gridUtil._unregisterEventListener(this._grid, "SelectStartContainer", this._gridElementSelectStartHandler);
		this._gridElementSelectStartHandler = null;
		$IG.Selection.callBaseMethod(this, "dispose");
	}
	/*******************************END OVERRIDES**************************************/
}
$IG.Selection.registerClass('Infragistics.Web.UI.Selection', $IG.GridBehavior, $IG.ISelectionBehavior);


/******************************GRID SELECTION COLLECTION *****************************/
$IG.GridSelectionCollection = function(selectedCssClass, owner, enumVal, rows, hierarchical)
{
	///<summary>
	///Base class for selected object collections in the grid.
	///</summary>
	this._hierarchical = hierarchical;
	this._selectedCssClass = selectedCssClass;
	this._ht = {};
	this._owner = owner;
	this._enumVal = enumVal
	var keys = owner._get_value(enumVal);
	if (keys == null)
		this._keys = [];
	else
		this._keys = Array.clone(keys);

	this._rows = rows;
	this._grid = this._owner._owner;
	this._util = this._grid._gridUtil;
}

$IG.GridSelectionCollection.prototype =
{
	add: function(item)
	{
		///<summary>
		///Selects the specified item.
		///</summary>
		///<param name="item">The item to select.</param>
	},

	addRange: function(items)
	{
		///<summary>
		///Selects all specified items.
		///</summary>
		///<param name="items">A javascript array of items to select.</param>
		if (items != null && items.length > 0)
		{
			for (var i = 0; i < items.length; i++)
				this.add(items[i]);
		}
	},

	remove: function(item)
	{
		///<summary>
		///Unselects the specified item.
		///</summary>
		///<param name="item">The item to unselect.</param>
	},

	indexOf: function(item)
	{
		///<summary>
		///Find the index of the specified item. 
		///</summary>
		///<param name="item">The item whose index should be returned</param>
		///<returns integer="true">If item isn't in the collection -1 is returned, other wise the index of the item is returned.</returns>
		return -1;
	},

	clear: function()
	{
		///<summary>
		///Unselects all items.
		///</summary>
		this._updateCSM();
	},

	get_length: function()
	{
		///<summary>
		///Returns the amount of items that are currently selected.
		///</summary>
		return this._keys.length;
	},

	getItem: function(index)
	{
		///<summary>
		///Returns the item at the specified index.
		///</summary>
		///<param name="index">The index to look for an item.</param>
		///<returns>Returns the item at the specified index, or null if no item exists at that index.</returns>
	},

	_get_selectType: function() { },

	_findElem: function() { return null; },

	_select: function(param1, param2, param3, param4)
	{
		this._onSelect(param1, param2, param3, param4);
		this._updateCSM();
	},

	_onSelect: function() { },
	_internalSelect: function() { },

	_unselect: function(param1, param2, param3)
	{
		this._internalUnselect(param1, param2, param3);
		this._updateCSM();
	},

	_internalUnselect: function() { },
	_onSelectRange: function()
	{
		this._updateCSM();
	},

	_selectRange: function(param1, param2, param3, param4)
	{
		this._onSelectRange(param1, param2, param3, param4);
	},

	_internalSelectRange: function() { },

	_updateCSM: function()
	{
		this._owner._set_value(this._enumVal, this._keys);
	},

	_findRowObjFromIndex: function(rowIndex)
	{
		return this._rows.get_row(rowIndex, true);
	},

	__registerSelectedGrid: function(ctrlKey, type)
	{		
		if (this._hierarchical)
		{
			var mainGrid = this._grid._get_mainGrid();
			if (this._keys.length > 0)
			{				
				if (ctrlKey !== undefined)
				{
					var selectedGrids = Array.clone(mainGrid.__selectedGridsArray);
					var gridId = this._grid._id;
					for (var i = 0; i < selectedGrids.length; i++)
					{
						var selGridId = selectedGrids[i];
						if (selGridId != gridId)
						{
							var selGrid = ig_controls[selGridId];
							if (selGrid)
							{
								var selection = selGrid.get_behaviors().get_selection();
								if (!ctrlKey)
								{
									selection.__clearAll(true);
									mainGrid._unregisterSelectedGrid(selGrid);
								}
								else
								{
									selection.__clearBasedOnCtrlKey(ctrlKey, type);
									if (this._get_selectType() == $IG.SelectType.Single)
									{
										if (type == "cell")
											selection.get_selectedCells()._onClear();
										else if (type == "row")
											selection.get_selectedRows()._onClear();
										else if (type == "column")
											selection.get_selectedColumns()._onClear();
									}
									if (selection.get_selectedRows().get_length() == 0 &&
										selection.get_selectedColumns().get_length() == 0 &&
										selection.get_selectedCells().get_length() == 0)
									{
										mainGrid._unregisterSelectedGrid(selGrid);
									}
								}							

							}
						}					
					}	
				}			
				mainGrid._registerSlectedGrid(this._grid);
			}
			else
				mainGrid._unregisterSlectedGrid(this._grid);
		}
	}
}
$IG.GridSelectionCollection.registerClass('Infragistics.Web.UI.GridSelectionCollection');

/******************************END GRID SELECTION COLLECTION ***************************/

/******************************GRID SELECTED CELL COLLECTION *****************************/
$IG.GridSelectedCellCollection = function(selectedCssClass, owner, enumVal, rows, hierarchical)
{
	///<summary>
	///Selected cells collection. Manipulating with the items of this collection means selecting/unselecting cells in the grid.
	///</summary>
	$IG.GridSelectedCellCollection.initializeBase(this, [selectedCssClass, owner, enumVal, rows, hierarchical]);
	this._elems = [];
	this._rowElemCache = [];
	
	this._srCss = this._owner._selectedRowSelectorCss;
	this._siCss = this._owner._selectedRowSelectorImageCss;
	this._rs = this._owner._rowSelectors;

	for (var i in this._keys)
	{
		if (!isNaN(parseInt(i)))
		{
			var indexes = this._keys[i];
			var row = this._rows.get_rowFromIDPair(indexes[0]);
			if (row != null)
			{
				var elem = this._findElem(row.get_index(), indexes[1]);
				this._elems.push(elem);
				elem._igcs = true;

				if (this._rs)
					this._rs._incrementSelectedCellCount(row, this._siCss, this._srCss);
			}
		}
	}
}

$IG.GridSelectedCellCollection.prototype =
{
	add: function(obj)
	{
		if (!obj)
			return;

		var elem = obj.get_element();
		var rowIndex = this._util.findRowIndexByCellElem(elem);
		this._internalSelect(rowIndex, obj.get_index(), elem);
		this._updateCSM();
	},

	remove: function(obj)
	{
		if (!obj)
			return;

		var elem = obj.get_element();
		var index = Array.indexOf(this._elems, elem);
		if (index >= 0)
		{
			this._internalUnselect(index);
			while (Array.remove(this._elems, null));
			while (Array.remove(this._keys, null));
		}
		this._updateCSM();
	},

	indexOf: function(obj)
	{
		if (!obj)
			return;

		var elem = obj.get_element();
		return Array.indexOf(this._elems, elem);
	},

	clear: function()
	{
		for (var i in this._elems)
			if (!isNaN(parseInt(i)))
			this._internalUnselect(i);

		while (Array.remove(this._elems, null));
		while (Array.remove(this._keys, null));
		$IG.GridSelectedCellCollection.callBaseMethod(this, 'clear');
	},

	_get_selectType: function()
	{
		return this._owner.get_cellSelectType();
	},

	_onClear: function()
	{
		if (this._keys.length > 0)
		{
			/* AK 7/22/09 18039: Is that needed here? Seems to be toomuch of the event firing*/			
			var args = this._owner.__raiseClientEvent("CellSelectionChanging", $IG.CellSelectionChangingEventArgs, [this._rows, this._keys, []]);
			if (args == null || !args.get_cancel())
			{
				this.clear();

				var event = this._owner._clientEvents.CellSelectionChanged;
				if (event && event.postBack == 0)
					this._owner.__raiseClientEvent("CellSelectionChanged", $IG.CellSelectionChangedEventArgs, [this._owner, this, true]);
			}
			this.clear();
		}
	},

	getItem: function(index)
	{
		var obj = null;
		var key = this._keys[index];
		if (key != null)
		{
			var rowObj = this._rows.get_rowFromIDPair(key[0]);
			obj = rowObj.get_cell(key[1]);
		}
		return obj;
	},

	_internalUnselect: function(index)
	{
		var rowObj = this._owner._grid._gridUtil.getRowFromCellElem(this._elems[index]);
		$util.removeCompoundClass(this._elems[index], this._selectedCssClass);
		this._elems[index]._igcs = false;
		this._elems[index] = null;
		this._keys[index] = null;

		if (this._rs)
			this._rs._decrementSelectedCellCount(rowObj, this._siCss, this._srCss); /* OK 6/12/2009 18370 - RowSelectors don't keep appropriate selected image when dragging to select cells */
	},

	_onSelect: function(rowIndex, cellIndex, elem, ctrlKey)
	{
		var isSelected = elem._igcs; //(elem.className.indexOf(this._selectedCssClass) != -1);
		rowIndex = parseInt(rowIndex);
		/*
		DK 2 Oct 2008
		Bug 8499 : JS error on "aux" rows when selection is turned on
		when the row index is negative we have a 'special' row, we don't select that.
		*/
		if (rowIndex < 0) return;

		if (!isSelected || !ctrlKey)
		{
			if (isSelected && this._keys.length == 1)
				return;
			var newKeys = [];
			if (ctrlKey && this._get_selectType() == $IG.SelectType.Multiple)
				newKeys = Array.clone(this._keys);
			newKeys.push([this._findRowObjFromIndex(rowIndex).get_idPair(), cellIndex]);
			var args = this._owner.__raiseClientEvent("CellSelectionChanging", $IG.CellSelectionChangingEventArgs, [this._rows, this._keys, newKeys]);
			if (args == null || !args.get_cancel())
			{
				if (!ctrlKey || this._get_selectType() == $IG.SelectType.Single)
					this.clear();
				this._internalSelect(rowIndex, cellIndex, elem, ctrlKey);

				this._owner.__raiseClientEvent("CellSelectionChanged", $IG.CellSelectionChangedEventArgs, [this._owner, this, true]);
			}
		}
		else if (isSelected && ctrlKey)
		{
			var count = this._keys.length;
			for (var i = 0; i < count; i++)
			{
				var row = this._rows.get_rowFromIDPair(this._keys[i][0]);
				if (row.get_index() == rowIndex && this._keys[i][1] == cellIndex)
				{
					var newKeys = Array.clone(this._keys);
					Array.removeAt(newKeys, i)
					var args = this._owner.__raiseClientEvent("CellSelectionChanging", $IG.CellSelectionChangingEventArgs, [this._rows, this._keys, newKeys]);
					if (args == null || !args.get_cancel())
					{
						this._internalUnselect(i);
						while (Array.remove(this._elems, null));
						while (Array.remove(this._keys, null));

						this._owner.__raiseClientEvent("CellSelectionChanged", $IG.CellSelectionChangedEventArgs, [this._owner, this, true]);
					}					
					return;
				}
			}
		}		
	},

	_internalSelect: function(rowIndex, cellIndex, elem, ctrlKey)
	{
		if (rowIndex == -1) // Ignore Aux. Rows
			return;
		// SJZ - Using an attribute on an element is more reliable b/c the user might have cell and row selection on
		// and since they both use the same cssClass this case may fail. 	
		if (!elem._igcs)//elem.className.indexOf(this._selectedCssClass) == -1)
		{
			var row = this._findRowObjFromIndex(rowIndex);
			var idPair = row.get_idPair();
			this._ht["r" + rowIndex + "c" + cellIndex] = elem;
			this._elems.push(elem);
			elem.className += " " + this._selectedCssClass;
			elem._igcs = true;
			this._keys.push([idPair, cellIndex]);

			if (this._rs)
				this._rs._incrementSelectedCellCount(row, this._siCss, this._srCss); /* OK 6/12/2009 18370 - RowSelectors don't keep appropriate selected image when dragging to select cells */
		}
		this.__registerSelectedGrid(ctrlKey, "cell");
	},

	_onSelectRange: function(cellIndex, cellElem, ctrlKey)
	{
		var rowIndex = this._util.findRowIndexByCellElem(cellElem);
		var args = this._owner.__raiseClientEvent("CellSelectionChanging", $IG.CellSelectionChangingEventArgs, [this._rows, this._keys, null, cellIndex, rowIndex]);
		if (args == null || !args.get_cancel())
		{
			this._internalSelectRange(cellIndex, cellElem, ctrlKey);

			$IG.GridSelectedCellCollection.callBaseMethod(this, "_onSelectRange", [cellIndex, cellElem]);

			this._owner.__raiseClientEvent("CellSelectionChanged", $IG.CellSelectionChangedEventArgs, [this._owner, this, true]);
		}
	},

	_internalSelectRange: function(cellIndex, cellElem, ctrlKey)
	{
		var startCell = null;
		var startRow = 0;
		if (this._keys.length > 0)
		{
			var row = this._rows.get_rowFromIDPair(this._keys[0][0]);
			if (row != null)
				startRow = row.get_index();
			startCell = this._keys[0][1];
		}
		else
		{
			var rowIndex = this._util.findRowIndexByCellElem(cellElem);
			this._internalSelect(rowIndex, cellIndex, cellElem, ctrlKey);
			return;
		}

		var endCell = parseInt(cellIndex);
		var endRow = parseInt(this._util.findRowIndexByCellElem(cellElem));

		// converting the startCell and endCell indecies to visible indecies
		var startCellVisibleIdx = null;
		var endCellVisibleIdx = null;
		if (startCell != null)
			startCellVisibleIdx = this._grid.get_columns().get_column(startCell).get_visibleIndex();
		if (endCell != null)
			endCellVisibleIdx = this._grid.get_columns().get_column(endCell).get_visibleIndex();

		if (startCellVisibleIdx != null && endCellVisibleIdx != null && startCellVisibleIdx > endCellVisibleIdx)
		{
			var endIdx = endCellVisibleIdx;
			endCellVisibleIdx = startCellVisibleIdx;
			startCellVisibleIdx = endIdx;
		}
		if (endRow < startRow)
		{
			var endR = endRow;
			endRow = startRow;
			startRow = endR;
		}
		for (var i in this._keys)
		{
			if (!isNaN(parseInt(i)))
			{
				var key = this._keys[i];
				var rowObj = this._rows.get_rowFromIDPair(key[0]);
				if (rowObj != null)
				{
					var row = rowObj.get_index();
					var cell = this._grid.get_columns().get_column(key[1]).get_visibleIndex();
					if (row < startRow || row > endRow)
						this._internalUnselect(i);
					else if (cell < startCellVisibleIdx || cell > endCellVisibleIdx)
						this._internalUnselect(i);
				}
			}
		}
		while (Array.remove(this._elems, null));
		while (Array.remove(this._keys, null));

		for (var i = startRow; i <= endRow; i++)
		{
			for (var j = startCellVisibleIdx; j <= endCellVisibleIdx; j++)
			{
				var column = this._util._getColumnFromVisibleIndex(j);
				if (this._owner._enableHiddenSelection || !column.get_hidden())
				{
					var adr = column.get_index();
					var elem = this._findElem(i, adr);
					this._internalSelect(i, adr, elem, ctrlKey);
				}
			}
		}
	},


	_findElem: function(rowIndex, cellIndex)
	{
		var elem = this._ht["r" + rowIndex + "c" + cellIndex];
		if (!elem)
		{
			var rowObj = this._findRowObjFromIndex(rowIndex);
			var visibleIndex = this._grid.get_columns().get_column(cellIndex).get_visibleIndex();
			this._ht["r" + rowIndex + "c" + cellIndex] = elem = this._util.getCellElemFromIndex(rowObj, visibleIndex);
		}
		return elem;
	}
}
$IG.GridSelectedCellCollection.registerClass('Infragistics.Web.UI.GridSelectedCellCollection', $IG.GridSelectionCollection);
/******************************END GRID SELECTED CELL COLLECTION ***************************/

/******************************GRID SELECTED ROW COLLECTION *****************************/
$IG.GridSelectedRowCollection = function(selectedCssClass, owner, enumVal, rows, hierarchical)
{
	///<summary>
	///Selected rows collection. Manipulating with the items of this collection means selecting/unselecting rows in the grid.
	///</summary>
	$IG.GridSelectedRowCollection.initializeBase(this, [selectedCssClass, owner, enumVal, rows, hierarchical]);

	this._srCss = this._owner._selectedRowSelectorCss;
	this._siCss = this._owner._selectedRowSelectorImageCss;
	this._rs = this._owner._rowSelectors;


	for (var i in this._keys)
	{
		if (!isNaN(parseInt(i)))
		{
			var row = this._resolveRowFromKeyIndex(i)
			if(row != null)
				this._ht[row.get_index()] = true;
		}
	}
}

$IG.GridSelectedRowCollection.prototype =
{
	add: function(obj)
	{
		if (!obj)
			return;

		this._internalSelect(obj);
		this._updateCSM();
	},

	remove: function(obj)
	{
		if (!obj)
			return;

		var index = this.indexOf(obj);
		if (index >= 0)
		{
			this._internalUnselect(index);
			while (Array.remove(this._keys, null));
		}
		this._updateCSM();
	},

	indexOf: function(obj)
	{
		if (!obj)
			return -1;

		for (var i in this._keys)
		{
			if (!isNaN(parseInt(i)))
			{
				if (obj == this._resolveRowFromKeyIndex(i))
					return i;
			}
		}

		return -1;
	},

	clear: function()
	{
		for (var i in this._keys)
			if (!isNaN(parseInt(i)))
			this._internalUnselect(i);

		while (Array.remove(this._keys, null));
		$IG.GridSelectedRowCollection.callBaseMethod(this, 'clear');
	},

	_get_selectType: function()
	{
		return this._owner.get_rowSelectType();
	},

	_onClear: function()
	{
		if (this._keys.length > 0)
		{
			
			/* AK 7/22/09 18039: Is that needed here? Seems to be toomuch of the event firing*/			
			var args = this._owner.__raiseClientEvent("RowSelectionChanging", $IG.RowSelectionChangingEventArgs, [this._rows, this._keys, []]);
			if (args == null || !args.get_cancel())
			{
				this.clear();
				var event = this._owner._clientEvents.RowSelectionChanged;
				if (event && event.postBack == 0)
					this._owner.__raiseClientEvent("RowSelectionChanged", $IG.RowSelectionChangedEventArgs, [this._owner, this, true]);
			}
			
			this.clear();
		}
	},

	getItem: function(index)
	{
		return this._resolveRowFromKeyIndex(index);
	},

	_internalUnselect: function(index)
	{
		var rowObj = this._resolveRowFromKeyIndex(index);
		var cellCount = rowObj.get_cellCount();
		var cellOffset = this._grid._get_cellIndexOffset();

		for (var j = cellOffset; j < cellOffset + cellCount; j++)
			$util.removeCompoundClass(rowObj._get_cellElementByIndex(rowObj.get_element(), j), this._selectedCssClass);

		if (this._rs)
		{
			this._rs.removeSelectorImage(rowObj, this._siCss);
			this._rs.removeSelectorClass(rowObj, this._srCss);
		}
		var row = this._resolveRowFromKeyIndex(index);
		if (row != null)
			this._ht[row.get_index()] = null;
		this._keys[index] = null;
	},

	_onSelect: function(rowObj, ctrlKey)
	{
		var key = parseInt(rowObj.get_index());
		var isSelected = this._ht[key];
		if (!isSelected || !ctrlKey)
		{
			if (isSelected && this._keys.length == 1)
				return;
			var newKeys = [];
			if (ctrlKey && this._get_selectType() == $IG.SelectType.Multiple)
				newKeys = Array.clone(this._keys);
			newKeys.push(rowObj.get_idPair());
			var args = this._owner.__raiseClientEvent("RowSelectionChanging", $IG.RowSelectionChangingEventArgs, [this._rows, this._keys, newKeys]);
			if (args == null || !args.get_cancel())
			{
				if (!ctrlKey || this._get_selectType() == $IG.SelectType.Single)
					this.clear();
				this._internalSelect(rowObj, ctrlKey);
				this._owner.__raiseClientEvent("RowSelectionChanged", $IG.RowSelectionChangedEventArgs, [this._owner, this, true]);
			}
		}
		else if (isSelected && ctrlKey)
		{
			var count = this._keys.length;
			for (var i = 0; i < count; i++)
			{
				var row = this._resolveRowFromKeyIndex(i);
				if (row != null)
				{
					if (row.get_index() == key)
					{
						var newKeys = Array.clone(this._keys);
						Array.removeAt(newKeys, i)
						var args = this._owner.__raiseClientEvent("RowSelectionChanging", $IG.RowSelectionChangingEventArgs, [this._rows, this._keys, newKeys]);
						if (args == null || !args.get_cancel())
						{
							this._internalUnselect(i);
							while (Array.remove(this._keys, null));
							this._owner.__raiseClientEvent("RowSelectionChanged", $IG.RowSelectionChangedEventArgs, [this._owner, this, true]);
						}
						return;
					}
				}
			}
		}
	},

	_internalSelect: function(rowObj, ctrlKey)
	{
		//D.M. Don't select auxillary rows.
		if (this._grid._get_auxRowIndex(rowObj, null) != -1 || rowObj == null)
			return;

		//D.M. If there's no activation we should focus on the grid.
		/* OK 10/26/2009 24213 - have to make sure that the grid is not hidden by checking the offsetWidth .*/
		if (!this._owner._activation && this._grid._element.offsetWidth > 0)
			this._grid._element.focus();

		var key = parseInt(rowObj.get_index());
		if (!this._ht[key])
		{
			var cellCount = rowObj.get_cellCount();
			var cellOffset = this._grid._get_cellIndexOffset();
			for (var j = cellOffset; j < cellOffset + cellCount; j++)
				rowObj._get_cellElementByIndex(rowObj.get_element(), j).className += " " + this._selectedCssClass;

			if (this._rs)
			{
				this._rs.addSelectorImage(rowObj, this._siCss);
				this._rs.addSelectorClass(rowObj, this._srCss);
			}

			this._keys.push(rowObj.get_idPair());
			this._ht[key] = true;
		}
		this.__registerSelectedGrid(ctrlKey, "row");
	},

	_onSelectRange: function(rowObj, ctrlKey)
	{
		var args = this._owner.__raiseClientEvent("RowSelectionChanging", $IG.RowSelectionChangingEventArgs, [this._rows, this._keys, null, rowObj]);
		if (args == null || !args.get_cancel())
		{
			this._internalSelectRange(rowObj, ctrlKey);

			$IG.GridSelectedRowCollection.callBaseMethod(this, "_onSelectRange", [rowObj]);

			this._owner.__raiseClientEvent("RowSelectionChanged", $IG.RowSelectionChangedEventArgs, [this._owner, this, true]);
		}
	},

	_internalSelectRange: function(rowObj, ctrlKey)
	{
		var startRow = 0;
		if (this._keys.length > 0)
		{
			var row = this._resolveRowFromKeyIndex(0);
			if (row != null)
				startRow = row.get_index();
		}
		else
		{
			this._internalSelect(rowObj, ctrlKey);
			return;
		}

		var endRow = parseInt(rowObj.get_index());

		for (var i in this._keys)
		{
			if (!isNaN(parseInt(i)))
			{
				var row = this._resolveRowFromKeyIndex(i);
				if (row != null)
				{
					var key = row.get_index();
					if (key < startRow || key > endRow)
						this._internalUnselect(i);
				}
			}
		}
		while (Array.remove(this._keys, null));

		if (startRow == endRow)
			this._internalSelect(this._rows.get_row(startRow), ctrlKey);
		else if (startRow < endRow)
		{
			for (var i = startRow; i <= endRow; i++)
				this._internalSelect(this._rows.get_row(i, true), ctrlKey);
		}
		else
		{
			for (var i = startRow; i >= endRow; i--)
				this._internalSelect(this._rows.get_row(i, true), ctrlKey);
		}
	},

	_resolveRowFromKeyIndex: function(index)
	{
		/*
		DK 6 Oct 2008
		get_rowFromIDPair woudl null ref out if you passed in a bad key.  So lets 
		not pass in a bad key.
		*/
		var key = this._keys[index];
		if (key)
			return this._rows.get_rowFromIDPair(key);
		return null;
	}
}
$IG.GridSelectedRowCollection.registerClass('Infragistics.Web.UI.GridSelectedRowCollection', $IG.GridSelectionCollection);
/******************************END GRID SELECTED ROW COLLECTION ***************************/

/******************************GRID SELECTED COLUMN COLLECTION *****************************/
$IG.GridSelectedColumnCollection = function(selectedCssClass, owner, enumVal, rows, hierarchical)
{
	///<summary>
	///Selected columns collection. Manipulating with the items of this collection means selecting/unselecting columns in the grid.
	///</summary>
	$IG.GridSelectedColumnCollection.initializeBase(this, [selectedCssClass, owner, enumVal, rows, hierarchical]);

	this._sh = this._owner._selectedHeaderCss;

	for (var i in this._keys)
	{
		if (!isNaN(parseInt(i)))
		{
			this._ht[this._keys[i]] = true;
		}
	}
}

$IG.GridSelectedColumnCollection.prototype =
{
	add: function(obj)
	{
		if (!obj)
			return;

		this._internalSelect(parseInt(obj.get_index()));
		this._updateCSM();
	},

	remove: function(obj)
	{
		if (!obj)
			return;

		var length = this._rows.get_length();
		var key = parseInt(obj.get_index());
		var index = Array.indexOf(this._keys, key);
		if (index >= 0)
		{
			this._internalUnselect(index, length);
			while (Array.remove(this._keys, null));
		}
		this._updateCSM();
	},

	indexOf: function(obj)
	{
		if (!obj)
			return;

		var key = parseInt(obj.get_index());
		return Array.indexOf(this._keys, key);
	},

	clear: function()
	{
		var rowCount = this._rows.get_length();
		for (var i in this._keys)
			if (!isNaN(parseInt(i)))
			this._internalUnselect(i, rowCount);

		while (Array.remove(this._keys, null));

		$IG.GridSelectedColumnCollection.callBaseMethod(this, 'clear');
	},

	_get_selectType: function()
	{
		return this._owner.get_columnSelectType();
	},

	_onClear: function()
	{
		if (this._grid._gridUtil._fireEvent(this, "_SelectedColumnChanging", null))
		{
			return;
		}
		if (this._keys.length > 0)
		{
			/* AK 7/22/09 18039: Is that needed here? Seems to be toomuch of the event firing*/
			var args = this._owner.__raiseClientEvent("ColumnSelectionChanging", $IG.ColumnSelectionChangingEventArgs, [this._grid, this._keys, []]);
			if (args == null || !args.get_cancel())
			{
				this.clear();
				var event = this._owner._clientEvents.ColumnSelectionChanged;
				if (event && event.postBack == 0)
					this._owner.__raiseClientEvent("ColumnSelectionChanged", $IG.ColumnSelectionChangedEventArgs, [this._owner, this, true]);
			}
			this.clear();
		}
	},

	getItem: function(index)
	{
		var obj = null;
		var key = this._keys[index];
		if (key != null)
			obj = this._grid._columns._getObjectByAdr(key);
		return obj;
	},

	_internalUnselect: function(index, rowCount)
	{
		var columnIndex = this._keys[index];
		var column = this._grid.get_columns().get_column(columnIndex);
		var visibleIndex = column.get_visibleIndex();
		for (var j = 0; j < rowCount; j++)
		{
			var rowObj = this._findRowObjFromIndex(j, true);
			if (rowObj)
			{
				var elem = this._util.getCellElemFromIndex(rowObj, visibleIndex);
				if (elem)
					$util.removeCompoundClass(elem, this._selectedCssClass);
			}
		}

		var elem = column._headerElement;
		if (elem)
			$util.removeCompoundClass(elem, this._sh);

		this._ht[this._keys[index]] = null;
		this._keys[index] = null;
	},
	_onSelect: function(index, ctrlKey)
	{
		if (this._grid._gridUtil._fireEvent(this._owner, "_SelectedColumnChanging", null))
		{
			return;
		}
		var isSelected = this._ht[index];
		if (!isSelected || !ctrlKey)
		{
			var newKeys = [];
			if (ctrlKey && this._get_selectType() == $IG.SelectType.Multiple)
				newKeys = Array.clone(this._keys);
			newKeys.push([index]);
			var args = this._owner.__raiseClientEvent("ColumnSelectionChanging", $IG.ColumnSelectionChangingEventArgs, [this._grid, this._keys, newKeys]);
			if (args == null || !args.get_cancel())
			{
				if (!ctrlKey || this._get_selectType() == $IG.SelectType.Single)
					this.clear();
				this._internalSelect(index, ctrlKey);
				this._owner.__raiseClientEvent("ColumnSelectionChanged", $IG.ColumnSelectionChangedEventArgs, [this._owner, this, true]);
			}
		}
		else if (isSelected && ctrlKey)
		{
			var count = this._keys.length;
			for (var i = 0; i < count; i++)
			{
				if (this._keys[i] == index)
				{
					var newKeys = Array.clone(this._keys);
					Array.removeAt(newKeys, i)
					var args = this._owner.__raiseClientEvent("ColumnSelectionChanging", $IG.ColumnSelectionChangingEventArgs, [this._grid, this._keys, newKeys]);
					if (args == null || !args.get_cancel())
					{
						this._internalUnselect(i, this._rows.get_length());
						while (Array.remove(this._keys, null));
						this._owner.__raiseClientEvent("ColumnSelectionChanged", $IG.ColumnSelectionChangedEventArgs, [this._owner, this, true]);
					}
					return;
				}
			}
		}
	},

	_internalSelect: function(index, ctrlKey)
	{
		index = parseInt(index);
		if (!this._ht[index])
		{
			this._repaintAt(index, true);
			this._keys.push(index);
			this._ht[index] = true;
		}
		this.__registerSelectedGrid(ctrlKey, "column");
	},

	/* VS 07/01/2009. Bug 18971 */
	/* repaint all cells in selected column at index */
	/* index: index of column within columns collection */
	/* header: true-repaint column header */
	_repaintAt: function(index, header)
	{
		var rowCount = this._rows.get_length();
		var column = this._grid.get_columns().get_column(index);
		if (!column)
			return;
		var visibleIndex = column.get_visibleIndex();
		for (var i = 0; i < rowCount; i++)
		{
			var rowObj = this._findRowObjFromIndex(i);
			if (rowObj)
			{
				var elem = this._util.getCellElemFromIndex(rowObj, visibleIndex);
				if (elem)
					elem.className += " " + this._selectedCssClass;
			}
		}
		var elem = header ? column._headerElement : null;
		if (elem)
			$util.addCompoundClass(elem, this._sh);
	},

	/* VS 07/01/2009. Bug 18971 */
	/* repaint all cells in selected columns: used by $IG.VirtualScrolling */
	_repaintRows: function()
	{
		var cols = this._keys.length;
		while (cols-- > 0)
			this._repaintAt(this._keys[cols]);
	},

	_onSelectRange: function(index, ctrlKey)
	{
		if (this._grid._gridUtil._fireEvent(this._owner, "_SelectedColumnChanging", null))
		{
			return;
		}

		var args = this._owner.__raiseClientEvent("ColumnSelectionChanging", $IG.ColumnSelectionChangingEventArgs, [this._grid, this._keys, null, index]);
		if (args == null || !args.get_cancel())
		{
			this._internalSelectRange(index, ctrlKey);

			$IG.GridSelectedColumnCollection.callBaseMethod(this, "_onSelectRange", [index]);

			this._owner.__raiseClientEvent("ColumnSelectionChanged", $IG.ColumnSelectionChangedEventArgs, [this._owner, this, true]);
		}
	},

	_internalSelectRange: function(index, ctrlKey)
	{
		index = parseInt(index);
		var columns = this._grid.get_columns();
		var startColumn = 0;
		var startColumnVisibleIndex = 0;

		if (this._keys.length > 0)
		{
			startColumn = this._keys[0];
			startColumnVisibleIndex = columns.get_column(startColumn).get_visibleIndex();
		}
		else
		{
			this._internalSelect(index, ctrlKey);
			return;
		}
		var endColumn = index;
		var endColumnVisibleIndex = columns.get_column(endColumn).get_visibleIndex();

		var rowCount = this._rows.get_length();
		for (var i in this._keys)
		{
			if (!isNaN(parseInt(i)))
			{
				var key = this._keys[i];
				var keyVisibleIndex = columns.get_column(key).get_visibleIndex();
				if (keyVisibleIndex < startColumnVisibleIndex || keyVisibleIndex > endColumnVisibleIndex)
					this._internalUnselect(i, rowCount);
			}
		}
		while (Array.remove(this._keys, null));

		if (startColumnVisibleIndex == endColumnVisibleIndex)
			this._internalSelect(startColumn, ctrlKey);
		else if (startColumnVisibleIndex < endColumnVisibleIndex)
		{
			for (var i = startColumnVisibleIndex; i <= endColumnVisibleIndex; i++)
			{
				var column = this._grid._gridUtil._getColumnFromVisibleIndex(i);
				if (this._owner._enableHiddenSelection || !column.get_hidden())
				{
					var idx = column.get_index();
					this._internalSelect(idx, ctrlKey);
				}
			}
		}
		else
		{
			for (var i = startColumnVisibleIndex; i >= endColumnVisibleIndex; i--)
			{
				var column = this._grid._gridUtil._getColumnFromVisibleIndex(i);
				if (this._owner._enableHiddenSelection || !column.get_hidden())
				{
					var idx = column.get_index();
					this._internalSelect(idx, ctrlKey);
				}
			}
		}
	}
}
$IG.GridSelectedColumnCollection.registerClass('Infragistics.Web.UI.GridSelectedColumnCollection', $IG.GridSelectionCollection);
/******************************END GRID SELECTED ROW COLLECTION ***************************/


/******************************************GridSelectionProps ENUM************************************/
$IG.GridSelectionProps = new function()
{
	this.CellClickAction = [$IG.GridBehaviorProps.Count + 0, 0];
	this.CellSelectType = [$IG.GridBehaviorProps.Count + 1, 1];
	this.RowSelectType = [$IG.GridBehaviorProps.Count + 2, 0];
	this.ColumnSelectType = [$IG.GridBehaviorProps.Count + 3, 0];
	this.SelectedCells = [$IG.GridBehaviorProps.Count + 4, null];
	this.SelectedRows = [$IG.GridBehaviorProps.Count + 5, null];
	this.SelectedColumns = [$IG.GridBehaviorProps.Count + 6, null];
	this.Count = $IG.GridBehaviorProps.Count + 7;
};
/******************************************END GridSelectionProps ENUM********************************/

/******************************************CellClickAction ENUM******************************/
$IG.CellClickAction = function()
{
	/// <summary>
	/// The enumeration defines an action whenever a cell in the grid is clicked.
	/// </summary>
	/// <field name="Cell" type="Number" integer="true" static="true">
	/// The cell should be selected.
	/// </field>
	/// <field name="Row" type="Number" integer="true" static="true">
	/// The cell's row should be selected.
	/// </field>
}
$IG.CellClickAction.prototype =
{
	Cell: 0,
	Row: 1
};
$IG.CellClickAction.registerEnum("Infragistics.Web.UI.CellClickAction");
/******************************************END CellClickAction ENUM**************************/

/******************************************SelectType ENUM******************************/
$IG.SelectType = function()
{
	/// <summary>
	/// The enumeration defines type of selection in the grid.
	/// </summary>
	/// <field name="None" type="Number" integer="true" static="true">
	/// No selection can be performed on the grid.
	/// </field>
	/// <field name="Single" type="Number" integer="true" static="true">
	/// One object can be selected at a time.
	/// </field>
	/// <field name="Multiple" type="Number" integer="true" static="true">
	/// Multiple objects can be selected at a time.
	/// </field>
}
$IG.SelectType.prototype =
{
	None: 0,
	Single: 1,
	Multiple: 2
};
$IG.SelectType.registerEnum("Infragistics.Web.UI.SelectType");
/******************************************END SelectType ENUM**************************/

/**************************************************EVENT ARGS****************************************/

/************************************CELL***************************************/
$IG.CellSelectionChangingEventArgs = function(params)
{
	/// <summary>
	/// Event arguments object that is passed into the CellSelectionChanging event handler.
	/// </summary>
	$IG.CellSelectionChangingEventArgs.initializeBase(this);
	this._rows = params[0];
	this._keys = Array.clone(params[1]);
	this._newCollection = null
	if (params[2] != null)
		this._newCollection = new $IG.GridCellReadOnlyCollection(params[2], this._rows); ;
	this._cellIndex = params[3];
	this._rowIndex = params[4];
	this._collection = new $IG.GridCellReadOnlyCollection(this._keys, this._rows);
}
$IG.CellSelectionChangingEventArgs.prototype =
{
	getCurrentSelectedCells: function()
	{
		/// <summary>
		/// Returns a Read Only collection of the currently selected cells.
		/// </summary>
		return this._collection;
	},

	getNewSelectedCells: function()
	{
		/// <summary>
		/// Returns a Read Only collection of cells that are going to be selected.
		/// </summary>
		if (this._newCollection == null)
		{
			var startCell = null;
			var startRow = 0;
			if (this._keys.length > 0)
			{
				var row = this._rows.get_rowFromIDPair(this._keys[0][0]);
				if (row != null)
					startRow = row.get_index();
				startCell = this._keys[0][1];
			}
			else
			{
				var newKeys = Array.clone(this._keys);
				newKeys.push([this._rowIndex, this._cellIndex])
				return this._newCollection = new $IG.GridCellReadOnlyCollection(newKeys, this._rows);
			}

			var endCell = parseInt(this._cellIndex);
			var endRow = parseInt(this._rowIndex);

			var newKeys = [];
			if (startCell > endCell)
			{
				var temp = endCell;
				endCell = startCell;
				startCell = temp;
			}
			if (startRow > endRow)
			{
				var temp = endRow;
				endRow = startRow;
				startRow = temp;
			}

			for (var i = startRow; i <= endRow; i++)
			{
				for (var j = startCell; j <= endCell; j++)
					newKeys.push([this._rows.get_row(i).get_idPair(), j]);
			}

			this._newCollection = new $IG.GridCellReadOnlyCollection(newKeys, this._rows);
		}
		return this._newCollection;
	}

}
$IG.CellSelectionChangingEventArgs.registerClass('Infragistics.Web.UI.CellSelectionChangingEventArgs', $IG.CancelEventArgs);

$IG.CellSelectionChangedEventArgs = function(params)
{
	/// <summary>
	/// Event arguments object that is passed into the CellSelectionChanged event handler.
	/// </summary>
	$IG.CellSelectionChangedEventArgs.initializeBase(this);
	this._context = {};
	this._context["behavior"] = params[0].get_name();
	this._collection = params[1];
	this._noIndicator = params[2];
}
$IG.CellSelectionChangedEventArgs.prototype =
{

	getSelectedCells: function()
	{
		/// <summary>
		/// Returns the collection of selected cells.
		/// </summary>
		return this._collection;
	}
}
$IG.CellSelectionChangedEventArgs.registerClass('Infragistics.Web.UI.CellSelectionChangedEventArgs', $IG.EventArgs);

/************************************END CELL***************************************/

/************************************ROW***************************************/
$IG.RowSelectionChangingEventArgs = function(params)
{
	/// <summary>
	/// Event arguments object that is passed into the RowSelectionChanging event handler.
	/// </summary>
	$IG.RowSelectionChangingEventArgs.initializeBase(this);
	this._rows = params[0];
	this._keys = Array.clone(params[1]);
	this._newCollection = null
	if (params[2] != null)
		this._newCollection = new $IG.GridRowReadOnlyCollection(params[2], this._rows); ;
	this._rowObj = params[3];
	this._collection = new $IG.GridRowReadOnlyCollection(this._keys, this._rows);
}
$IG.RowSelectionChangingEventArgs.prototype =
{

	getCurrentSelectedRows: function()
	{
		/// <summary>
		/// Returns a Read Only collection of the currently selected rows.
		/// </summary>
		return this._collection;
	},

	getNewSelectedRows: function()
	{
		/// <summary>
		/// Returns a Read Only collection of rows that are going to be selected.
		/// </summary>
		if (this._newCollection == null)
		{
			var startRow = 0;
			if (this._keys.length > 0)
			{
				var row = this._rows.get_rowFromIDPair(this._keys[0]);
				if (row != null)
					startRow = row.get_index();
			}
			else
			{
				var newKeys = Array.clone(this._keys);
				newKeys.push(this._rowObj.get_idPair());
				return this._newCollection = new $IG.GridRowReadOnlyCollection(newKeys, this._rows);
			}

			var endRow = parseInt(this._rowObj.get_index());

			var newKeys = [];
			if (startRow > endRow)
			{
				var temp = endRow;
				endRow = startRow;
				startRow = temp;
			}

			for (var i = startRow; i <= endRow; i++)
			{
				newKeys.push(this._rows.get_row(i).get_idPair());
			}

			this._newCollection = new $IG.GridRowReadOnlyCollection(newKeys, this._rows);
		}
		return this._newCollection;
	}
}
$IG.RowSelectionChangingEventArgs.registerClass('Infragistics.Web.UI.RowSelectionChangingEventArgs', $IG.CancelEventArgs);

$IG.RowSelectionChangedEventArgs = function(params)
{
	/// <summary>
	/// Event arguments object that is passed into the RowSelectionChanged event handler.
	/// </summary>
	$IG.RowSelectionChangedEventArgs.initializeBase(this);
	this._context = {};
	this._context["behavior"] = params[0].get_name();
	this._collection = params[1];
	this._noIndicator = params[2];
}
$IG.RowSelectionChangedEventArgs.prototype =
{
	getSelectedRows: function()
	{
		/// <summary>
		/// Returns the collection of selected rows.
		/// </summary>
		return this._collection;
	}
}
$IG.RowSelectionChangedEventArgs.registerClass('Infragistics.Web.UI.RowSelectionChangedEventArgs', $IG.EventArgs);
/************************************END ROW***************************************/

/************************************COLUMN***************************************/
$IG.ColumnSelectionChangingEventArgs = function(params)
{
	/// <summary>
	/// Event arguments object that is passed into the ColumnSelectionChanging event handler.
	/// </summary>
	$IG.ColumnSelectionChangingEventArgs.initializeBase(this);
	this._grid = params[0];
	this._keys = Array.clone(params[1]);
	this._newCollection = null
	if (params[2] != null)
		this._newCollection = new $IG.GridColumnReadOnlyCollection(params[2], this._grid); ;
	this._columnIndex = params[3];
	this._collection = new $IG.GridColumnReadOnlyCollection(this._keys, this._grid);
}
$IG.ColumnSelectionChangingEventArgs.prototype =
{
	getCurrentSelectedColumns: function()
	{
		/// <summary>
		/// Returns a Read Only collection of the currently selected columns.
		/// </summary>
		return this._collection;
	},

	getNewSelectedColumns: function()
	{
		/// <summary>
		/// Returns a Read Only collection of columns that are going to be selected.
		/// </summary>
		if (this._newCollection == null)
		{
			var startColumn = 0;
			if (this._keys.length > 0)
				startColumn = this._keys[0];
			else
			{
				var newKeys = Array.clone(this._keys);
				newKeys.push(this._columnIndex)
				return this._newCollection = new $IG.GridColumnReadOnlyCollection(newKeys, this._grid);
			}
			var endColumn = this._columnIndex;

			var newKeys = [];
			if (startColumn > endColumn)
			{
				var temp = endColumn;
				endColumn = startColumn;
				startColumn = temp;
			}

			for (var i = startColumn; i <= endColumn; i++)
				newKeys.push(i);

            this._newCollection = new $IG.GridColumnReadOnlyCollection(newKeys, this._grid);
		}
		return this._newCollection;
	}
}
$IG.ColumnSelectionChangingEventArgs.registerClass('Infragistics.Web.UI.ColumnSelectionChangingEventArgs', $IG.CancelEventArgs);

$IG.ColumnSelectionChangedEventArgs = function(params)
{
	/// <summary>
	/// Event arguments object that is passed into the ColumnSelectionChanged event handler.
	/// </summary>
	$IG.ColumnSelectionChangedEventArgs.initializeBase(this);
	this._context = {};
	this._context["behavior"] = params[0].get_name();
	this._collection = params[1];
	this._noIndicator = params[2];
}
$IG.ColumnSelectionChangedEventArgs.prototype =
{
	getSelectedColumns: function()
	{
		/// <summary>
		/// Returns the collection of selected columns.
		/// </summary>
		return this._collection;
	}
}
$IG.ColumnSelectionChangedEventArgs.registerClass('Infragistics.Web.UI.ColumnSelectionChangedEventArgs', $IG.EventArgs);
/************************************END COLUMN***************************************/
/**********************************************END EVENT ARGS****************************************/

/************************************CellReadOnlyCollection******************************************/

$IG.GridCellReadOnlyCollection = function(keys, rows)
{
	/// <summary>
	/// Read-only collection of grid cells.
	/// </summary>
	this._keys = keys;
	this._rows = rows;
}

$IG.GridCellReadOnlyCollection.prototype =
{
	getCell: function(index)
	{
		/// <summary>
		/// Returns the cell at the specified index. 
		/// </summary>
		///<param name="index">The index of the cell that should be returned</param>
		var obj = null;
		var key = this._keys[index];
		if (key != null)
		{
			var rowObj = this._rows.get_rowFromIDPair(key[0]);
			if (rowObj != null)
				obj = rowObj.get_cell(key[1]);
		}
		return obj;
	},

	get_length: function()
	{
		/// <summary>
		/// Returns the amount of cells in the collection. 
		/// </summary>
		return this._keys.length;
	}

}
$IG.GridCellReadOnlyCollection.registerClass('Infragistics.Web.UI.GridCellReadOnlyCollection');

/************************************END CellReadOnlyCollection**************************************/

/************************************RowReadOnlyCollection******************************************/

$IG.GridRowReadOnlyCollection = function(keys, rows)
{
	/// <summary>
	/// Read-only collection of grid rows.
	/// </summary>
	this._keys = keys;
	this._rows = rows;
}

$IG.GridRowReadOnlyCollection.prototype =
{
	getRow: function(index)
	{
		/// <summary>
		/// Returns the row at the specified index. 
		/// </summary>
		///<param name="index">The index of the row that should be returned</param>
		var obj = null;
		var key = this._keys[index];
		if (key != null)
		{
			return this._rows.get_rowFromIDPair(key);
		}
		return obj;
	},

	get_length: function()
	{
		/// <summary>
		/// Returns the amount of rows in the collection. 
		/// </summary>
		return this._keys.length;
	}

}
$IG.GridRowReadOnlyCollection.registerClass('Infragistics.Web.UI.GridRowReadOnlyCollection');

/************************************END RowReadOnlyCollection**************************************/

/************************************ColumnReadOnlyCollection******************************************/

$IG.GridColumnReadOnlyCollection = function(keys, grid)
{
	/// <summary>
	/// Read-only collection of grid columns.
	/// </summary>
	this._keys = keys;
	this._grid = grid;
}

$IG.GridColumnReadOnlyCollection.prototype =
{
	getColumn: function(index)
	{
		/// <summary>
		/// Returns the column at the specified index. 
		/// </summary>
		///<param name="index">The index of the column that should be returned</param>
		var obj = null;
		var key = this._keys[index];
		if (key != null)
		{
			if (key != null)
				obj = this._grid._columns._getObjectByAdr(key);
		}
		return obj;
	},

	get_length: function()
	{
		/// <summary>
		/// Returns the amount of columns in the collection. 
		/// </summary>
		return this._keys.length;
	}

}
$IG.GridColumnReadOnlyCollection.registerClass('Infragistics.Web.UI.GridColumnReadOnlyCollection');

/************************************END ColumnReadOnlyCollection**************************************/

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();