var sheetRules; // all rules in stylesheet Set by initStyleChange()
var currentRule; // which rule are we editing? Set by assignRule()
var defaultStyles = new Array();


function StyleManager() {}

StyleManager.InitStyles = function() {
	if (!document.styleSheets) return;
	var sheets = document.styleSheets;

	this.Map = new Object();
//	alert('total '+sheets.length+' sheets')
	for (var i=0;i<sheets.length;i++) {
		var currentSheet = sheets[i];
		if (currentSheet.cssRules)
			sheetRules = currentSheet.cssRules
		else if (currentSheet.rules)
			sheetRules = currentSheet.rules;
		else {
//			alert('bad sheet '+currentSheet.href);
			continue;
		}

//		alert('sheet: '+currentSheet.href)

		for (var ii=0;ii<sheetRules.length;ii++) {
			var value = sheetRules[ii].selectorText;
			if (value.match(',')) { // Mozilla does not break comma-separated selectors into separate rules...
				var subselectors = value.split(',');
				for (var sub = 0; sub < subselectors.length; sub++) {
					var real_name = subselectors[sub].replace(/^[ \t]*(.*)[ \t]*/, '$1');
					this.Map[real_name] = sheetRules[ii]
				}
			}
			else {
				this.Map[value.toLowerCase()] = sheetRules[ii];
			}
		}
	}
	this.Inited = true;
//	preg_print_pre(this.Map, /last/);
}

StyleManager.ChangeStyle = function(selector, s, value)
{
	if (!this.Inited) this.InitStyles()
	rule = this.Map[selector.toLowerCase()];
	if (!rule) {
		if (this.AddStyle(selector, s, value)) {
			return true;
		}
		alert('rule '+selector+' not found')
		return;
	}
	alert('adjusting rule '+selector+' setting '+s+' to '+value+' from '+rule.style[s])
	rule.style[s] = value;
	alert('now it is '+rule.style[s])
}

StyleManager.AddStyle = function(selector, style, value)
{
	var sheet = document.styleSheets[0];
	var rule = false;
	if (sheet.insertRule) {
		sheet.insertRule(selector+'{'+style+':'+value+'}', sheet.cssRules.length);
		rule = sheet.cssRules[sheet.cssRules.length-1];
	}
	else if(sheet.addRule) {
		sheet.addRule(selector, style+':'+value);
		rule = sheet.rules[sheet.rules.length-1];
	}
	if (rule) {
		alert ('adding rule as '+selector);
		this.Map[selector.toLowerCase()] = sheet.cssRules[sheet.cssRules.length-1];
		return true;
	}
	return false;
}

StyleManager.GetStyle = function(selector)
{
	if (!this.Inited) this.InitStyles()
	rule = this.Map[selector.toLowerCase()];
	if (!rule) return false;
	return rule;
}

StyleManager.GetStyleValue = function(selector, style)
{
	rule = this.GetStyle(selector);
	if (!rule) return false;
	return rule.selector;
}

function preg_print_pre(obj, reg)
{
	if (!reg) reg = /.*/;
	var p = ''
	for (var prop in obj) {
		if (prop.match(reg) ) {
			p += prop + ': '+obj[prop] + '\n'
		}
	}
	alert(p)
}

var startTime,endTime;

var profile = 0;
var profile_total = 0;
var startTime = new Date().getTime();

function Profile(message,force)
{
	if (profile || force) {
		endTime = new Date().getTime();
		var tmp = (endTime-startTime);
		profile_total += tmp;
		alert(message+' took '+tmp+' ms of '+profile_total)
		startTime = new Date().getTime();
	}
}

function ResetStart()
{
	startTime = new Date().getTime();
	profile_total = 0;
}

function GridScroller(grid_id, w, h)
{
	this.GridId = grid_id

	this.Footer = false;

	this.LeftCells = 0;
	this.LeftWidth = 0;

	this.BottomOffset = 0;

	this.Width = w;
	this.Height = h;

	this.MaxHeight = h; // maximal grid height from constructor (also save here, because this.Height will be changed after Resize method call)

	this.AutoWidth = true;

	this.ScrollerW = 0;
	this.ScrollerH = 0;

	this.MinWidths = [];
	this.IDs = [];

	this.Rendered = false;

	this.PickerCRC = '';

	this.MaxHeaderHeights = [50,30];
	this.MaxRowHeight = 45;

	this.Html = ''; // html from last grid rendering
}

GridScroller.prototype._getMeasureHtml = function() {
	return '<div id="my_measure_'+this.GridId+'" style="width: auto; height: 0px; z-index: -105;"></div>';
}

GridScroller.prototype._prepareHtml = function($container) {
	if (typeof($container) == 'undefined') {
		var dot = this._getMeasureHtml();
//		console.log('dot without container');
		document.write(dot);
	}
	else {
//		console.log('dot inside container');
		var dot = document.createElement('div');
		dot.id = 'my_measure_'+this.GridId;
		dot.style.width = 'auto';
		dot.style.height = '0px';
		dot.style.zIndex = '-105';
		document.getElementById($container).appendChild(dot);
	}

	var dot = document.getElementById('my_measure_'+this.GridId);
	var measure = document.getElementById('my_measure_'+this.GridId);
	this.pos = findPos(dot);
//	alert('dot: '+this.pos[0]+','+this.pos[1])
	var collapse_correction = this._getCollapseCorrection();
	if (is.ie) this.pos[0] += 1;

//	this.MainOuter.style.width = 'auto'
	var w = measure.offsetWidth;
	var h = document.body.clientHeight;
	var dim = getDimensions(measure);
	h -= this.pos[1] + dim.padding[0] + dim.padding[2] + dim.borders[0] + dim.borders[2] + this.BottomOffset;
	var $html = this.AltHTML(this.pos[0],this.pos[1], w, h);

	return $html;
}

GridScroller.prototype._getCollapseCorrection = function() {
	return is.ie ? 0 : -1;
}

GridScroller.prototype.Render = function(id)
{
	Application.removeDebuggerStatistics();

	ResetStart();

//	var widths = this.PrepareWidths();
//	this.MinWidths = [40,null,null,250]
	this.MinWidths = this.PrepareWidths(); // [50,70,90,150,150,110,70,111];

	document.body.style.height = '100%';
	document.body.style.overflow = 'hidden';
	document.body.scroll = 'no';

	// this.Html = this.AltHTML();
//	Profile('Getting HTML',1);
//	console.log('GridScroller.Render(', id, ')');
	if (id && id != '') {
//		console.log('id given');
		if (this.Html.length == 0) {
			// 1st render and inside container -> prepare html
//			console.log('1st render and no html');
			this.Html = this._prepareHtml(id);

			var collapse_correction = this._getCollapseCorrection();

			// direct innerHTML assignment results empty line (15px height) to be added before
			// container when grid data is set from ajax responce (like in catalog) in IE, so
			// use jQuery here
//			document.getElementById(id).innerHTML = this._getMeasureHtml() + '<div id="main_div_'+this.GridId+'" style="margin-left: '+collapse_correction+'px">'+this.Html+'</div>';
			$( jq('#' + id) ).html( this._getMeasureHtml() + '<div id="main_div_'+this.GridId+'" style="margin-left: '+collapse_correction+'px">'+this.Html+'</div>' );
		}
		else {
			// direct innerHTML assignment results empty line (15px height) to be added before
			// container when grid data is set from ajax responce (like in catalog) in IE, so
			// use jQuery here
//			document.getElementById(id).innerHTML = '<div id="main_div_'+this.GridId+'">'+this.Html+'</div>';
			$( jq('#' + id) ).html( '<div id="main_div_'+this.GridId+'">'+this.Html+'</div>' );
		}
//		execJS(document.getElementById(id));
	}
	else {
//		console.log('id not given');
		if (this.Rendered) {
//			console.log('rendering inside container');
			this.Render('main_div_'+this.GridId);
			return;
		}

//		console.log('just rendering');
		this.Html = this._prepareHtml();
		var collapse_correction = this._getCollapseCorrection();
		document.write('<div id="main_div_'+this.GridId+'" style="margin-left: '+collapse_correction+'px">'+this.Html+'</div>');
	}
	this.Rendered = true;
//	Profile('Main render & refs',1)
	this.SetReferences();

//	return;

	if (getFrame('head').ScrollerW) {
		this.ScrollerW = getFrame('head').ScrollerW;
		this.ScrollerH = getFrame('head').ScrollerH;
	}
	else {
		this.ScrollerW = 17;
		this.ScrollerH = 17;
		/*this.ScrollerW = this.MainInner.offsetWidth - this.MainInner.clientWidth
		this.ScrollerH = this.MainInner.offsetHeight - this.MainInner.clientHeight
		getFrame('head').ScrollerW = this.ScrollerW
		getFrame('head').ScrollerH = this.ScrollerH*/
	}

//	Profile('Up to col widths',1);
	if (!this.UpdateColWidths()) return;

	if (this.Width == 'auto') {
		this.Resize( this.GetAutoSize(this.Height) );
	}
	else {
		this.Resize();
	}

	this.AdjustInputWidths();
	this.TheGrid.style.visibility = 'visible'
	this.MainScroller.style.visibility = 'visible'
//	Profile('Finalizng', 1);

	var the_grid = this;
	if (document.all) {
		$status = window.attachEvent('onresize', function(ev) { the_grid.AutoResize() });
	} else {
		$status = window.addEventListener('resize', function(ev) { the_grid.AutoResize() }, true);
	}
	if (document.all) {
		this.DataScroller.onmousewheel = function(ev) {
			var e = document.all ? window.event : ev;
			this.TheGrid.MainInner.scrollTop += -e.wheelDelta/2
			this.TheGrid.SyncScroll();
		}
		if (this.LeftCells > 0) {
			this.LeftDataInner.onmousewheel = function(ev) {
				var e = document.all ? window.event : ev;
				this.TheGrid.MainInner.scrollTop += -e.wheelDelta/2
				this.TheGrid.SyncScroll();
			}
		}
	}
	else {
		this.DataScroller.addEventListener("DOMMouseScroll", function(ev) {
			var e = document.all ? window.event : ev;
			this.TheGrid.MainInner.scrollTop += e.detail*10
			this.TheGrid.SyncScroll();
		}, false);
		if (this.LeftCells > 0) {
			this.LeftDataInner.addEventListener("DOMMouseScroll", function(ev) {
				var e = document.all ? window.event : ev;
				this.TheGrid.MainInner.scrollTop += e.detail*10
				this.TheGrid.SyncScroll();
			}, false);
		}
	}

	addLoadEvent(
		function() {
			the_grid.RefreshPos();
			the_grid.AutoResize();
			the_grid.SetResizeHandles();
		}
	);
}

GridScroller.prototype.SetReferences = function() {
	this.MainOuter = document.getElementById('outer_main_'+this.GridId );
	this.MainInner = document.getElementById('inner_main_'+this.GridId)
	this.MainScroller = document.getElementById('main_scroller_'+this.GridId)
	this.TheGrid = document.getElementById(this.GridId );

	this.HeadTable = document.getElementById('header_'+this.GridId);
	this.HeadScroller = document.getElementById('inner_header_'+this.GridId);
	this.HeadOuter = document.getElementById('outer_header_'+this.GridId);

	this.DataTable = document.getElementById('data_'+this.GridId);
	this.DataScroller = document.getElementById('inner_data_'+this.GridId);
	this.DataOuter = document.getElementById('outer_data_'+this.GridId);

	if (this.HasFooter) {
		this.FooterTable = document.getElementById('footer_'+this.GridId);
		this.FooterScroller = document.getElementById('inner_footer_'+this.GridId);
		this.FooterOuter = document.getElementById('outer_footer_'+this.GridId);
	}

	if (this.LeftCells != 0) {
		this.LeftHeaderTable = document.getElementById('left_header_'+this.GridId);
		this.LeftHeaderScroller = document.getElementById('inner_left_header_'+this.GridId);
		this.LeftHeaderOuter = document.getElementById('outer_left_header_'+this.GridId);
		this.LeftHeaderInner = document.getElementById('inner_left_header_'+this.GridId);

		this.LeftDataTable = document.getElementById('left_data_'+this.GridId);
		this.LeftDataOuter = document.getElementById('outer_left_data_'+this.GridId);
		this.LeftDataInner = document.getElementById('inner_left_data_'+this.GridId);

		if (this.HasFooter) {
			this.LeftFooterTable = document.getElementById('left_footer_'+this.GridId);
			this.LeftFooterInner = document.getElementById('inner_left_footer_'+this.GridId);
			this.LeftFooterOuter = document.getElementById('outer_left_footer_'+this.GridId);
		}
	}

	this.DataScroller.TheGrid = this;
	this.MainInner.TheGrid = this;
	if (this.LeftCells > 0) this.LeftDataInner.TheGrid = this;
//	this.Dot = document.getElementById('my_dot_'+this.GridId)

	this.MainOuter.className = 'grid-scrollable'
	if (!is.ie) {
//		this.MainOuter.style.marginLeft = '-1px';
	}
}

GridScroller.prototype.SetLeftHeights = function() {
	if (this.LeftCells != 0) {
		this.SetHeights('left_header_'+this.GridId, 'header_'+this.GridId);
		this.SetHeights('left_data_'+this.GridId, 'data_'+this.GridId);
		if (this.HasFooter()) {
			this.SetHeights('left_footer_'+this.GridId, 'footer_'+this.GridId);
		}
	}
}

GridScroller.prototype.UpdateColWidths = function() {
//	pos = findPos(this.Dot)
	pos = this.pos;

	this.TheGrid.style.left = (pos[0])+ 'px'
	this.TheGrid.style.top = (pos[1]) + 'px'

	this.SetLeftHeights();

	if (this.HasFooter()) {
		this.FooterHeight = this.FooterTable.offsetHeight;
		this.FooterOuter.style.height = this.FooterHeight + 'px'
	}
	else {
		this.FooterHeight = 0;
	}

	this.HeadHeight = this.HeadTable.offsetHeight;

//	console.log('measured Head Height: '+this.HeadHeight);

	this.DataHeight = this.DataTable.offsetHeight;
	this.HeadOuter.style.height = (this.HeadHeight) + 'px'

	if (this.LeftCells != 0) {
		this.LeftWidth = Math.max(this.LeftHeaderTable.offsetWidth, this.LeftDataTable.offsetWidth)
		this.LeftHeaderOuter.style.height = (this.HeadHeight) + 'px'
		if (this.HasFooter()) {
			this.LeftFooterOuter.style.height = (this.FooterHeight) + 'px'
			this.LeftWidth = Math.max(this.LeftWidth, this.LeftFooterTable.offsetWidth);
		}
//		console.log('measured Left Width: '+this.LeftWidth);
	}

	this.MainInner.onscroll = function() {
		this.TheGrid.SyncScroll()
	}

	this.MainOuter.style.width = 'auto'

	this.UpdateTotalDimensions();

	return true;
}

GridScroller.prototype.UpdateTotalDimensions = function()
{
	this.HeadHeight = this.HeadTable.offsetHeight;
	this.DataHeight = this.DataTable.offsetHeight;
	this.HeaderWidth = this.HeadTable.offsetWidth + this.LeftWidth - this.HeadTable.rows[0].cells[(this.HeadTable.rows[0].cells.length-1)].offsetWidth;
	this.DataTotalHeight = this.DataHeight + this.HeadHeight + this.FooterHeight;
}

GridScroller.prototype.ResetHeights = function(table1_id, table2_id)
{
	var table1 = document.getElementById(table1_id);
	var table2 = document.getElementById(table2_id);
	var height1_div, height2_div;

	for (var row=0; row<table1.rows.length; row++)
	{
		// reseting heights
		table1.rows[row].cells[0].style.height =  'auto';
		table2.rows[row].cells[0].style.height =  'auto';
		table1.rows[row].style.height = 'auto';
		table2.rows[row].style.height = 'auto';
		var height1_div = document.getElementById(table1_id+'_left_height_'+row);
		if (height1_div) {
			height1_div.style.height = 'auto';
		}
		var height2_div = document.getElementById(table2_id+'_left_height_'+row);
		if (height2_div) {
			height2_div.style.height = 'auto';
		}
	}
}

GridScroller.prototype.SetHeights = function(table1_id, table2_id)
{
	var table1 = document.getElementById(table1_id);
	var table2 = document.getElementById(table2_id);
	var height1_div, height2_div;

	this.ResetHeights(table1_id, table2_id);

	var heights1 = this.GetHeights(table1_id);
	var heights2 = this.GetHeights(table2_id);
	var table, the_height, num;

	for (var row = 0; row < table1.rows.length; row++) {
		if (heights1[row] > heights2[row]) {
			// table1 row's height is larger -> adjust table2 row's height
			the_height = heights1[row];
			table = table2;
			id = table2_id;
		}
		else {
			// table2 row's height is larger -> adjust table1 row's height
			the_height = heights2[row];
			table = table1;
			id = table1_id;
		}

		var height_div = document.getElementById(id + '_left_height_' + row);

		if (height_div) { // the div only exists for FF
			height_div.style.height = the_height+'px';
			height_div.style.width = table.rows[row].cells[0].clientWidth+'px'
		}
		else {
			if (!is.ie) { // firefox needs div, but it can display it as table-cell
				var width = table.rows[row].cells[0].clientWidth;
//				table.rows[row].cells[0].innerHTML = '<div id="'+id+'_left_height_'+row+'" style="display: table-cell; background-color: inherit; width: '+width+'px; height: '+(the_height) +'px; overflow: hidden;">' + table.rows[row].cells[0].innerHTML + '</div>'
			}
		}
		// IE can't display div as table-cell, but it respects the tr height

		if (document.all) {
			$(table.rows[row].cells[0]).height(the_height);
		}

		$(table.rows[row]).height(the_height);
	}
}

GridScroller.prototype.GetHeights = function(table_id)
{
	var heights = new Array();
	var table = document.getElementById(table_id);

	for (var row = 0; row < table.rows.length; row++) {
		var $cell = $( table.rows[row].cells[0] );
		heights.push( document.all ? $cell.height() : $cell.outerHeight() );
	}

	return heights;
}

GridScroller.prototype.GetWidths = function(table_id)
{
	var table = document.getElementById(table_id);
	var widths = new Array();
	if (!table.rows[0]) return [];
	for (var col=0; col<table.rows[0].cells.length; col++)
	{
		var tmp = getDimensions(table.rows[0].cells[col]);
		widths.push( tmp.innerWidth )
//		widths.push( table.rows[0].cells[col].offsetWidth )
		if (table_id.match(/^header_/)) {
//		alert('get ('+col+')'+table.rows[0].cells[col].innerHTML+' width '+table.rows[0].cells[col].offsetWidth)
		}
	}
	return widths;
}

GridScroller.prototype.SetResizeHandles = function()
{
	var points = new Array();

	if (this.LeftCells > 0) {
		var table = this.LeftHeaderTable;
		var points = new Array();
		if (!table.rows[0]) return [];
		for (var col=0; col<table.rows[0].cells.length; col++)
		{
			var tmp = findPos(table.rows[0].cells[col]);
			points.push(tmp);
		}
	}

	var table = this.HeadTable;
	if (!table.rows[0]) return [];
	for (var col=0; col<table.rows[0].cells.length; col++)
	{
		var tmp = findPos(table.rows[0].cells[col]);
		points.push(tmp);
	}
	var scroller = this;

	var resize_bar = document.getElementById(this.GridId + '[resize_bar]');
	if (!resize_bar) {
		resize_bar = addElement(document.body, 'div');
		resize_bar.id = this.GridId + '[resize_bar]';
	}

	resize_bar.style.display = 'none';
	resize_bar.style.width = '2px';
	resize_bar.style.height = '200px';
	resize_bar.style.backgroundColor = '#777';
	resize_bar.style.zIndex = 40;
	resize_bar.style.position = 'absolute';

	for (var i=1; i<points.length; i++) {
		var handle = document.getElementById(this.GridId + '[grid_resize_handle_' + i + ']');
		if (!handle) {
			handle = addElement(document.body, 'div');
			handle.id = this.GridId + '[grid_resize_handle_' + i + ']';
		}
		handle.style.width='6px';
		handle.style.height=this.HeadTable.offsetHeight+'px';
		handle.style.position='absolute';
//		handle.style.backgroundColor='red';
		handle.style.left = (points[i][0] - 3)+'px';
		handle.style.top = points[i][1]+'px';
		handle.style.zIndex = 50;
		handle.style.cursor = 'col-resize';
		handle.col_num = i-1;

		DragManager.MakeDragable(this.GridId + '[grid_resize_handle_' + i + ']',
			function(a_handle) {
				var resize_bar = document.getElementById(scroller.GridId + '[resize_bar]');
				var pos = findPos(a_handle);
				resize_bar.style.left = (pos[0])+'px';
				resize_bar.style.top = pos[1]+'px';
				resize_bar.style.height = scroller.Height+'px';
				resize_bar.style.display = 'block';
				var col_num = a_handle.col_num;
				DragManager.DragObject.min_col_width = scroller.GetColWidth(col_num);
			},
			function(drag_object, coords) {
				var offset = coords.x - DragManager.MouseOffset[0] - DragManager.InitialPos[0];
				if (parseInt(DragManager.DragObject.min_col_width) + offset > 15)  {
					var resize_bar = document.getElementById(scroller.GridId + '[resize_bar]');
					resize_bar.style.left = (coords.x - DragManager.MouseOffset[0] + 2) + 'px';
				}
			},
			function(a_handle) {
				var resize_bar = document.getElementById(scroller.GridId + '[resize_bar]');
				resize_bar.style.display = 'none';
				coords = findPos(a_handle);
				var offset = (coords[0] - DragManager.InitialPos[0]);
//				alert('offset: '+offset+' ('+coords[0]+' - '+DragManager.MouseOffset[0]+' - '+DragManager.InitialPos[0]+')');
				var col_num = a_handle.col_num;
				var cur_w = scroller.GetColWidth(col_num);
				if (cur_w + offset < 15) {
					offset = 15-cur_w;
				}
				scroller.SetColWidth(col_num, cur_w+offset);
				scroller.Resize( scroller.GetAutoSize() );
				scroller.ScrollResizeHandles();
				DragManager.InitialPos = [coords[0] - DragManager.MouseOffset[0], coords[1] - DragManager.MouseOffset[1]];

			},
			{VerticalDrag: false}
		)
	}
}

GridScroller.prototype.GetColWidth = function(col)
{
	return this.MinWidths[col];
}

GridScroller.prototype.AdjustInputWidths = function()
{
	var elems = new Array();
	var inputs = this.HeadTable.getElementsByTagName('INPUT');
	for (var i=0; i<inputs.length; i++) {elems[elems.length] = inputs[i];}
	var selects = this.HeadTable.getElementsByTagName('SELECT');
	for (var i=0; i<selects.length; i++) {elems[elems.length] = selects[i];}
	if (this.LeftCells > 0) {
		var left_inputs = this.LeftHeaderTable.getElementsByTagName('INPUT');
		for (var i=0; i<left_inputs.length; i++) {elems[elems.length] = left_inputs[i];}
		var left_selects = this.LeftHeaderTable.getElementsByTagName('SELECT');
		for (var i=0; i<left_selects.length; i++) {elems[elems.length] = left_selects[i];}
	}
	var widths = new Array()
	for (var i=0; i<elems.length; i++) {
		elems[i].style.width = '1px';
	}
	for (var i=0; i<elems.length; i++) {
		var input_dim = getDimensions(elems[i]);
		var parent_dim = getDimensions(elems[i].parentNode);
		widths[i] = (parent_dim.innerWidth - parent_dim.borders[1] - parent_dim.borders[3] - input_dim.borders[1] - input_dim.borders[3] - 2)+'px';
	}
	for (var i=0; i<elems.length; i++) {
		try {
			elems[i].style.width = widths[i];
		}
		catch (e) {
			// IE don't allow to set width for hidden element
//			alert('IE exception:' + e);
		}
	}
}

GridScroller.prototype.SetColWidth = function(col, width)
{
	if (col >= this.LeftCells) {
		if (this.DataTable.rows.length) this.DataTable.rows[0].cells[col - this.LeftCells].style.width = width+'px';
		for (var row=0; row < this.HeadTable.rows.length; row++)
		{
			this.HeadTable.rows[row].cells[col - this.LeftCells].style.width = width+'px';
			var a = document.getElementById(this.GridId + '[cursor_work_around_A_'+col+'_'+row+']');
			var b = document.getElementById(this.GridId + '[cursor_work_around_B_'+col+'_'+row+']');
			if (a) a.style.width = width+'px';
			if (b) b.style.width = width+'px';
		}
		if (this.HasFooter()) {
			this.FooterTable.rows[0].cells[col - this.LeftCells].style.width = width+'px';
		}
	}
	else {
		if (this.LeftDataTable.rows.length) this.LeftDataTable.rows[0].cells[col].style.width = width+'px';
		for (var row=0; row < this.LeftHeaderTable.rows.length; row++)
		{
			this.LeftHeaderTable.rows[row].cells[col].style.width = width+'px';
			var a = document.getElementById(this.GridId + '[cursor_work_around_A_'+col+'_'+row+']');
			var b = document.getElementById(this.GridId + '[cursor_work_around_B_'+col+'_'+row+']');
			if (a) a.style.width = width+'px';
			if (b) b.style.width = width+'px';
		}
		if (this.HasFooter()) {
			this.LeftFooterTable.rows[0].cells[col].style.width = width+'px';
		}

		var cur_left_total_w = 0;
		var new_left_total_w = 0;
		for (var i=0; i < this.LeftCells; i++) {
			cur_left_total_w += this.MinWidths[i];
			new_left_total_w += i==col? width : this.MinWidths[i];
		};
		var left_diff = this.LeftWidth - cur_left_total_w;

		this.SetLeftWidth(new_left_total_w+left_diff);
	}
	this.AdjustInputWidths();

	this.MinWidths[col] = width;
	this.SetLeftHeights();
	this.UpdateTotalDimensions();
	this.SyncScroll();
	this.ScheduleSaveWidths();
}

GridScroller.prototype.ScrollResizeHandles = function()
{
	for (var col=1; col<this.LeftHeaderTable.rows[0].cells.length; col++)
	{
		var handle = document.getElementById(this.GridId + '[grid_resize_handle_' + col + ']');
		if (!handle) return;
		var pos = findPos(this.LeftHeaderTable.rows[0].cells[col]);
		handle.style.left = (pos[0]-3)+'px';
	}

	if (this.HeadTable.rows[0].cells.length) {
		var left_most_pos = findPos(this.HeadTable.rows[0].cells[0]);
		var handle = document.getElementById(this.GridId + '[grid_resize_handle_' + (this.LeftCells) + ']');
		if (handle) handle.style.left = (left_most_pos[0]-3)+'px';
	}

	for (var col=1; col<this.HeadTable.rows[0].cells.length; col++)
	{
		var handle = document.getElementById(this.GridId + '[grid_resize_handle_'+(col+this.LeftCells)+']');
		if (!handle) continue;
		var pos = findPos(this.HeadTable.rows[0].cells[col]);
		var n_left = pos[0]-this.MainInner.scrollLeft-3
		if (n_left <= left_most_pos[0] || n_left > left_most_pos[0] + this.DataOuter.clientWidth) {
			handle.style.display = 'none'; //resize handle is outside of visible range
		}
		else {
			handle.style.display = 'block';
		}
		handle.style.left = n_left+'px';
	}
}

GridScroller.prototype.GetAutoSize = function(h)
{
	this.MainOuter.style.width = 'auto'
	var w = this.MainInner.offsetWidth;

	if (!isset(h)) {
		h = this.MaxHeight; // 'auto';
	}

	if (h == 'auto') {
		var h = document.body.clientHeight;

		var pos = findPos(this.MainOuter);

		var dim = getDimensions(this.MainOuter);

		h -= pos[1] + dim.padding[0] + dim.padding[2] + dim.borders[0] + dim.borders[2] + this.BottomOffset;
	}

	return [w, h];
}


GridScroller.prototype.AutoResize = function()
{
	var obj = this;
	if (this.ResizeHappening && this.ResizeTimer) {
		window.clearTimeout(this.ResizeTimer);
		this.ResizeTimer = false;
	}
	this.ResizeHappening = true;
	this.ResizeTimer = window.setTimeout(function() {
			// GridScroller sets references to it's elements after Render method is called (once).
			// When grid elements are replaced from ajax responce, then all stored
			// refrences are invalid (GridScroller.Render method is called after this timer is execuded).
			// To prevent "Unspecified error" in IE reset all references.

			obj.SetReferences();
			obj.RefreshPos();
			obj.Resize( obj.GetAutoSize() );
			obj.ResizeHappening = false;
		}, 300)
}

GridScroller.prototype.RefreshPos = function() {
	var dot = document.getElementById('my_measure_'+this.GridId);
	this.pos = findPos(dot);

	if (is.ie) {
		// measure div is moved left for 1 pixel in IE during resize (nothing strange, it's IE)
		this.pos[0] += 1;
	}
}

GridScroller.prototype.Resize = function(w,h)
{
//	alert('-1');

	if (typeof(w) == 'object') {
		h = w[1];
		w = w[0];
	}
	if (w) this.Width = w;
	if (h) this.Height = h;

	var x,y;
//	pos = findPos(this.Dot)
	pos = this.pos;
	x = pos[0];
	y = pos[1];

	this.TheGrid.style.left = (x)+ 'px'
	this.TheGrid.style.top = (y) + 'px'
//	alert('moved');

//	alert('0');

	this.MainOuter.style.height = (this.Height)+'px'
	this.MainOuter.style.width = (this.Width)+'px'

//	alert('1');

	var scroller_width;

//	this.HeadTable.rows[0].cells[(this.HeadTable.rows[0].cells.length-1)].offsetWidth

	scroller_height = this.HeaderWidth > this.Width ? this.ScrollerH : 0;
	scroller_width =  this.DataTotalHeight > this.Height - scroller_height ? this.ScrollerW : 0;
	scroller_height = this.HeaderWidth > this.Width - scroller_width ? this.ScrollerH : 0;

//	alert('min: '+this.MinDataWidth+' pos: '+pos[0]+','+pos[1]+' scroller W x H: '+scroller_width+' x '+scroller_height+' will resize to '+this.Width+' x '+this.Height+' data: '+this.HeaderWidth+' x '+this.DataHeight)

	this.HeadOuter.style.width = (this.Width -scroller_width -this.LeftWidth)+ 'px';
	this.DataOuter.style.width = (this.Width -scroller_width -this.LeftWidth)+ 'px';

//	alert('1.2');

	this.TheGrid.style.width = (this.Width - scroller_width) + 'px';
	this.TheGrid.style.height = (this.Height - scroller_height) + 'px';

//	alert('1.5');

	this.SetLeftWidth();

//	alert('2');

	if (this.HasFooter()) {
		this.FooterOuter.style.width = (this.Width -scroller_width -this.LeftWidth)+ 'px';
	}

	if (this.DataTotalHeight < this.Height - scroller_height) {
		var adjusted_data_height = this.DataTotalHeight - this.HeadHeight - this.FooterHeight
	}
	else {
		var adjusted_data_height = this.Height - this.HeadHeight - this.FooterHeight - scroller_height
	}

	this.DataOuter.style.height = adjusted_data_height + 'px'
	if (this.LeftCells != 0) {
		this.LeftDataOuter.style.height = adjusted_data_height + 'px'
	}

//	alert('3');

	this.MainScroller.style.width = (this.HeadTable.offsetWidth + this.LeftWidth)+'px'
	this.MainScroller.style.height = ( this.DataHeight + this.HeadHeight + this.FooterHeight)+'px'

//	alert('4');
}

GridScroller.prototype.SetLeftWidth = function(left_width)
{
	if (left_width) this.LeftWidth = left_width;
	if (this.LeftCells != 0) {

		// there was -1 for Mozilla, but somehow it's not needed anymore...
		this.LeftHeaderOuter.parentNode.style.width = (this.LeftWidth + (is.ie ? 0 : 0) ) + 'px';

		this.LeftHeaderOuter.style.width = (this.LeftWidth) + 'px';
		this.LeftHeaderInner.style.width = (this.LeftWidth) + 'px';

		this.LeftDataOuter.style.width = (this.LeftWidth) + 'px';
		this.LeftDataInner.style.width = (this.LeftWidth) + 'px';
		if (this.HasFooter()) {
			this.LeftFooterOuter.style.width = (this.LeftWidth) + 'px';
			this.LeftFooterInner.style.width = (this.LeftWidth) + 'px'
		}

		// this is IE workaround, we have to set inner div width to given px (above) and then back to 100%
		// for IE to readjust the surrounding tables, otherwise it memorizes inner div pixel width and
		// cannot make surrounding table cells smaller then that
		this.LeftHeaderInner.style.width = '100%';
		this.LeftDataInner.style.width = '100%';
		if (this.HasFooter()) {
			this.LeftFooterInner.style.width = '100%';
		}
	}
}

GridScroller.prototype.SyncScroll = function()
{
	this.HeadScroller.scrollLeft = this.MainInner.scrollLeft;
	this.DataScroller.scrollLeft = this.MainInner.scrollLeft;
	if (this.HasFooter()) {
		this.FooterScroller.scrollLeft = this.MainInner.scrollLeft;
	}

	this.DataScroller.scrollTop = this.MainInner.scrollTop;
	if (this.LeftCells != 0) {
		this.LeftDataInner.scrollTop = this.MainInner.scrollTop;
	}
	this.ScrollResizeHandles();
}

GridScroller.prototype.AltHTML = function(x,y,w,h)
{
	var o = '';

	o += this.CreateScroller( '<div id="main_scroller_'+this.GridId+'" style="background-color: inherit; position: relative; width: auto; z-index: 20; height: '+(h)+'px;"></div>', w, h, 'main_'+this.GridId, false, 1, 'grid-scrollable' );

//	console.log(o)

//	return o+'</div>'

	o += '<div id="'+this.GridId+'" class="grid-container" style="background-color: inherit; position: absolute; left: '+(x)+'px; top: '+(y)+'px; visibility: visible; z-index: 10; width: auto; height: '+(h)+'px; overflow: hidden;">';

	var header_rows = this.Header.length;
	var cols = this.Header[0].length;
	var data_rows = this.Data.length;
	var footer_rows = this.Footer.length;

	var header_h = 80;
	if (this.LimitedHeights) {
		for (var i=0; i<this.MaxHeaderHeights.length; i++) {header_h += this.MaxHeaderHeights[i]};
		header_h += this.MaxHeaderHeightCorrection;
	}
	data_h = h - header_h;


//	console.log('header_h: %i, data_h: %i', header_h, data_h)

	var header = 'b';
	var data = 'd';
	var footer = 'f';
	var left_header = '1';
	var left_data = 'c';
	var left_footer = 'e';
	var header = this.GetTableWithScroller(this.Header, [this.LeftCells, 0, cols, header_rows], 'header', null, null, null, header_h)
	var data = this.GetTableWithScroller(this.Data, [this.LeftCells, 0, cols, data_rows], 'data', 'grid-data-row-even', '', null, data_h)
	var footer = this.HasFooter() ? this.GetTableWithScroller(this.Footer, [this.LeftCells, 0, cols, footer_rows], 'footer') : '';

	var left_header = this.GetTableWithScroller(this.Header, [0,0,this.LeftCells, header_rows], ['header','left_header'], null, null, null, header_h)
	var left_data = this.GetTableWithScroller(this.Data, [0,0,this.LeftCells, data_rows], ['data','left_data'], 'grid-data-row-even', 'left_', null, data_h)
	var left_footer = this.GetTableWithScroller(this.Footer, [0,0,this.LeftCells, footer_rows], ['footer','left_footer'])

	/*var css = '';
	for (var i=0;i<this.Header[0].length; i++) {
		css += '.width-adj-grid-col-'+i+' {} ';
	}
	o += '<style type="text/css">'+css+'</style>';*/

	if (this.LeftCells != 0) {
		o += '<table style="width: 100%; table-layout: fixed; border-collapse: collapse;">\n'
		o += '<tr>\n<td style="vertical-align: top; margin: 0px; padding: 0px;">\n' + left_header + '\n</td>\n'
		o += '<td style="vertical-align: top; margin: 0px; padding: 0px;">\n' + header + '\n</td>\n</tr>\n'

		o += '<tr>\n<td style="vertical-align: top; margin: 0px; padding: 0px;">\n' + left_data + '\n</td>\n'
		o += '<td style="vertical-align: top; margin: 0px; padding: 0px;">\n' + data + '\n</td>\n</tr>\n'

		if (this.HasFooter()) {
			o += '<tr><td style="vertical-align: top; margin: 0px; padding: 0px">' + left_footer + '</td>'
			o += '<td style="vertical-align: top; margin: 0px; padding: 0px">' + footer + '</td></tr>'
		}
		o += '</table>\n'
	}
	else {
		o += header + data + footer;
	}
	o += '</div>';
	return o;
}

GridScroller.prototype.PrepareWidths = function()
{
	cache = getFrame('head').grid_widths_cache;
	if (!isset(cache)) {
		cache = new Object
	}

	if (this.MinWidths.length >= this.Header[0].length) {
		var has_all_widths = true;
		for (var i=0; i < this.MinWidths.length; i++) {
			if (isNaN(parseInt(this.MinWidths[i]))) {
				this.MinWidths[i] = 100;
//				has_all_widths = false;
			}
		}
		if (has_all_widths) {
			widths = this.MinWidths
			cache[this.GridId+'_'+this.PickerCRC] = widths;
			return widths;
		}
	}

	if (cache[this.GridId+'_'+this.PickerCRC]) {
		// return cache[this.GridId+'_'+this.PickerCRC]
	}

//	print_pre(this.MinWidths)
	var o = '';
	data = this.Header.concat(this.Data).concat(this.Footer);
	o += this.GetTableCells(this.Header, [0,0,this.Header[0].length,this.Header.length], 'header', null, null, false, true)[0];
	if (this.Data.length) {
		var data= this.GetTableCells(this.Data, [0,0,this.Data[0].length,this.Data.length], 'data', null, null, false, true)[0];
		o += data;
	}
	var w = document.all ? window.document.body.offsetWidth : window.innerWidth
	var table_width = w < 500 ? '1024px' : 'auto';
//	console.log('tmp table width: %s (window width: %s)', table_width, w)
	o = '<table style="visibility: visible; width: '+table_width+'; border-collapse: collapse" id="tmp_'+this.GridId+'">'+o+'</table>'

	document.write(o)
	widths = this.GetWidths('tmp_'+this.GridId);
//	print_pre(widths)

	tmp_el = document.getElementById('tmp_'+this.GridId);
	var p = tmp_el.parentNode;
	p.removeChild(tmp_el);
	cache[this.GridId+'_'+this.PickerCRC] = widths;
	return widths;
}

GridScroller.prototype.GetTableWithScroller = function(source, dim, class_mode, even_class, id_prefix, w, h)
{
//	console.log(source, dim, class_mode, even_class, id_prefix, w, h)
	var tmp = this.GetIdAndClassName(class_mode);
	var id = tmp[1];
	if (!h) h = 100;
	var cells = this.GetTableCells(source, dim, class_mode, even_class, id_prefix);
	// var cells = this.GetTableCells(source, dim, class_mode, even_class, id_prefix, false, true);
//	console.log('createing scroller %s w,h: %i,%i', id, cells[1],h)
	return this.CreateScroller('<table style="table-layout: fixed; width: 100%;" id="'+id+'_'+this.GridId+'">\n'+cells[0]+'\n</table>\n\n', cells[1], h, id+'_'+this.GridId, true, 5);
}

GridScroller.prototype.GetIdAndClassName = function(class_mode)
{
	if (typeof(class_mode)=='object') {
		var class_name = class_mode[0];
		var id = class_mode[1]
	}
	else {
		var class_name = class_mode;
		var id = class_mode;
	}
	return [class_name, id]
}

GridScroller.prototype.GetTableCells = function(source, dim, class_mode, even_class, id_prefix, needs_last, no_inner_div)
{
	if (!source.length) return ['', 0];
	var o = '';
	var start_col = dim[0];
	var start_row = dim[1];
	var end_col = dim[2];
	var end_row = dim[3];
	var even = false;
	if (!even_class) even_class = '';
	var tmp = this.GetIdAndClassName(class_mode);
	var class_name = tmp[0];
	var id = tmp[1];
	if (id_prefix==null) id_prefix = id;
	var needs_last = needs_last == null ? (end_col == (source[0].data ? source[0].data.length : source[0].length)) : needs_last;
	var total_width = 0;
	var width_printed = false;

	for (var row=start_row; row<end_row; row++) {
		row_data = source[row].data ? source[row].data : source[row];

		var rh = '';
		var row_id = this.IDs[row] ? 'id="'+id_prefix+this.IDs[row]+'"' : '';

		var row_class = 'grid-'+class_name+'-row '+(even ? even_class : '')+' grid-'+class_name+'-row-'+row + (source[row].row_class ? ' '+source[row].row_class : '');
		rh +='<tr '+row_id+' class="'+row_class+'" sequence="'+(row+1)+'">'+"\n"
		even = !even;

		total_width = 0;

		if (this.LimitedHeights) {
			var row_height = id.match(/^(left_)?header/) ? this.MaxHeaderHeights[row]+'px;' : this.MaxRowHeight+'px;'
			var height_style = id.match(/^(left_)?header/) ? 'height: '+this.MaxHeaderHeights[row]+'px;' : 'height: '+this.MaxRowHeight+'px;';
		}
		else {
			var row_height = 'auto'
			var height_style = '';
		}

		for (var col=start_col; col<end_col; col++) {
			total_width += this.MinWidths[col]+12;

			var cursor_workaround = ['',''];
			if (id.match(/^(left_)?header/) && is.gecko) {
				cursor_workaround = ['<div id="' + this.GridId + '[cursor_work_around_A_'+col+'_'+row+']" style="width: '+(this.MinWidths[col])+'px; overflow: auto;"><div id="' + this.GridId + '[cursor_work_around_B_'+col+'_'+row+']" style="width: '+(this.MinWidths[col])+'px; overflow: hidden;">', '</div></div>'];
			}
			else {
				if (this.LimitedHeights) {
					cursor_workaround = ['<div id="_clipper_'+col+'_'+row+'" style="'+(is.ie ? '' : 'display: table-cell; ')+'vertical-align: inherit; overflow: hidden; max-height: '+row_height+'"><div style="overflow: hidden; max-height: '+row_height+'">','</div></div>'];
				}
			}

			var width_style = width_printed ? '' : 'width: '+this.MinWidths[col]+'px;"'
			var td_style = 'style="overflow: hidden; max-height: '+row_height+'; '+width_style+'"';
			var td_class = 'grid-'+class_name+'-col-'+col;
			if (this.FieldNames) {
				td_class += ' '+this.FieldNames[col];
			}
			rh += "\t"+'<td '+td_style+' class="'+td_class+'">'+cursor_workaround[0]+row_data[col]+cursor_workaround[1]+'</td>'+"\n"
		}
		width_printed = true; // print widths in first row only
		if (needs_last) {
			rh += "\t"+'<td class="grid-'+class_name+'-last-cell"><img src="'+this.Spacer+'" width="1" height="1" alt=""/></td>'+"\n"
		}
		rh += '</tr>'+"\n"
		o += rh;
	}
	return [o, total_width];
}


GridScroller.prototype.HasFooter = function()
{
	return (this.Footer != false)
}

var colors = ['red', 'blue', 'green', 'pink', 'orange', 'brown', 'yellow', 'magenta', '#999', '#AAA', '#BBB', '#CCC', '#DDD', '#EEE', '#FFF'];
var next_color = 0;

GridScroller.prototype.CreateScroller = function(content, w, h, id, hidden, z, outer_class)
{
//	console.log('creating scroller: ',w,h,id,hidden,z)
	if (hidden) {
		overflow = 'hidden'
	}
	else {
		overflow = 'auto'
	}
	if (!z) {
		z = 0;
	}
	if (id && id != '') {
		outer_id = 'id="outer_'+id+'"';
		inner_id = 'id="inner_'+id+'"';
	}
	else {
		outer_id = '';
		inner_id = '';
	}
	var o = '';
	if (!outer_class) outer_class='scoller-outer';
	o += '<div '+outer_id+' class="'+outer_class+'" style="z-index: '+z+'; width: '+w+'px; height: '+h+'px;">'
	o += '<div '+inner_id+' class="scroller-inner" style="z-index: '+z+'; width: 100%; height: 100%; overflow: '+overflow+'; position: relative;">'
	o += content
	o += '</div></div>'
	return o
}

GridScroller.prototype.SetData = function(a_data)
{
	this.Data = a_data;
}

GridScroller.prototype.SetHeader = function(a_header)
{
	this.Header = a_header;
	this.MaxHeaderHeightCorrection = (6*this.Header.length)+1;
}

GridScroller.prototype.SetFooter = function(a_footer)
{
	this.Footer = a_footer;
}

GridScroller.prototype.SaveWidths = function()
{
	if (!this.SaveURL) return;
	var w = this.MinWidths.join(':');
	Request.makeRequest(this.SaveURL.replace('#WIDTHS#', w), this.BusyRequest, '', this.successCallback, this.errorCallback, '', this);
}

GridScroller.prototype.ScheduleSaveWidths = function()
{
	var obj = this;
	if (this.SaveWidthsScheduled && this.SaveWidthsTimer) {
		window.clearTimeout(this.SaveWidthsTimer);
		this.SaveWidthsTimer = false;
	}
	this.SaveWidthsScheduled = true;
	this.SaveWidthsTimer = window.setTimeout(function() {
			obj.SaveWidths();
			obj.SaveWidthsScheduled = false;
		}, 800)
}