var $GridManager = new GridManager();

function GridManager () {
	this.Grids = Grids; // get all from global variable, in future replace all references to it with $GridManager.Grids
	this.AlternativeGrids = new Array();
}

GridManager.prototype.AddAlternativeGrid = function ($source_grid, $destination_grid, $reciprocal)
{
	if ($source_grid == $destination_grid) {
		return false;
	}

	if (typeof(this.AlternativeGrids[$source_grid]) == 'undefined') {
		// alternative grids not found, create empty list
		this.AlternativeGrids[$source_grid] = new Array();
	}

	if (!in_array($destination_grid, this.AlternativeGrids[$source_grid])) {
		// alternative grids found, check if not added already
		this.AlternativeGrids[$source_grid].push($destination_grid);
	}

	if ($reciprocal) {
		this.AddAlternativeGrid($destination_grid, $source_grid);
	}
}

GridManager.prototype.ClearAlternativeGridsSelection = function ($source_prefix)
{
	if (!this.AlternativeGrids[$source_prefix]) return false;

	var $i = 0;
	var $destination_prefix = '';
	while ($i < this.AlternativeGrids[$source_prefix].length) {
		$destination_prefix = this.AlternativeGrids[$source_prefix][$i];
		if (this.Grids[$destination_prefix]) {
			// alternative grid set, but not yet loaded by ajax
			this.Grids[$destination_prefix].ClearSelection();
		}
		$i++;
	}
}

GridManager.prototype.CheckDependencies = function ($prefix) {
	if (typeof(this.Grids[$prefix]) != 'undefined') {
		this.Grids[$prefix].CheckDependencies('GridManager.CheckDependencies');
	}
}

function GridItem(grid, an_element, cb, item_id, class_on, class_off)
{
	this.Grid = grid;
	this.selected = false;
	this.id = an_element.id;
	this.ItemId = item_id;
	this.sequence = parseInt(an_element.getAttribute('sequence'));
	this.class_on = class_on;
	if (class_off == ':original') {
		this.class_off = an_element.className;
	}
	else
		this.class_off = class_off;
	this.HTMLelement = an_element;
	this.CheckBox = cb;

	this.value = this.ItemId;
	this.ItemType = 11;
}

GridItem.prototype.Init = function ()
{
	this.HTMLelement.GridItem = this;
	this.HTMLelement.onclick = function(ev) {
			this.GridItem.Click(ev);
	};
	this.HTMLelement.ondblclick = function(ev) {
			this.GridItem.DblClick(ev);
	}
	if ( isset(this.CheckBox) ) {
		this.CheckBox.GridItem = this;
		this.CheckBox.onclick = function(ev) {
				this.GridItem.cbClick(ev);
		};
		this.CheckBox.ondblclick = function(ev) {
			this.GridItem.DblClick(ev);
		}
	}
}

GridItem.prototype.DisableClicking = function ()
{
	this.HTMLelement.onclick = function(ev) {
			return false;
	};
	this.HTMLelement.ondblclick = function(ev) {
			return false;
	}
	if ( isset(this.CheckBox) ) {
		this.CheckBox.onclick = function(ev) {
				return false;
		};
	}
}

GridItem.prototype.Select = function ()
{
	if (this.selected) return;
	this.selected = true;
	this.HTMLelement.className = this.class_on;
	if ( isset(this.CheckBox) ) {
		this.CheckBox.checked = true;
	}
	this.Grid.LastSelectedId = this.ItemId;
	this.Grid.SelectedCount++;

	// this is for in-portal only (used in relation select)
	LastCheckedItem = this;
	if (typeof (this.Grid.OnSelect) == 'function' ) {
		this.Grid.OnSelect(this.ItemId);
	}
}

GridItem.prototype.UnSelect = function ( force )
{
	if ( !this.selected && !force) return;
	this.selected = false;
	this.HTMLelement.className = this.class_off;
	if ( isset(this.CheckBox) ) {
		this.CheckBox.checked = false;
	}
	this.Grid.SelectedCount--;
	if (typeof (this.Grid.OnUnSelect) == 'function' ) {
		this.Grid.OnUnSelect(this.ItemId);
	}
}

GridItem.prototype.ClearBrowserSelection = function() {
	var $is_opera = navigator.userAgent.toLowerCase().indexOf("opera") != -1;
	if (window.getSelection) {
		// removeAllRanges will be supported by Opera from v 9+, do nothing by now
		var selection = window.getSelection();
		if (selection.removeAllRanges) { // Mozilla & Opera 9+
			window.getSelection().removeAllRanges();
		}
 	} else if (document.selection && !$is_opera) { // IE
 		document.selection.empty();
 	}
}

GridItem.prototype.Click = function (ev)
{
	this.ClearBrowserSelection();
	this.Grid.ClearAlternativeGridsSelection('GridItem.Click');

	var e = document.all ? window.event : ev;
	if (e.shiftKey && !this.Grid.RadioMode) {
		this.Grid.SelectRangeUpTo(this.sequence);
	}
	else {
		if (e.ctrlKey && !this.Grid.RadioMode) {
			this.Toggle()
		}
		else {
			if (!(this.Grid.RadioMode && this.Grid.LastSelectedId == this.ItemId && this.selected)) {
				// don't clear selection if item same as current is selected
				this.Grid.ClearSelection(null,'GridItem.Click');
				this.Toggle();
			}
		}
	}
	this.Grid.CheckDependencies('GridItem.Click');
	e.cancelBubble = true;
}

GridItem.prototype.cbClick = function (ev)
{
	var e = document.all ? window.event : ev;
	if (this.Grid.RadioMode) this.Grid.ClearSelection(null,'GridItem.cbClick');
	this.Grid.ClearAlternativeGridsSelection('GridItem.cbClick');
	this.Toggle();
	this.Grid.CheckDependencies('GridItem.cbClick');
	e.cancelBubble = true;
}

GridItem.prototype.DblClick = function (ev)
{
	var e = document.all ? window.event : ev;
	this.Grid.Edit();
}

GridItem.prototype.Toggle = function ()
{
	if (this.selected) this.UnSelect()
	else {
		this.Grid.LastSelectedSequence = this.sequence;
		this.Select();
	}
}

GridItem.prototype.FallsInRange = function (from, to)
{
	return (from <= to) ?
					(this.sequence >= from && this.sequence <= to) :
					(this.sequence >= to && this.sequence <= from);
}


function Grid(prefix, class_on, class_off, dbl_click, toolbar)
{
	this.prefix = prefix;
	this.class_on = class_on;
	this.class_off = class_off;
	this.Items = new Array();
	this.LastSelectedSequence = 1;
	this.LastSelectedId = null;
	this.DblClick = dbl_click;
	this.ToolBar = toolbar;
	this.SelectedCount = 0;
	this.AlternativeGrids = new Array();
	this.DependantButtons = new Array();
	this.RadioMode = false;
}

Grid.prototype.AddItem = function( an_item ) {
	this.Items[an_item.id] = an_item;
}

Grid.prototype.AddItemsByIdMask = function ( tag, mask, cb_mask ) {
	var $item_id=0;
	elements = document.getElementsByTagName(tag.toUpperCase());
	for (var i=0; i < elements.length; i++) {
		if ( typeof(elements[i].id) == 'undefined') {
			continue;
		}
		if ( !elements[i].id.match(mask)) continue;
		$item_id=RegExp.$1;

		cb_name = cb_mask.replace('$$ID$$',$item_id);

		cb = document.getElementById(cb_name);
		if (typeof(cb) == 'undefined') alert ('No Checkbox defined for item '+elements[i].id);

		this.AddItem( new GridItem( this, elements[i], cb, $item_id, this.class_on, this.class_off ) );
	}
}

Grid.prototype.InitItems = function() {
	for (var i in this.Items) {
		this.Items[i].Init();
	}
	this.ClearSelection( true,'Grid.InitItems' );
}

Grid.prototype.DisableClicking = function() {
	for (var i in this.Items) {
		this.Items[i].DisableClicking();
	}
	this.ClearSelection( true, 'Grid.DisableClicking' );
}

Grid.prototype.ClearSelection = function( force, called_from ) {
//	alert('selection clear. force: '+force+'; called_from: '+called_from);
	if (typeof(force) == 'undefined') force = false;
	if (this.CountSelected() == 0 && !force) return;
	for (var i in this.Items) {
		this.Items[i].UnSelect(force);
	}
	this.SelectedCount = 0;
	this.CheckDependencies('Grid.ClearSelection');
}

Grid.prototype.GetSelected = function() {
	var $ret = new Array();
	for (var i in this.Items) {
		if (this.Items[i].selected) {
			$ret[$ret.length] = this.Items[i].ItemId;
		}

	}
	return $ret;
}

Grid.prototype.InvertSelection = function() {
	for (var i in this.Items)
	{
		if( this.Items[i].selected )
		{
			this.Items[i].UnSelect();
		}
		else
		{
			this.Items[i].Select();
		}
	}
	this.CheckDependencies('Grid.InvertSelection');
}

Grid.prototype.SelectAll = function() {
	for (var i in this.Items) {
		this.Items[i].Select();
	}
	this.CheckDependencies('Grid.SelectAll');
	this.ClearAlternativeGridsSelection('Grid.SelectAll');
}

Grid.prototype.SelectRangeUpTo = function( last_sequence ) {
	for (var i in this.Items) {
		if (this.Items[i].FallsInRange(this.LastSelectedSequence, last_sequence)) {
			this.Items[i].Select();
		}
	}
}

Grid.prototype.CountSelected = function ()
{
	return this.SelectedCount;
}

Grid.prototype.Edit = function() {
	if ( this.CountSelected() == 0 ) return;
	this.DblClick(this.prefix);
}

Grid.prototype.SetDependantToolbarButtons = function($buttons, $direct, $mode) {
	if (!isset($direct)) $direct = true; // direct (use false for invert mode)
	if (!isset($mode)) $mode = 1; // enable/disable (use 2 for show/hide mode)
	for (var i in $buttons) {
		this.DependantButtons.push(new Array($buttons[i], $direct, $mode));
	}
	//this.DependantButtons = buttons;
	this.CheckDependencies('Grid.SetDependantToolbarButtons');
}

Grid.prototype.CheckDependencies = function($called_from)
{
//	alert('prefix: ' + this.prefix + '; ' + $called_from + ' -> Grid.CheckDependencies');
	var enabling = (this.CountSelected() > 0);
	for (var i in this.DependantButtons) {
		if (this.DependantButtons[i][0].match("portal:(.*)")) {
			button_name = RegExp.$1;
			if (toolbar) {
				if (enabling == this.DependantButtons[i][1]) {
					toolbar.enableButton(button_name, true);
				}
				else
				{
					toolbar.disableButton(button_name, true);
				}
			}
		}
		else {
			if (this.DependantButtons[i][2] == 1) {
				this.ToolBar.SetEnabled(this.DependantButtons[i][0], enabling == this.DependantButtons[i][1]);
			}
			else {
				this.ToolBar.SetVisible(this.DependantButtons[i][0], enabling == this.DependantButtons[i][1]);
			}
		}
	}
	//if (enabling) this.ClearAlternativeGridsSelection('Grid.CheckDependencies');

}

Grid.prototype.ClearAlternativeGridsSelection = function (called_from)
{
	$GridManager.ClearAlternativeGridsSelection(this.prefix);
}

Grid.prototype.AddAlternativeGrid = function (alt_grid, reciprocal)
{
	var $dst_prefix = typeof('alt_grid') == 'string' ? alt_grid : alt_grid.prefix;
	$GridManager.AddAlternativeGrid(this.prefix, $dst_prefix, reciprocal);
}

Grid.prototype.FirstSelected = function ()
{
	min_sequence = null;
	var res = null
	for (var i in this.Items) {
		if (!this.Items[i].selected) continue;
		if (min_sequence == null)
			min_sequence = this.Items[i].sequence;
		if (this.Items[i].sequence <= min_sequence) {
			res = this.Items[i].ItemId;
			min_sequence = this.Items[i].sequence;
		}
	}
	return res;
}