function GEOTabGridObject(container, options) {
	var self = this;
	this.options = {
		// Level 1
		Elements : [], // Full list can be: ["selector","path","filter","grid",
						// "buttons"]
		onFilter : null,
		onRowClick : null,
		onAdd : null,
		onDelete : null,
		onEdit : null,
		onSelectorChange : null,
		blCheckboxes : false,
		// Level 2
		rootPId : 9998, // the root pId of the nodes
		filterEmptyText : "Type here to search for item",
		checkboxesLabel : "Select All/None",
		rootLabel : "Back to Top",
		iptDisabledClass : "geo_iptFilterDisabled",
		iptEnabledClass : "geo_iptFilterEnabled",
		iconGroup : "/gfx/groupIcon.gif",
		iconLevelUp : "/gfx/iconLevelUp.gif",
		iconDevice : "/gfx/iconDevice.gif",
		iconDriver : "/gfx/iconDriver.gif",
		trNormalClass : "geo_normalRow",
		trSelectedClass : "geo_selectedRow",
		elementID : {
			"grid" : "geo_groups_grid",
			"selector" : "geo_groups_selector",
			"filter" : "geo_filter",
			"path" : "geo_groupPath",
			"buttons" : "geo_buttonArea"
		},
		dialogWindowClass : "dialogWindow",
		dialogWindowIptClass : "geo_ipt",
		btnClass : "btn",
		addBtnLbl : "Add",
		delBtnLbl : "Remove",
		editBtnLbl : "Edit"
	};

	// debug (paddings)
	this._extHeightSubst = 40;
	// container of object
	this.container = null;
	// container of table
	this.table = null;
	// filter (input)
	this.filter = null;
	// path container
	this.path = null;
	// buttons Area
	this.buttons = null;
	// Selector area
	this.selector = null;
	// the tree: struct with all the possible nodes. {pId,name}
	this.pathTree = {};
	// current html tr row.
	this.currentRow = null;
	// data of the rows
	this.currentRowData = {};
	// the cutrrent pId of the nodes
	this.current_pId = this.options.rootPId;

	// Init options
	this.initOptions = function(options) {
		for ( var i in options) {
			this.options[i] = options[i];
		}
	};
	// init all the containers.
	this.init = function(container) {
		this.current_pId = this.options.rootPId;
		this.container = document.getElementById(container) || null;
		for ( var i = 0; i < this.options.Elements.length; i++) {
			switch (this.options.Elements[i]) {
			case "grid":
				if (this.options.blCheckboxes)
					this.initCheckboxes();
				this.initTable();
				break;
			case "filter":
				this.initFilter();
				break;
			case "buttons":
				this.initButtons();
				break;
			case "selector":
				this.initSelector();
				break;
			case "path":
				this.initPath();
				break;
			}
		}
		var filterString = self.getFilter();
		var selectorValue = self.getSelector();
		self.options.onRowClick(this.current_pId, filterString, selectorValue,
				self.fillWithData);
		this.fixHeight();
	};
	// make the html text correct for display as normal text on the page
	this.htmlFormat = function(str) {
		str = str || "";
		str = str.replace(/>/gi, "&gt;");
		str = str.replace(/</gi, "&lt;");
		return str;
	};

	this.getComponentsHeights = function() {
		return (this.path ? this.path.scrollHeight : 0)
				+ (this.filter ? this.filter.scrollHeight : 0)
				+ (this.buttons ? this.buttons.scrollHeight : 0)
				+ (this.selector ? this.selector.scrollHeight : 0);
	};
	this.fixHeight = function() {
		this.container.style.height = Math.max(this.options.dataTableHeight,
				150)
				+ "px";
		var h = Math.max(this.options.dataTableHeight, 150)
				- this.getComponentsHeights() - 32;
		this.table.parentNode.style.height = h + "px";
	};
	this._find = function(ar, v) {
		for ( var i = 0; i < ar.length; i++)
			if (ar[i] == v)
				return true;
		return false;
	};

	// ///////////////////////////////////////////////
	// Init Selector Line
	this.initSelector = function() {
		var div = this.container.appendChild(document.createElement("DIV"));
		div.id = this.options.elementID["selector"];
		div.appendChild(document.createElement("SELECT"));
		div.firstChild.options[0] = new Option("Device", "device");
		div.firstChild.options[1] = new Option("Driver", "driver");
		div.firstChild.onchange = function() {
			var filterString = self.getFilter();
			var selectorValue = self.getSelector();
			if (self.options.onSelectorChange) {
				self.options.onSelectorChange(self.current_pId, filterString,
						selectorValue, self.fillWithData);
			}
			$('.geo_checkBoxesDiv > INPUT').get(0).checked = false;
		};
		this.selector = div;
	};
	this.getSelector = function() {
		var str = (!this.selector) ? "" : this.selector.firstChild.value;
		return str;
	};

	// ///////////////////////////////////////////////
	// Init Checkboxes line
	this.initCheckboxes = function() {
		var div = this.container.appendChild(document.createElement("DIV"));
		div.className = "geo_checkBoxesDiv";

		var ipt = document.createElement("INPUT");
		ipt.type = "checkbox";
		div.appendChild(ipt);
		div.appendChild(document.createTextNode(this.options.checkboxesLabel));
		// div.innerHTML = '<input type="checkbox"/>
		// '+this.options.checkboxesLabel;
		div.firstChild.onclick = function() {
			self.checkAll(this.checked);
		};
	};
	this.checkAll = function(mode) {
		for ( var i = 0; i < this.table.rows.length; i++) {
			var c = this.table.rows[i].cells[0];
			if (c.firstChild && c.firstChild.type == 'checkbox')
				c.firstChild.checked = mode;
		}
	};
	this._getAllchecked = function() {
		var res = [];
		for ( var i = 0; i < this.table.rows.length; i++) {
			var c = this.table.rows[i].cells[0];
			if (c.firstChild && c.firstChild.type == 'checkbox'
					&& c.firstChild.checked)
				res[res.length] = c.firstChild.value;
		}
		return res;
	};
	this.getChecked = function(types) {
		var res = {};
		for ( var i = 0; i < types.length; i++)
			res[types[i]] = [];
		var values = this._getAllchecked();
		for ( var i = 0; i < values.length; i++) {
			var type = values[i].split("_")[0];
			if (!res[type])
				res[type] = [];
			res[type][res[type].length] = values[i].split("_")[1];
		}
		var result = [];
		for ( var i = 0; i < types.length; i++)
			result[i] = res[types[i]];
		return result;
	};

	// ///////////////////////////////////////////////
	// Init filter
	this.initFilter = function() {
		var div = this.container.appendChild(document.createElement("DIV"));
		div.id = this.options.elementID["filter"];
		var ipt = document.createElement("INPUT");
		ipt.className = this.options.iptDisabledClass;
		ipt.value = this.options.filterEmptyText;
		div.appendChild(ipt);
		ipt.style.width = parseInt(div.offsetWidth) - 26 - 1 + 'px';
		// div.innerHTML = '<input type="text"
		// class="'+this.options.iptDisabledClass+'"
		// value="'+this.options.filterEmptyText+'"/>';
		this.filter = div.firstChild;
		this.filter.onfocus = function() {
			if (self.filter.className == self.options.iptDisabledClass) {
				self.filter.className = self.options.iptEnabledClass;
				self.filter.value = "";
			}
		};
		this.filter.onblur = function() {
			if (self.filter.value == "") {
				self.filter.className = self.options.iptDisabledClass;
				self.filter.value = self.options.filterEmptyText;
			}
		};
		this.filter.onkeypress = function(e) {
			e = e || window.event;
			if (e.keyCode == 13)
				self.applyFilter();
		};
		
	};
	this.getFilter = function() {
		var str = (!this.filter
				|| this.filter.className == this.options.iptDisabledClass || this.filter.value == "") ? "%"
				: this.filter.value.replace(/\*/gi, "%");
		return str;
	};
	this.cleanFilter = function() {
		this.filter.className = this.options.iptDisabledClass;
		this.filter.value = this.options.filterEmptyText;
		window.focus();
	};
	// apply filter to the content in the container
	this.applyFilter = function() {
		var filterString = this.getFilter();
		var selectorValue = this.getSelector();
		if (this.options.onFilter) {
			this.options.onFilter(this.current_pId, filterString,
					selectorValue, this.fillWithData);
		}
	};
	// ///////////////////////////////////////////////

	// ///////////////////////////////////////////////
	// container
	this.initTable = function() {
		var div = this.container.appendChild(document.createElement("DIV"));
		div.id = this.options.elementID["grid"];
		tbl = document.createElement("TABLE");
		tbl.cellPadding = "0";
		tbl.cellSpacing = "0";
		tbl.style.emptyCells = "show";
		tbl.appendChild(document.createElement("TBODY"));
		this.table = div.appendChild(tbl);
	};
	this.getSelectedItem = function() {
		return (this.currentRow ? {
			id : this.currentRowData[this.currentRow.id],
			name : this.currentRowData[this.currentRow.id].name,
			pId : this.current_pId
		} : {
			id : 0,
			name : "",
			pId : this.current_pId
		});
	};
	this._addRow = function(id, lbl, type) {
		// Path is alerady exists so we have to add this value manually
		self.addToPath(id, lbl);
		self.addRow(id, lbl, type);
	};
	this.addRow = function(id, lbl, type) {
		type = type || "group";
		var icon = "";
		switch (type) {
		case "group":
			icon = this.options.iconGroup;
			break;
		case "levelUp":
			icon = this.options.iconLevelUp;
			break;
		case "device":
			icon = this.options.iconDevice;
			break;
		case "driver":
			icon = this.options.iconDriver;
			break;
		}
		this.currentRowData[id] = {
			id : id,
			name : lbl
		};
		var tr = this.table.insertRow(id == 0 ? 0 : -1);
		tr.id = id;
		tr.onselectstart = function() {
			return false;
		};
		tr.insertCell(-1);
		tr.insertCell(-1);
		tr.cells[0].style.width = this.options.blCheckboxes ? '40px' : "22px";

		if (this.options.blCheckboxes&&type!="levelUp")
			$("<input type='checkbox' />").attr('value', type + "_" + id)
					.appendTo(tr.cells[0]);
		else 
			if (this.options.blCheckboxes&&type=="levelUp")
				$("<div class='checkbox'>&nbsp;</div>").appendTo(tr.cells[0]);
		var img = document.createElement("IMG");
		img.src = icon;
		img.align = "top";
		tr.cells[0].appendChild(img);
		// tr.cells[0].innerHTML=(this.options.blCheckboxes?'<input
		// value="'+type+"_"+id+'" type="checkbox" />':"")+'<img src="'+icon+'"
		// align="top"/>';

		tr.cells[1].appendChild(document.createTextNode(this.htmlFormat(lbl)));
		// tr.cells[1].innerHTML=this.htmlFormat(lbl)+"&nbsp;";
		tr.title = lbl;
		tr.className = this.options.trNormalClass;
		tr.onclick = function() {
			if (self.currentRow)
				self.currentRow.className = self.options.trNormalClass;
			self.currentRow = this;
			self.currentRow.className = self.options.trSelectedClass;
		};
		if (this._find( [ "group", "levelUp" ], type))
			if (this.options.onRowClick)
				tr.ondblclick = function() {
					var filterString = self.getFilter();
					var selectorValue = self.getSelector();
					var id = this.id;
					if (id == 0)
						id = self.pathTree[self.current_pId].pId;
					self.options.onRowClick(id, filterString, selectorValue,
							self.fillWithData);
				};
	};

	this._setRowName = function(id, name) {
		self.setRowName(id, name);
	};
	this.setRowName = function(id, name) {
		for ( var i = this.table.rows.length - 1; i >= 0; i--)
			if (this.table.rows[i].id == id) {
				// this.table.rows[i].cells[1].innerHTML =
				// this.htmlFormat(name);
				this.table.rows[i].cells[1].appendChild(document
						.createTextNode(this.htmlFormat(name)));
				break;
			}
		this.pathTree[id].name = name;
	};
	this._deleteRow = function(id) {
		self.deleteRow(id);
	};
	this.deleteRow = function(id) {
		for ( var i = this.table.rows.length - 1; i >= 0; i--)
			if (this.table.rows[i].id == id) {
				this.table.deleteRow(i);
				break;
			}
		for ( var i in this.pathTree)
			if (this.pathTree[i].pId == id)
				this.pathTree[i].pId = this.pathTree[id].pId;
		this.pathTree[id] = null;
	};
	this.cleanTable = function() {
		for ( var i = this.table.rows.length - 1; i >= 0; i--)
			this.table.deleteRow(i);
	};
	// ///////////////////////////////////////////////

	// ///////////////////////////////////////////////
	// Init Path
	this.initPath = function() {
		this.path = this.container.appendChild(document.createElement("DIV"));
		this.path.id = this.options.elementID["path"];
		this.pathTree[this.options.rootPId] = {
			pId : 0,
			name : this.options.rootLabel
		};
	};
	// add the element to the path tree
	this.addToPath = function(id, name) {
		if (this.current_pId == 0)
			name = this.options.rootLabel;
		this.pathTree[id] = {
			pId : this.current_pId,
			name : name
		};
	};
	// draw the path according to the parentId.
	this.drawPath = function(id, avoidClean) {
		if (!this.path)
			return;
		// first call
		if (!avoidClean) {
			var nextNode = this.path.nextSibling;
			this.path.parentNode.removeChild(this.path);
			this.initPath();
			if (nextNode)
				this.path.parentNode.insertBefore(this.path, nextNode);
			else
				this.path.parentNode.appendChild(this.path);
			this.path.appendChild(document.createElement("NOBR"));
			if (id != this.options.rootPId) {
				this.addRow(0, "..", "levelUp");
			}
		}

		if (!this.pathTree[id] || (!avoidClean && id == this.options.rootPId))
			return;
		var a = document.createElement("A");
		a.href = "javascript:void(0);";
		a.onclick = function() {
			if (self.options.onRowClick) {
				var filterString = self.getFilter();
				var selectorValue = self.getSelector();
				self.options.onRowClick(id, filterString, selectorValue,
						self.fillWithData);
			}
			return false;
		};

		// a.innerHTML=this.pathTree[id].name;
		a.appendChild(document.createTextNode(this.pathTree[id].name));
		if (this.path.firstChild.firstChild) {
			this.path.firstChild.insertBefore(a,
					this.path.firstChild.firstChild);
		} else {
			this.path.firstChild.appendChild(a);
		}
		this.drawPath(this.pathTree[id].pId, true);

		var m = this.path.offsetWidth - this.path.scrollWidth;
		if (m > 0)
			m = 0;
		this.path.firstChild.style.left = m + "px";

	};

	this.getOrganizationNode = function() {
		return this.options.rootPId;
	};
	this.fillWithData = function(id, data, selector) {
		if (!data[0])
			data = [ data ];
		if (!selector) {
			self.current_pId = id;
			self.cleanTable();
		}
		for (i = 0; data[0].children && i < data[0].children.length; i++) {
			self.addToPath(data[0].children[i].id, data[0].children[i].name);
			self.addRow(data[0].children[i].id, data[0].children[i].name,
					selector);
		}

		if (!selector) {
			self.drawPath(id);
		}
	};

	// /////////////////////////////////////////////////////////////////
	// Init Buttons:
	this.initButtons = function() {
		this.buttons = this.container
				.appendChild(document.createElement("DIV"));
		this.buttons.id = this.options.elementID["buttons"];

		var div = document.body.appendChild(document.createElement("DIV"));
		div.className = this.options.dialogWindowClass;
		var ipt = document.createElement("INPUT");
		ipt.className = this.options.dialogWindowIptClass;
		div.appendChild(ipt);
		// div.innerHTML = '<input class="'+this.options.dialogWindowIptClass+'"
		// />';
		this._dialogIpt = div.firstChild;
		this._dialog = $(div).dialog(GeotabConfig.datatable.dialog);

		var btn = document.createElement("INPUT");
		btn.className = this.options.btnClass;
		btn.value = this.options.addBtnLbl;
		btn.type = "button";
		if (this.options.onAdd)
			btn.onclick = function() {
				self._dialogIpt.value = "";
				self._dialog.data('title.dialog',
						GeotabConfig.datatable.dialog_add.title);
				var b = {};
				b[GeotabConfig.datatable.dialog_add.buttons[0]] = function() {
					var node = self.getSelectedItem();
					var selectorValue = self.getSelector();
					self.options.onAdd(0, self.current_pId,
							self._dialogIpt.value, selectorValue, self._addRow);
					self._dialog.dialog("close");
				};
				b[GeotabConfig.datatable.dialog_add.buttons[1]] = function() {
					$(this).dialog("close");
				};
				self._dialog.data("buttons.dialog", b);
				self._dialog.dialog("open");
			};
		this.buttons.appendChild(btn);

		var btn = document.createElement("INPUT");
		btn.className = this.options.btnClass;
		btn.value = this.options.editBtnLbl;
		btn.type = "button";
		if (this.options.onEdit)
			btn.onclick = function() {
				var node = self.getSelectedItem();
				if (!node.id) {
					alert("No nodes were selected.");
				} else {
					self._dialogIpt.value = node.name;
					self._dialog.data('title.dialog',
							GeotabConfig.datatable.dialog_edit.title);
					var b = {};
					b[GeotabConfig.datatable.dialog_edit.buttons[0]] = function() {
						var node = self.getSelectedItem();
						if (confirm("The node '" + node.name
								+ "' will be renamed. Click Ok to Continue."))
							self.options.onEdit(node.id, self.current_pId,
									self._dialogIpt.value, self.setRowName);
					};
					b[GeotabConfig.datatable.dialog_add.buttons[1]] = function() {
						$(this).dialog("close");
					};
					self._dialog.data("buttons.dialog", b);
					self._dialog.dialog("open");
				}
			};
		this.buttons.appendChild(btn);

		var btn = document.createElement("INPUT");
		btn.className = this.options.btnClass;
		btn.value = this.options.delBtnLbl;
		btn.type = "button";
		if (this.options.onDelete)
			btn.onclick = function() {
				var node = self.getSelectedItem();
				if (!node.id) {
					alert("No nodes were selected.");
				} else {
					if (confirm("The node '" + node.name
							+ "' will be removed. Click Ok to Continue."))
						self.options.onDelete(node.id, self.current_pId,
								node.name, self._deleteRow);
				}
			};
		this.buttons.appendChild(btn);
	};

	options = options || {};
	if (options.length) {
		for ( var i = 0; i < options.length; i++)
			this.initOptions(options[i]);
	} else {
		this.initOptions(options);
	}
	this.init(container);
}
