var BwClasses = new Object();
var BwThemePath = null;

function BwStart ()
{
	if (BwLocateTheme()) {
		BwBootstrapElement (document.body);
		setTimeout (function () {BwDataModel.loadModels (BwDataModel.rootModels); BwDataModel.initialLoading = false; }, 10);
	}
}

function BwLocateTheme ()
{
	var scripts = document.getElementsByTagName ("script");
	for (var i = 0; i < scripts.length; i++)
	{
		var s = scripts[i].src;
		if (s.match ("Theme.js") && s.match ('Bw'))
		{
			var p = s.lastIndexOf ("/");
			BwThemePath = s.substring (0, p + 1);
			return true;
		}
	}
	
	alert ("A theme MUST be linked to the page"); 
	return false;
};

function BwBootstrapElement (element)
{
	var l = element.childNodes.length;
	
	for (var i = 0; i < l; i++)
	{
		var e = element.childNodes[i];
		var n = e.className;
		var c = null;
		var continueTraversal = true;
		var isaClass = false;
			
		if (n)
		{
			c = BwClasses[n];

			if (c && c != null) {
				isaClass = true;
			}
		}

		if (isaClass) {
			e.BwClass = c;
			e.BwClass();
			continueTraversal = e.initFromDOM ();
		}

		if (continueTraversal) {
			BwBootstrapElement (e);
		}
	}
}

function BwLoadInterface (parent, url)
{
	var q = new BwQuery();
	q.get (url);
	parent.innerHTML = q.getText();
	BwBootstrapElement (parent);
};

function BwGetById (id)
{
	return document.getElementById (id);
};

function log (str)
{
	var l = BwGetById ("log");
	if (!l)
	{
		l = document.createElement("DIV");
		l.style.font="menu";
		l.id = "log";
		document.body.appendChild (l);
	}
	l.innerHTML += (str + "<br>");
}

if (window.addEventListener) {
	window.addEventListener ("load", BwStart, true);
} else {
	window.attachEvent ("onload", BwStart);
}

Array.prototype.peek = function ()
{
	var l = this.length;
	return (l>0) ? this[l-1] : null; 
};

Array.prototype.lookup = function (o)
{
	var l = this.length;
	for (var i = 0; i < l; i++) {
		if (this[i] == o) {
			return i;
		}
	}
	return -1;
};
BwClasses["BwCalendar"] = BwCalendar;

function BwCalendar ()
{
	this.isa = BwEditableWidget;
	this.isa();
	
	this.currDate = new Date();
	
	this.initFromDOM = BwCalendar.initFromDOM;
	
	this.draw = BwCalendar.draw;
	this.drawCalendar = BwCalendar.drawCalendar;
	this.changeMonth = BwCalendar.changeMonth;
	this.changeDay = BwCalendar.changeDay;

	this.getValue = BwCalendar.getValue;
	this.setValue = BwCalendar.setValue;

	this.drawLayout = BwCalendar.drawLayout;
	this.drawLeftButton = BwCalendar.drawLeftButton;
	this.drawRightButton = BwCalendar.drawRightButton;
	this.drawCurrentDateLabel = BwCalendar.drawCurrentDateLabel;
	this.drawWeekDayLabel = BwCalendar.drawWeekDayLabel;
	this.clearCalendarContainer = BwCalendar.clearCalendarContainer;
	this.drawWeekContainer = BwCalendar.drawWeekContainer;
	this.drawDayContainer = BwCalendar.drawDayContainer;
	this.drawDayLabel = BwCalendar.drawDayLabel;
	this.setDayLabelStyle = BwCalendar.setDayLabelStyle;
	
	this.mouseClicked = BwCalendar.mouseClicked;
	this.mouseDoubleClicked = BwCalendar.mouseDoubleClicked;
	this.keyPressed = BwCalendar.keyPressed;
}

BwCalendar.DAY_LABEL = [ 'Sun','Mon','Tue','Wed','Thu','Fri','Sat' ];
BwCalendar.MONTH_LABEL = [ 'January','February','March','April','May','June','July','August','September','October','November','December' ];
BwCalendar.WEEK_START_OFFSET = 0;

BwCalendar.newInstance = function (date)
{
	var self = document.createElement ("div");
	
	self.BwClass = BwCalendar;
	self.BwClass();
	
	self.className = "BwCalendar";
	
	if (date && date != null) {
		self.setAttribute ("date", date);
	}
	
	self.initFromDOM();

	return self;
};

BwCalendar.initFromDOM = function ()
{
	this.style.MozUserInput="enabled";
	this.style.MozUserFocus="normal";
	this.style.cursor="default";

	BwEditableWidget.initFromDOM.call (this);
	
	var d = this.getAttribute ("date");
	this.currDate = (d != null) ? new BwDateIO.read(d) : new Date();
	
	this.draw ();
	
	var _this = this;
	this.onclick = function (e) { _this.mouseClicked(e); };
	this.ondblclick = function (e) { _this.mouseDoubleClicked(e); };
	this.onkeydown = function (e) { return _this.keyPressed(e); };
	
	this.onaction = this.getAttribute ("onaction");
	
	return false;
};

BwCalendar.wrap = function (index, offset)
{
	var i = index + offset;
	return (i >= 7) ? 7 - i : (i < 0) ? 7 + i : i;
};

BwCalendar.changeMonth = function (offset)
{
	var c = this.currDate; 
	var a = c.getDate();
	var t = c.getTime();
	var d = new Date (t);
	var n = c.getMonth() + offset;
	var y = c.getFullYear();
	
	if (n < 0) {
		n = 11;
		y --;
	}
	else if (n > 11) {
		n = 0;
		y++;
	}
	
	d.setFullYear (y);
	d.setMonth (n);
	while (d.getMonth() != n)
	{
		d = new Date (t);
		d.setFullYear (y);
		d.setMonth (n);
		d.setDate (--a);
	}
	
	this.setValue (d);
};

BwCalendar.getValue = function ()
{
	return this.currDate;
};

BwCalendar.setValue = function (d)
{
	this.currDate = d;
	
	var el = this.currentDateLabelContainer;
	while (el.firstChild != null) {
		el.removeChild (el.firstChild);
	}
	
	el = this.drawCurrentDateLabel (BwCalendar.MONTH_LABEL[d.getMonth()], d.getFullYear());
	this.currentDateLabelContainer.appendChild (el);
	
	this.drawCalendar ();
};

BwCalendar.changeDay = function (td)
{
	var l = td.firstChild;
	if (l == null || !l.getValue) return;
	
	this.currDate.setDate (l.getValue());
	
	this.setDayLabelStyle (this.sel, false);
	this.sel = td;
	this.setDayLabelStyle (this.sel, true);
};

BwCalendar.draw = function ()
{
	this.dayLabelContainer = [];

	this.drawLayout ();
	
	var el = this.drawLeftButton();
	this.leftButtonContainer.appendChild (el);
	
	el = this.drawRightButton();
	this.rightButtonContainer.appendChild (el);
	
	el = this.drawCurrentDateLabel (BwCalendar.MONTH_LABEL[this.currDate.getMonth()], this.currDate.getFullYear());
	this.currentDateLabelContainer.appendChild (el);
	
	for (var i = 0; i < 7; i++)
	{
		el = this.drawWeekDayLabel (BwCalendar.DAY_LABEL[BwCalendar.wrap (i, BwCalendar.WEEK_START_OFFSET)]);
		this.dayLabelContainer[i].appendChild (el);
	}

	this.drawCalendar ();
};

BwCalendar.drawCalendar = function ()
{
	this.clearCalendarContainer();
	
	var cal = new Date();
	cal.setDate (1);
	cal.setMonth (this.currDate.getMonth());
	cal.setFullYear (this.currDate.getFullYear());
	
	var k = 0;
	while (cal.getMonth() == this.currDate.getMonth())
	{
		var d = cal.getDate();
		
		var j = BwCalendar.wrap (cal.getDay(), -BwCalendar.WEEK_START_OFFSET);
		if (j == 0 || d == 1)
		{
			r = this.drawWeekContainer();
			r.dateRowIndex = k++;
			this.calendarContainer.appendChild (r);

			for (var i = 0; i < 7; i++)
			{
				var el = this.drawDayContainer ();
				el.dateCellIndex = i;
				r.appendChild (el);
			}
		}
		
		var dc = r.childNodes[j];
		var dl = this.drawDayLabel (d);
		dc.appendChild (dl);
		
		if (d == this.currDate.getDate())
		{
			this.setDayLabelStyle (dc, true);
			this.sel = dc;
		}
		
		cal.setDate (cal.getDate()+1);
	}
};

BwCalendar.mouseClicked = function (event)
{
	if (!event) event = window.event;
	var target = (event.target)?event.target:event.srcElement;
	
	var t = target;
	while (t != null)
	{
		if (t == this.leftButtonContainer) {
			this.changeMonth (-1);
			break;
		}
		if (t == this.rightButtonContainer) {
			this.changeMonth (1);
			break;
		}
		
		if (t == this.calendarContainer) 
		{
			t = BwXml.getNodeValue(target);/*.text || target.innerText;*/
			if (t != null && typeof t != 'undefined' && t != '')
			{
				t = BwUtil.findParentElement (target, 'TD');
				this.changeDay (t);
			}
			break;
		}
		
		t = t.parentNode;
	}
};

BwCalendar.mouseDoubleClicked = function (event)
{
	if (!event) event = window.event;
	var target = (event.target)?event.target:event.srcElement;
	
	var t = target;
	while (t != null)
	{
		if (t == this.calendarContainer) 
		{
			t = BwXml.getNodeValue(target);/*.text || target.innerText;*/
			if (t != null && typeof t != 'undefined' && t != '')
			{
				t = BwUtil.findParentElement (target, 'TD');
				if (this.onaction != null) {
					return BwUtil.call (this, this.onaction);
				}
			}
			break;
		}
		
		t = t.parentNode;
	}
	return false;
};

BwCalendar.keyPressed = function (event)
{
	var c = this.calendarContainer;
	var rows = c.childNodes;
	var nr = rows.length;
	var cr = this.sel.parentNode.dateRowIndex;
	var cc = this.sel.dateCellIndex;
	
	if (!event) event = window.event;

	switch (event.keyCode)
	{
		case 38:
			if (cr <= 0) break;
			this.changeDay (rows[cr - 1].childNodes[cc]);
			break;
			
		case 40:
			if (cr >= (rows.length - 1)) break; 
			this.changeDay (rows[cr + 1].childNodes[cc]);
			break;
			
		case 37:
			if (cc <= 0) break;
			this.changeDay (rows[cr].childNodes[cc - 1]);
			break;
			
		case 39:
			if (cc >= 6) break; 
			this.changeDay (rows[cr].childNodes[cc + 1]);
			break;

		case 33:
			this.changeMonth (-1);
			break;
			
		case 34:
			this.changeMonth (1);
			break;
			
		case 13:
			BwUtil.call (this, this.onaction);
			return;
			
		default:
			return true;
	}
	
	return false;
};


BwClasses["BwCheckbox"] = BwCheckbox;

function BwCheckbox ()
{
	this.isa = BwEditableWidget;
	this.isa();
	
	this.initFromDOM = BwCheckbox.initFromDOM;
	
	this.setValue = BwCheckbox.setValue;
	this.getValue = BwCheckbox.getValue;
}

BwCheckbox.newInstance = function (val, disabled)
{
	var self = document.createElement ("input");
	
	self.BwClass = BwCheckbox;
	self.BwClass();
	
	self.className = "BwCheckbox";
	
	if (val) {
		self.setAttribute ("checked", val);
	}
	
	self.initFromDOM ();

	if (typeof disabled != "undefined" && Boolean(disabled) == true) {
		self.disable();
	}

	return self;
};

BwCheckbox.initFromDOM = function ()
{
	BwEditableWidget.initFromDOM.call (this);
	
	/*this.style.display = "inline";*/
	this.type = "checkbox";
	/*
	this.ondblclick = function (e){if(e)e.stopPropagation();else window.event.cancelBubble=true;};
	*/
};

BwCheckbox.getValue = function ()
{
	return this.checked;
};

BwCheckbox.setValue = function (val)
{
	this.checked = val;
};
function BwColumn ()
{
	this.name = null;
	this.size = null;
	this.code = null;
	this.value = null;
}

BwColumn.ERROR = "Invalid column specification";

BwColumn.prototype.setAlign = function (s)
{
	this.align = (s) ? s : "left";
};

BwColumn.prototype.setSize = function (s)
{
	this.size = s;
};

BwColumn.prototype.setName = function (n)
{
	this.name = n;
};

BwColumn.prototype.loadValueCode = function (s)
{
	if (s == null || s.length == 0) {
		throw BwColumn.ERROR;
	}

	this.valueData = s;
};

BwColumn.prototype.loadRenderCode = function (s)
{
	var p1 = s.indexOf ('(');
	if (p1 < 0) throw BwColumn.ERROR;
	
	var p2 = s.indexOf (')');
	if (p2 < 0) throw BwColumn.ERROR;
	
	var code = "return " + s.substring (0, p1) + ".newInstance(" ;
	
	s = s.substring (p1+1, p2);
	var l = s.length;
	var i = 0;
	while (l > 0)
	{
		p1 = s.indexOf (',');
		if (p1 < 0) p1 = l;
		
		var d = s.substring (0, p1);
		
		if (i++ > 0) code += ',';
		code += ("d[" + d + "]");

		s = s.substring (p1+1, l);
		l = s.length;
	}

	this.code = new Function ("d", code + ");");
};

BwColumn.prototype.cellContent = function (data, list)
{
	var r = this.code (data);
	
	var s = r.style;
	s.whiteSpace = "nowrap";
	s.overflow = "hidden";
	if (r.editable)
	{
		var _this = this;
		r.onupdate = function(){list.cellUpdated(this);};
		r.onfocus = function(){list.cellFocused(this);};
	}
	
	return r;
};

BwConstants = { SCROLLBAR_SIZE: 20 };
function BwDataColumn (mode, value, type)
{
	this.mode = mode;
	this.value = value;
	this.type = type;
}

BwDataColumn.prototype.dataFromNode = function (node, data)
{
	var v;
		
	switch (this.mode)
	{
		case BwDataModel.VARIABLE:
			v = BwXml.get (node, this.value);
			break;

		case BwDataModel.CONSTANT:
			v = this.value;
			break;

		case BwDataModel.MACRO:
			v = this.value (data);
			break;
		
		default:
			v = null;
	}
	
	if (v != null && this.type == "number")
	{
		var n = new Number (v);
		if (!isNaN (n)) v = n.valueOf();
	}
	
	return v;
};

BwClasses["BwDataModel"] = BwDataModel;

function BwDataModel ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.cursorPath = [];
	this.subscribers = [];
	this.relations = [];
	this.columns = [];
	this.recordsPath = null;
	this.childRecordsPath = null;
	this.url = null;

	this.initFromDOM = BwDataModel.initFromDOM;
	this.initColumns = BwDataModel.initColumns;
	this.initRelations = BwDataModel.initRelations;
	this.initUrl = BwDataModel.initUrl;
	this.initLoad = BwDataModel.initLoad;
	
	this.load = BwDataModel.load;
	this.reload = BwDataModel.reload;
	
	this.traverse = BwDataModel.traverse;
	this._traverse = BwDataModel._traverse;
	this.dataFromNode = BwDataModel.dataFromNode;
	this.pathToNode = BwDataModel.pathToNode;

	this.publish = BwDataModel.publish;
	this.subscribe = BwDataModel.subscribe;
	this.unsubscribe = BwDataModel.unsubscribe;
	
	this.empty = BwDataModel.empty;
	this.remove = BwDataModel.remove;
	this.insert = BwDataModel.insert;
	this.append = BwDataModel.append;
	this._add = BwDataModel._add;

	this.setCursorPath = BwDataModel.setCursorPath;
	this.getValue = BwDataModel.getValue;
}

BwDataModel.VARIABLE = 1;
BwDataModel.CONSTANT = 2;
BwDataModel.MACRO = 3;

BwDataModel.rootModels = [];
BwDataModel.initialLoading = true;

BwDataModel.loadModels = function (models)
{
	for (var i = 0; i < models.length; i++)
	{
		var m = models[i];
		m.initLoad();

		if (m.relations.length > 0)
		{
			BwDataModel.loadModels (m.relations);
		}
	}
};

BwDataModel.initFromDOM = function ()
{
	this.style.display = "none";
	
	this.recordsPath = this.getAttribute ("records");
	this.childRecordsPath = this.getAttribute ("childRecords");
	this.url = this.getAttribute ("src");
	
	this.initColumns();
	this.initRelations ();
	
	return false;
};

BwDataModel.initColumns = function ()
{
	var e;
	while ((e = this.firstChild) != null)
	{
		this.removeChild (e);
		
		if (e.className == "BwColumn")
		{
			var col = new BwDataColumn ();
			this.columns.push (col);

			var a = e.getAttribute ("type");
			col.type = (a != null) ? a : "string";
			
			a = e.getAttribute ("variable");
			if (a != null) {
				col.mode = BwDataModel.VARIABLE;
				col.value = a;
				continue;
			}
			
			a = e.getAttribute ("constant");
			if (a != null) {
				col.mode = BwDataModel.CONSTANT;
				col.value = a;
				continue;
			}
			
			a = e.getAttribute ("macro");
			if (a != null) {
				col.mode = BwDataModel.MACRO;
				col.value = new Function ("data",  a);
				continue;
			}
		}
		else if (e.className == "BwDataModel")
		{
			this.relations.push (e);
		}
	}
};

BwDataModel.initRelations = function ()
{
	for (var i =0; i < this.relations.length; i++)
	{
		var e = this.relations[i];
		e.relatedTo = this;
		this.appendChild (e);
		e.BwClass = BwDataModel;
		e.BwClass();
		e.initFromDOM ();
	}

	if (!this.relatedTo) BwDataModel.rootModels.push (this);
};

BwDataModel.initUrl = function (url)
{
	var r = this.relatedTo;
	if (!r) return url;
	
	if (r.cursorPath.length == 0) return null;
	
	var u = url;
	for (var i = 0; i < r.columns.length; i++)
	{
		var p = new RegExp ("\\$\\(" + i + "\\)");
		if (u.match (p))
		{
			var n = r.pathToNode (r.cursorPath);
			var v = r.dataFromNode (n);
			u = u.replace (p, v[i]);
		}
	}
	
	return u;
};

BwDataModel.initLoad = function ()
{
	this.xml = this.load (this.initUrl (this.url));
	if (this.xml != null) {
		this.traverse (false, 0, this.xml, null, null, false);
	}
};

BwDataModel.load = function (url)
{
	if (url == null) return;
	var q = new BwQuery();
	q.get (url);

	/* TODO : check for errors and throw exception !!  */
	
	return q.getXML();
};

BwDataModel.reload = function ()
{
	this.empty ();
	this.initLoad ();
};

BwDataModel.traverse = function (insert, depth, newNode, notifiee, refNode, sync)
{
	var nodes = (newNode == this.xml) ? BwXml.getNodes (newNode, this.recordsPath) : [ newNode ];
	if (nodes.length == 0) return;
	
	var stack = [];
	var frame = { nodes: nodes, depth: depth, i: 0 };
	stack.push (frame);
	
	this.publish (notifiee, "updateBegins", refNode, insert);
	
	this._traverse (notifiee, stack, 0, sync);
};

BwDataModel._traverse = function (notifiee, stack, callID, sync)
{
	var f = stack.peek();
	if (f == null) return;
	
	if (f.i >= f.nodes.length)
	{
		stack.pop();
	}
	else
	{
		var n = f.nodes[f.i];
		var hasChild = false;
		
		if (this.childRecordsPath != null)
		{
			var nodes = BwXml.getNodes (n, this.childRecordsPath);
			hasChild = (nodes.length > 0);
		}
		
		this.publish (notifiee, "nodeAdded", n, f.depth, hasChild);
		
		if (hasChild)
		{
			var frame = { nodes: nodes, depth: f.depth + 1, i: 0 };
			stack.push (frame);
		}
		
		f.i++;
	}
	
	if (stack.length > 0)
	{
		if (callID == 0)
		{
			var _this = this;
			var f = function () { 
				for (var i = 8; i >= 0; i--) {
					_this._traverse (notifiee, stack, i, sync);
				}
			};
			(sync) ? f() : setTimeout (f, 1);
		}
	}
	else {
		this.publish (notifiee, "updateEnds");
	}
};

BwDataModel.dataFromNode = function (node)
{
	var data = [];

	var cl = this.columns.length;
	for (var j = 0; j < cl; j++)
	{
		var c = this.columns[j];
		var v = c.dataFromNode (node, data);
		data[j] = v;
	}
	
	return data;
};

BwDataModel.pathToNode = function (path)
{
	if (typeof path == 'number') path = [ path ];
	
	var node = this.xml;
	var l = path.length;
	for (var i = 0; i < l; i++)
	{
		var p = path[i];
		var nodes = BwXml.getNodes (node, (i == 0) ? this.recordsPath : this.childRecordsPath);
		if (p >= nodes.length) {
			throw ("Invalid node path : " + path);
		}
		node = nodes[p];
	}
	return node;
};

BwDataModel.publish = function (notifiee, method)
{
	var args = [];
	for (var i = 2; i < arguments.length; i++) {
		args[i-2] = arguments[i];
	}
	
	if (notifiee != null)
	{
		var m = notifiee[method];
		if (m) m.apply (notifiee, args);
	}
	else
	{
		var l = this.subscribers.length;
		for (var i = 0; i < l; i++)
		{
			notifiee = this.subscribers[i];
			var m = notifiee[method];
			if (m) m.apply (notifiee, args);
		}
	}
};

BwDataModel.subscribe = function (subscriber)
{
	this.subscribers.push (subscriber);
	if (!BwDataModel.initialLoading)
	{
		this.traverse (false, 0, this.xml, subscriber, null, false);
	}
};

BwDataModel.unsubscribe = function (subscriber)
{
	var i = this.subscribers.lookup (subsriber);
	this.subscribers.splice (i, 1);
};

BwDataModel.empty = function()
{
	this.xml = null;
	this.publish (null, "nodesRemoved");
};

BwDataModel.remove = function (path)
{
	var node = this.pathToNode (path);
	node.parentNode.removeChild (node);
	this.publish (null, "nodeRemoved", path);
};

BwDataModel.insert = function (path, xml)
{
	this._add (path, xml, true);
};

BwDataModel.append = function (path, xml)
{
	this._add (path, xml, false);
};

BwDataModel._add = function (path, xml, insert)
{
	if (typeof xml == 'string') xml = this.load (xml);
	if (this.xml == null)
	{
		this.xml = xml;
		this.traverse (false, 0, this.xml, null, null, false);
		return;
	}
	
	var node = this.pathToNode (path);
	
	var nodes = BwXml.getNodes (xml, this.recordsPath);
	var l = nodes.length; 
	for (var i = 0; i < l; i++)
	{
		var n = nodes[i];
		var nn = BwXml.importNode (this.xml, n, true);
		var depth = path.length - 1;
		var p = node.parentNode;

		(insert) ?	p.insertBefore (nn, node) : p.appendChild (nn);
		
		this.traverse (insert, depth, nn, null, node, true);
	}
};

BwDataModel.setCursorPath = function (path)
{
	this.cursorPath = path;
	for (var i = 0; i < this.relations.length; i++)
	{
		var r = this.relations[i];
		r.reload ();
	}
};

BwDataModel.getValue = function (col, node)
{
	if (!node) {
		node = this.pathToNode (this.cursorPath);
	}

	return this.dataFromNode (node)[col];
};

BwClasses["BwDatefield"] = BwDatefield;

function BwDatefield ()
{
	this.isa = BwEditableWidget;
	this.isa();
	
	this.pop = true;
	this.field = null;
	this.calendar = null;
	
	this.initFromDOM = BwDatefield.initFromDOM;
	this.showCalendar = BwDatefield.showCalendar;
	this.hideCalendar = BwDatefield.hideCalendar;
	this.calendarAction = BwDatefield.calendarAction;

	this.getValue = BwDatefield.getValue;
	this.setValue = BwDatefield.setValue;
	
	this.mouseClicked = BwDatefield.mouseClicked;
	this.keyPressed = BwDatefield.keyPressed;
	this.focused = BwDatefield.focused;
	this.calendarBlured = BwDatefield.calendarBlured;
}

BwDatefield.calendar = null;

BwDatefield.newInstance = function ()
{
	var self = document.createElement ("div");

	self.BwClass = BwDatefield;
	self.BwClass();

	self.className = "BwDatefield";

	self.initFromDOM();

	return self;
};

BwDatefield.initFromDOM = function ()
{
	BwEditableWidget.initFromDOM.call (this);
	
	this.field = BwTextfield.newInstance ();
	this.field.style.verticalAlign="middle";
	this.field.input.autocomplete = "off";
	
	var _this = this;
	this.field.input.onfocus = function () {return _this.focused (); };
	this.field.input.onkeydown = function (e) {return _this.keyPressed (e); };
	
	this.appendChild (this.field);

	var v = this.getAttribute ("value");
	if (v != null) {
		this.setValue (v);
	}

	this.onupdate = this.getAttribute ("onupdate");

	return false;
};

BwDatefield.hideCalendar = function ()
{
	var c = BwDatefield.calendar;
	if (c != null)
	{
		if (c.focus) {
			c.releaseCapture();
		}
		
		document.body.removeChild (c);
		BwDatefield.calendar = null;
		return;
	}
};

BwDatefield.showCalendar = function ()
{
	var f = this.field;
	var c = BwDatefield.calendar;
	
	if (c != null) {
		this.hideCalendar();
	}
	
	c = BwCalendar.newInstance();
	c.tabIndex = "0";
	c.style.position = "absolute";
	
	var t = BwUtil.getElementTopPosition (f);
	var l = BwUtil.getElementLeftPosition (f);
	var p = f;
	while ((p = p.parentNode) != null) {
		if (p.scrollTop) t -= p.scrollTop;
		if (p.scrollLeft) l -= p.scrollLeft;
	}
	c.style.top = t +  "px";
	c.style.left = l +  "px";
	
	c.MozUserFocus = "normal";
	BwDatefield.calendar = c;
	document.body.appendChild (c);
	
	var _this = this;
	c.onaction = function() { _this.calendarAction(); };
	c.onclick = function (e) {return _this.mouseClicked (e); };
	
	if (c.focus) {
		c.onblur = function (e) {return _this.calendarBlured (e); };
		c.focus();
		c.setCapture();
	} 
	
	if (f.getValue() == "") return;
		
	var d = new BwDateIO();
	var s = null;
	try {
		s = d.read (f.getValue());
	} catch (e) {
		log (e);
		return;
	}
	
	if (s && s != null && !isNaN (s.valueOf()))
	{
		c.setValue (s);
	}
};

BwDatefield.calendarAction = function ()
{
	this.setValue (BwDatefield.calendar.getValue());
	
	this.hideCalendar();

	this.pop = false;
	this.field.input.focus();
};

BwDatefield.getValue = function ()
{
	return this.field.getValue();
};

BwDatefield.setValue = function (val)
{
	this.field.setValue ((typeof val != "string") ? new BwDateIO ().write (val) : val);
	BwUtil.call (this, this.onupdate);
};

BwDatefield.mouseClicked = function (event)
{
	var p = BwUtil.getGlobalMousePosition (event);
	var c = BwDatefield.calendar;
	
	var l = parseInt (c.style.left);
	var t = parseInt (c.style.top);
	var r = l + c.offsetWidth;
	var b = t + c.offsetHeight;
	
	if (c.focus && (p.x < l || p.x > r || p.y < t || p.y > b))
	{
		this.hideCalendar();
		return false;
	}
	
	return BwDatefield.calendar.mouseClicked (event);
};

BwDatefield.focused = function (e)
{
	if (this.pop) this.showCalendar();
	this.pop = true;

	return true;
};

BwDatefield.calendarBlured = function (e)
{
	this.hideCalendar();
	
	this.pop = false;
	/*this.field.input.focus();*/
	
	return false;
};

BwDatefield.keyPressed = function (event)
{
	if (!event) event = window.event;
	event.cancelBubble = true;

	if (event.keyCode == 27) {
		this.hideCalendar();
	}
	
	if (BwDatefield.calendar != null) {
		BwDatefield.calendar.keyPressed (event);
	}
};

function BwDateIO (fmt)
{
	this.fmt = (typeof fmt == "undefined") ? BwDateIO.DEFAULT_FORMAT : fmt;
	this.act = new Array();
	
	var f = this.fmt;
	var a = this.act;
	var l = f.length;
	var prev = null;
	
	for (var i = 0; i < l; i++)
	{
		var c = f.charAt (i);
		
		if (c != prev)
		{
			var k = a.length;
			a[k] = new Array();
			a[k][0] = c;
			a[k][1] = i;
			a[k][2] = 1;
		}
		else
		{
			a[a.length-1][2]++;
		}

		prev = c;
	}
}

BwDateIO.DEFAULT_FORMAT = "mm/dd/yyyy";

BwDateIO.prototype.read = function (str)
{
	var d = null;
	var m = null;
	var y = null;
	var c = this.act;
	var l = c.length;

	for (var i = 0; i < l; i++)
	{
		var a = c[i];
		var typ = a[0];
		var beg = a[1];
		var end = beg + a[2];
		
		var s = str.substring (beg, end);
		var n = new Number (s);
		n = n.valueOf();
		if (typ == 'd') d = n;
		else if (typ == 'm') m = n;
		else if (typ == 'y') y = n;
	}

	return new Date (y, m-1, d);
};

BwDateIO.prototype.write = function (date)
{
	var d = ''+(date.getDate());
	var m = ''+(date.getMonth() + 1);
	var y = ''+(date.getFullYear());

	var c = this.act;
	var l = c.length;
	
	var s = '';
	
	for (var i = 0; i < l; i++)
	{
		var a = c[i];
		var typ = a[0];
		var len = a[2];
		
		if (typ == 'd')
		{
			s += this.pad (d, len);
		} 
		else if (typ == 'm')
		{
			s += this.pad (m, len);
		} 
		else if (typ == 'y')
		{
			s += this.pad (y, len);
		}
		else
		{
			for (var j = 0; j < len; j++)
			{
				s += typ;
			}
		}
	}
	return s;
};

BwDateIO.prototype.pad = function (v, len)
{
	var l = v.length;
	if (l <= len) 
	{
		for (var i = l; i < len; i++)
		{
			v = '0' + v;
		}
		return v;
	}
	throw "Invalid date format";
};

BwClasses["BwDate"] = BwDate;

function BwDate ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.initFromDOM = BwDate.initFromDOM;
	
	this.setValue = BwDate.setValue;
	this.getValue = BwDate.getValue;
}

/* date must be DD-MM-YYYY or YYYY-MM-DD */
BwDate.newInstance = function (date, lang, separ)
{
    var self = document.createElement ("DIV");

    this.dateRank = 0;
	
	self.BwClass = BwDate;
	self.BwClass();
	
	self.className = "BwLabel";
	
	if (date)
	{
        var isFrench = (lang=='FR')?true:false;
		self.setAttribute ("text", BwDate.format(date,isFrench,separ));
		self.setAttribute ("dateRank", BwDate.format(date,false,''));
	}
	
	self.initFromDOM();
    return self;
};

BwDate.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
	
	this.style.display="inline";
	this.style.MozUserSelect="none";
	this.style.cursor="default";
	this.onselectstart=function(){return false;};

	var txt = this.getAttribute ("text");
	if (txt != null) {
		this.setValue(txt);
	}
	return false;
};

BwDate.getValue = function ()
{
    var dateRank = this.getAttribute ("dateRank");
	if (dateRank != null)
    	return dateRank;
    return 0;
};

BwDate.setValue = function (txt)
{
	this.innerHTML = txt;
};

/* date must be DD-MM-YYYY or YYYY-MM-DD */
BwDate.format = function(date, isFrench, separ)
{
    if (date)
    {
        if (separ==null)
            separ='/';
        var isDateFR = date.indexOf(separ,1)<4;
        if (isDateFR)
        {
            var DD = date.substr(0,2);
            var MM = date.substr(3,2);
            var YY = date.substr(6,4);
        }
        else
        {
            var YY = date.substr(0,4);
            var MM = date.substr(5,2);
            var DD = date.substr(8,4);
        }
        if (isFrench==true)
            return (DD+separ+MM+separ+YY);
        else
            return (YY+separ+MM+separ+DD);
    }
};

function BwEditableWidget ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.editable = true;
	
	this.initFromDOM = BwEditableWidget.initFromDOM;
	
	this.enable = BwEditableWidget.enable;
	this.disable = BwEditableWidget.disable;
}

BwEditableWidget.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
};

BwEditableWidget.enable = function ()
{
	this.disabled=false;
};

BwEditableWidget.disable = function ()
{
	this.disabled=true;
};


BwClasses["BwExpander"] = BwExpander;

function BwExpander ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.view = null;
	this.control = null;
	
	this.initFromDOM = BwExpander.initFromDOM;
	this.toggle = BwExpander.toggle;
	this.open = BwExpander.open;
	this.close = BwExpander.close;
}

BwExpander.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
	
	var txt = this.getAttribute ("label");
	var c = BwImageLabel.newInstance (BwThemePath + BwStockIcon.storagePath + "closed.png", txt);
	c.style.cursor="default";
	
	this.control = c;
	var p = c._image;
	p.style.marginLeft="0px";

	var _this = this;
	c.onclick = function(){_this.toggle();};
	
	var v = BwView.newInstance();
	v.style.marginTop="5px";
	this.view = v;
	
	var child = this.firstChild;
	while (child != null)
	{
		this.removeChild (child);
		v.appendChild (child);
		child = this.firstChild;
	}
	
	this.appendChild (c);
	this.appendChild (v);
	
	var opened = this.getAttribute ("opened");
	if (opened != null && opened == "true") {
		this.toggle();
	}
	
	this.onopen = this.getAttribute ("onopen");

	return false;
};

BwExpander.toggle = function ()
{
	if (this.view.visible()) {
		this.close();
	} else {
		this.open();
	}
};

BwExpander.open = function ()
{
	this.control._image.setSource(BwThemePath + BwStockIcon.storagePath + "opened.png");
	this.view.show();
	
	BwUtil.call	(this, this.onopen);
};

BwExpander.close = function ()
{
	this.control._image.setSource(BwThemePath + BwStockIcon.storagePath + "closed.png");
	this.view.hide();
};

BwClasses["BwFrame"] = BwFrame;

function BwFrame ()
{
	this.isa = BwWidget;
	this.isa();

	this.contentContainer = null;

	this.draw = BwFrame.draw;
	this.initFromDOM = BwFrame.initFromDOM;
}

BwFrame.newInstance = function ()
{
	var self = document.createElement ("div");
	
	self.BwClass = BwFrame;
	self.BwClass();
	
	self.initFromDOM();
	
	return self;
};

BwFrame.initFromDOM = function ()
{
	var child = [];
	var curr;
	while ((curr = this.firstChild) != null)
	{
		this.removeChild (curr);
		child.push (curr);
	}
	
	var frame = this.draw();
	
	var c = this.contentContainer;
	var l = child.length;
	for (var i = 0; i < l; i++)
	{
		c.appendChild (child[i]);
	}
	
	this.appendChild (frame);
	
	return true;
};


BwClasses["BwImage"] = BwImage;

function BwImage ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.url = null;
	
	this.initFromDOM = BwImage.initFromDOM;
	
	this.nodeAdded = BwImage.nodeAdded;
	
	this.draw = BwImage.draw;
	
	this.setSource = BwImage.setSource;
	this.getSource = BwImage.getSource;
}

BwImage.newInstance = function (src)
{
	var self = document.createElement ("img");
	
	self.BwClass = this;
	self.BwClass();
	
	if (src) {
		self.setAttribute ("source", src);
	}
	
	self.initFromDOM ();
	
	return self;
};

BwImage.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
	
	var s = this.style;
	s.MozUserSelect="none";
	s.MozUserInput="disabled";
	
	var u = this.getAttribute ("source");
	if (u) {
		this.setSource (u);
	}
	
	return false;
};

BwImage.draw = function ()
{
	var png = this.url.toLowerCase().indexOf (".png");

	if (document.all && png != -1)
	{
		this.src = BwThemePath + BwStockIcon.storagePath + "none.gif";
		this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.url + "')";
	}
	else
	{
		this.src = this.url;
		this.style.filter = "";
	}
};

BwImage.getSource = function ()
{
	return this.url;
};

BwImage.setSource = function (src)
{
	this.url = src;
	this.draw();
};

BwClasses["BwImageLabel"] = BwImageLabel;

function BwImageLabel ()
{
	this.isa = BwWidget;
	this.isa();

	this._image = null;
	this._label = null;
	
	this.initFromDOM = BwImageLabel.initFromDOM;
	
	this.draw = BwImageLabel.draw;
	
	this.setImage= BwImageLabel.setImage;
	this.getImage= BwImageLabel.getImage;
	
	this.setLabel = BwImageLabel.setLabel;
	this.getLabel = BwImageLabel.getLabel;
	
	this.getValue = BwImageLabel.getValue;
	this.setValue = BwImageLabel.setValue;
}

BwImageLabel.newInstance = function (image, label)
{
	var self = document.createElement ("DIV");
	
	self.BwClass = this;
	self.BwClass();
	
	self.setAttribute ("image", image);
	self.setAttribute ("label", label);

	self.initFromDOM ();
	
	return self;
};

BwImageLabel.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
	
	this.draw();
	
	return false;
};

BwImageLabel.draw = function ()
{
	this.style.display="inline";
	
	var img = this.getAttribute ("image");
	this.setImage (img);
	
	var txt = this.getAttribute ("label");
	this.setLabel (txt);
	
	return false;
};

BwImageLabel.setImage = function (img)
{
	var p = this._image;
	if (p == null)
	{
		p = BwImage.newInstance ();
		p.style.marginLeft="2px";
		p.style.marginRight="2px";
		p.style.verticalAlign = "middle";
		p.align="center";
	
		this.appendChild (p);
		
		this._image = p;
	}
	
	if (img != p.getSource()) {
		p.setSource (img);
	}
};

BwImageLabel.getImage = function ()
{
	var p = this._image;
	return p.getSource();
};

BwImageLabel.setLabel = function (txt)
{
	var t = this._label;
	if (t == null)
	{
		t = BwLabel.newInstance ();
		this.appendChild (t);
		this._label=t;
	}
	
	if (txt != t.getValue()) {
		t.setValue (txt);
	}
};

BwImageLabel.getLabel = function ()
{
	var t = this._label;
	return t.getValue();
};

BwImageLabel.getValue = function ()
{
	return this.getLabel();
};

BwImageLabel.setValue = function (txt)
{
	return this.setLabel (txt);
};

BwClasses["BwIntuitive"] = BwIntuitive;

function BwIntuitive ()
{
	this.isa = BwEditableWidget;
	this.isa();
	
	this.disabled = false;
	this.list = null;
	this.field = null;

	this.initFromDOM = BwIntuitive.initFromDOM;
	this.initColumns = BwIntuitive.initColumns;
	
	this.showList = BwIntuitive.showList;
	
	this.setValue = BwIntuitive.setValue;
	this.getValue = BwIntuitive.getValue;
	
	this.keyUp = BwIntuitive.keyUp;
	this.keyDown = BwIntuitive.keyDown;
	
	this.disable = BwIntuitive.disable;
	this.enable = BwIntuitive.enable;
	
	this.lostFocus = BwIntuitive.lostFocus;
	this.gotFocus = BwIntuitive.gotFocus;
}

BwIntuitive.initFromDOM = function ()
{
	BwEditableWidget.initFromDOM.call (this);
	
	this.src = this.getAttribute ("src");
	this.record = this.getAttribute ("record");
	this.rowValue = this.getAttribute ("rowValue");
	this.columns = this.initColumns ();
	
	var f = BwTextfield.newInstance ("", false);
	f.autocomplete = "off";
	f.style.MozUserSelect="text";
	f.style.width=this.style.width;
	this.appendChild (f);
	
	this.field = f;
	
	var _this = this;
	var func = function (e) { _this.keyDown (e) };
	if (navigator.product == "Gecko") {
		f.onkeypress = func;
	} else {
		f.onkeydown = func;
	}
	f.onkeyup = function(e){ _this.keyUp (e) };
	f.onblur = function(){setTimeout(function(){_this.lostFocus();}, 100);};
	f.onfocus = function(){_this.gotFocus();};
};

BwIntuitive.lostFocus = function ()
{
	var now = new Date().getTime();
	var dif = now - this.focusTime;
	if (dif > 200 && this.list) {
		this.list.hide();
	}
};

BwIntuitive.gotFocus = function ()
{
	this.focusTime = new Date().getTime();
};

BwIntuitive.initColumns = function ()
{
	var cols = new Array();
	
	var c = this.firstChild;
	while (c != null)
	{
		if (c.nodeType == 1 && c.className == 'BwColumn') {
			cols.push (c);
		}
		
		this.removeChild (c);
		c = this.firstChild;
	}

	return cols;
};

BwIntuitive.showList = function ()
{
	var l = this.list;
	var f = this.field;
	
	if (l == null) 
	{
		var w = f.offsetWidth;
		if (navigator.product == "Gecko") {
			w -= 2;
		}
		l = BwList.newInstance (null, this.record, this.rowValue, false, false, this.columns, w, 100);
		l.style.position="absolute";
		l.style.zIndex="1";
		this.appendChild (l);
		this.list = l;
		
		var _t = this;
		l.onaction = function(){_t.setValue(_t.list.getValue());_t.list.hide();};
		l.onfocus = function(){_t.gotFocus();};
		l.onblur = function(){setTimeout(function(){_t.lostFocus();}, 100);};
	}
	
	l.show();
	
	var s = l.style;
	s.top = (BwUtil.getElementTopPosition (f) + f.offsetHeight - 1) + "px";
	s.left = (BwUtil.getElementLeftPosition (f)) + "px";
	
	return l;
};

BwIntuitive.keyDown = function (e)
{
	if (!e) e = window.event;
	var k = e.keyCode;
	if (k == 40 || k==38 || k==33 || k==34 || k==36 || k==35)
	{
		this.list.keyPressed (e);
	}
};

BwIntuitive.keyUp = function (e)
{
	if (!e) e = window.event;
	
	var k = e.keyCode;
	
	if (k==40 || k==38 || k==33 || k==34 || k==36 || k==35) {
		return;
	}
	
	var l = this.list;
	var f = this.field;
	
	if (l != null && k == 27 || ((k == 8 || k == 46) && this.field.value == "")) {
		l.hide();
		return;
	}
	else if (l != null && k == 13 && l.visible())
	{
		var s = l.getSelection();
		if (s.length > 0) {
			f.value = l.getValue();
		}
		l.hide();
		return;
	}
	else if (l == null || !l.visible()) {
		l = this.showList();
	}
	
	if (k == 8 || k == 46 || (k > 64 && k < 91) || (k > 47 && k < 58) || (k > 95 && k < 106))
	{
		l.clear();
		l.layout();
		l.appendXML(this.src + f.value);
	}
};

BwIntuitive.getValue = function ()
{
	return this.field.value;
};

BwIntuitive.setValue = function (txt)
{
	this.field.value = txt;
};

BwIntuitive.disable = function ()
{
	this.disabled = true;
	this.field.disable();
};
BwIntuitive.enable = function ()
{
	this.disabled = false;
	this.field.enable();
};


BwClasses["BwLabel"] = BwLabel;

function BwLabel ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.initFromDOM = BwLabel.initFromDOM;
	
	this.updateLabelStyle = BwLabel.updateLabelStyle;

	this.nodeAdded = BwLabel.nodeAdded;
	
	this.setValue = BwLabel.setValue;
	this.getValue = BwLabel.getValue;
	
	this.disable = BwLabel.disable;
	this.enable = BwLabel.enable;
}

BwLabel.newInstance = function (val, model)
{
	var self = document.createElement ("div");
	
	self.BwClass = BwLabel;
	self.BwClass();
	
	self.className = "BwLabel";
	
	self.setAttribute ("value", val);
	
	if (typeof model != 'undefined') {
		self.setAttribute ("model", model);
	}
	
	self.initFromDOM();
	
	return self;
};

BwLabel.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
	
	var s = this.style;
	s.display="inline";
	s.MozUserSelect="none";
	s.cursor="default";

	this.updateLabelStyle (true);
	
	this.onselectstart=function(){return false;};

	this.model = BwGetById (this.getAttribute ("model"));
	if (this.model != null)
	{
		this.model.subscribe (this);
		this.value = this.getAttribute ("value");
	}
	else
	{
		var a = this.getAttribute ("value");
		if (a != null) {
			this.setValue (a);
		}
	}
	
	return false;
};

BwLabel.getValue = function ()
{
	return this.innerHTML;
};

BwLabel.nodeAdded = function (newNode, depth, hasChild)
{
	var data = this.model.dataFromNode (newNode);
	this.setValue (data[this.value]);
};

BwLabel.setValue = function (val)
{
	this.innerHTML = val;
};

BwLabel.disable = function ()
{
	this.updateLabelStyle (false);
};

BwLabel.enable = function ()
{
	this.updateLabelStyle (true);
};

BwClasses["BwLink"] = BwLink;

function BwLink ()
{
	this.isa = BwWidget;
	this.isa();
	
    this.url = null;
    this.targ = null;
    
	this.initFromDOM = BwLink.initFromDOM;
	
    this.setUrl = BwLink.setUrl;
	this.getUrl = BwLink.getUrl;

    this.setTarget = BwLink.setTarget;
	this.getTarget = BwLink.getTarget;

    this.setValue = BwLink.setValue;
	this.getValue = BwLink.getValue;
}

BwLink.newInstance = function (linkName, linkUrl, linkTarget)
{
	var self = document.createElement ("A");
	
	self.BwClass = BwLink;
	self.BwClass();

	self.className = "BwLink";
	
	if (linkUrl==null) {
		self.setAttribute ("href", "#");
    } else {
		self.setAttribute ("href", linkUrl);
    }
	
	if (linkName) {
		self.setAttribute ("title", linkName);
	}
	
    if (linkTarget && linkUrl!='null') {
		self.setAttribute ("target", linkTarget);
	}
	
	self.initFromDOM();
	
	return self;
};

BwLink.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
	
	this.style.cursor="pointer";
	var linkName = this.getAttribute ("title");

	if (linkName != null)
		this.setValue (linkName);

    return false;
};

BwLink.setUrl = function (u)
{
    this.url = u;
    this.href=u;
};

BwLink.getUrl = function ()
{
    var u = this.url;
    if (u==null) return null;
	return u;
};

BwLink.setTarget = function (targ)
{
    this.targ = targ;
    this.target = targ;
};

BwLink.getTarget = function ()
{
    var t = this.targ;
    if (t==null) return null;
	return t;
};

BwLink.getValue = function ()
{
	return this.innerHTML;
};

BwLink.setValue = function (link)
{
	this.innerHTML = link;
};

BwClasses["BwList"] = BwList;

function BwList ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.selection = [];
	this.primarySelection = null;
	this.columns = [];
	
	this.initFromDOM = BwList.initFromDOM;
	this.initColumns = BwTable.initColumns;
	this.initHeader = BwList.initHeader;
	this.initList = BwList.initList;
	this.initLayout = BwList.initLayout;
	
	this.drawHeaderCell = BwList.drawHeaderCell;
	this.drawHeaderCellSortIndicator = BwList.drawHeaderCellSortIndicator;
	this.drawHeaderCellTitle = BwList.drawHeaderCellTitle;
	this.drawAsyncActivityIndicator = BwList.drawAsyncActivityIndicator;
	this.updateHeaderCellSortIndicator = BwList.updateHeaderCellSortIndicator;
	this.updateRowsStyle = BwList.updateRowsStyle;
	this.updateHeaderContainerStyle = BwList.updateHeaderContainerStyle;
	this.updateListContainerStyle = BwList.updateListContainerStyle;
	
	this.updateBegins = BwList.updateBegins;
	this.updateEnds = BwList.updateEnds;

	this.mouseClicked = BwList.mouseClicked;
	this.mouseDoubleClicked = BwList.mouseDoubleClicked;
	this.mousePressed = BwList.mousePressed;
	this.mouseReleased = BwList.mouseReleased;
	this.mouseMoved = BwList.mouseMoved;
	this.keyPressed = BwList.keyPressed;
	
	this.handleColumnHeaders = BwList.handleColumnHeaders;
	
	this.sortColumn = BwList.sortColumn;
	this.closeRow = BwList.closeRow;
	this.openRow = BwList.openRow;
	
	this.selectRow = BwList.selectRow;
	this.selectRowByValue = BwList.selectRowByValue;
	this.deselect = BwList.deselect;
	this.deselectAll = BwList.deselectAll;
	this.select = BwList.select;
	
	this.scrollToRow = BwList.scrollToRow;

	this.cellUpdated = BwList.cellUpdated;
	this.cellFocused = BwList.cellFocused;

	this.getSelection = BwList.getSelection;
	this.getCellValue = BwList.getCellValue;
	this.getValue = BwList.getValue;
	this.getLength = BwList.getLength;
}

BwList.newInstance = function (rowModel, rowValue, multi, header, columns, width, height)
{
	var self = document.createElement ("div");
	
	self.BwClass = BwList;
	self.BwClass();
	
	self.className = "BwList";
	
	self.setAttribute ("rowModel", rowModel);
	self.setAttribute ("rowValue", rowValue);
	self.setAttribute ("multi", multi);
	self.setAttribute ("showHeader", header);
	
	if (height && height != null) {
		self.style.height=height+"px";
	}
	
	if (width && width != null) {
		self.style.width=width+"px";
	}

	for (var i = 0; i < columns.length; i++) {
		self.appendChild (columns[i]);
	}
	
	self.initFromDOM();
	
	return self;
};


BwList.initFromDOM = function ()
{
	var s = this.style;
	s.MozUserInput="enabled";
	s.MozUserFocus="normal";

	this.rowHeight = this.getAttribute ("rowHeight");
	
	this.initColumns();
	this.initHeader();
	this.initList();
	this.initLayout();
	
	var att = this.getAttribute ("hierarchy");
	if (att != null)
	{
		this.listTable.hierarchy = att;
	}
	
	att = this.getAttribute ("rowValue");
	if (att != null)
	{
		this.listTable.rowValue = att;
	}

	att = this.getAttribute ("rowModel");
	if (att != null)
	{
		this.listTable.rowModel = BwGetById (att);
	}
	
	att = this.getAttribute ("sortable");
	this.sortable = (!att || att == 'true') ? true : false;
	
	att = this.getAttribute ("multi");
	this.multi = (att == null || att == 'false') ? false : true;
	
	this.rowValue = this.getAttribute ("rowValue");
	this.onselect = this.getAttribute ("onselect");
	this.onaction = this.getAttribute ("onaction");
	this.onupdate = this.getAttribute ("onupdate");
	
	if (this.listTable.rowModel) {
		this.listTable.rowModel.subscribe (this.listTable);
	}

	var _this = this;
	this.onmousemove=function(e){_this.mouseMoved(e);};
	this.onmousedown=function(e){return _this.mousePressed(e);};
	this.onmouseup=function(e){_this.mouseReleased(e);};
	this.onclick=function(e){_this.mouseClicked(e);};
	this.ondblclick=function(e){_this.mouseDoubleClicked(e);};
	this.onkeydown = function(e){return _this.keyPressed(e);};
	
	if (this.header != null) {
		this.list.onscroll = function () {_this.header.scrollLeft = _this.list.scrollLeft; };
	}
	
	return false;
};

BwList.initHeader = function ()
{
	var show = this.getAttribute ("showHeader");
	if (show != null && show == 'false') return;
	
	var el;
	
	el = document.createElement ('div');
	el.className = "header";
	el.style.overflow = "hidden";
	
	this.appendChild (el);
	this.header = el;

	this.updateHeaderContainerStyle ();
	
	el = BwTable.newInstance();
	el.style.whiteSpace="nowrap";
	el.style.borderCollapse="collapse";
	el.style.tableLayout="fixed";
	el.style.border="none";
	el.cellSpacing=0;
	el.cellPadding=0;
	this.header.appendChild (el);
	this.headerTable = el;
	
	el = document.createElement ('tr');
	this.headerTable.tbody.appendChild (el);
	
	var tr = this.headerTable.tbody.firstChild;
	var l = this.columns.length;
	for (var i = 0; i < l; i++)
	{
		el = document.createElement ('col');
		el.columnIndex = i;
		this.headerTable.colgroup.appendChild (el);
		
		el = document.createElement ('td');
		if (i == (l - 1))
		{
			el.style.paddingRight = BwConstants.SCROLLBAR_SIZE;
		}
		el.style.overflow = "hidden";
		el.MozUserSelect="none";
		el.columnIndex = i;
		tr.appendChild (el);
		
		var c = this.drawHeaderCell (i);
		
		var a  = this.columns[i].align;
		c.titleContainer.style.textAlign = a;
	
		var t = this.drawHeaderCellTitle (i);
		var si = this.drawHeaderCellSortIndicator (i);
		this.columns[i].sortIndicator = si;
		
		if (a == "right")
		{
			c.sortIndicatorContainer.appendChild (si);
			c.titleContainer.appendChild (t);
		}
		else
		{
			c.titleContainer.appendChild (t);
			c.sortIndicatorContainer.appendChild (si);
		}

		el.appendChild (c);
	}
};

BwList.initList = function ()
{
	var el;

	el = document.createElement ('div');
	el.className = "list";
	el.style.overflow="auto";
	
	this.appendChild (el);
	this.list = el;
	
	this.updateListContainerStyle ();
	
	el = BwTable.newInstance ();
	el.rowHeight = this.rowHeight;
	
	var _this = this;
	el.updateBegins = function (r, i) { _this.updateBegins(r, i); };
	el.updateEnds = function (r) { _this.updateEnds(r); };
	el.updateRowsStyle = function () { _this.updateRowsStyle(); };
	el.cellUpdated = function (w) { _this.cellUpdated (w); };
	el.cellFocused = function (w) { _this.cellFocused (w); };
	el.columns = this.columns;
	
	el.style.whiteSpace="nowrap";
	el.style.borderCollapse="collapse";
	el.style.tableLayout="fixed";
	el.style.border="none";
	el.cellSpacing=0;
	el.cellPadding=0;
	this.list.appendChild (el);
	this.listTable = el;
	
	var l = this.columns.length;
	for (var i = 0; i < l; i++)
	{
		el = document.createElement ('col');
		this.listTable.colgroup.appendChild (el);
	}
};

BwList.updateBegins = function (refNode, insert)
{
	BwTable.updateBegins.call (this.listTable, refNode, insert);
	
	this.waitImage = this.drawAsyncActivityIndicator();
	this.list.appendChild (this.waitImage);
};

BwList.updateEnds = function ()
{
	this.updateRowsStyle ();
	this.list.removeChild (this.waitImage);
	
	BwTable.updateEnds.call (this.listTable);
};

BwList.initLayout = function ()
{
	var h = this.clientHeight;
	var hh = (this.header) ? this.header.offsetHeight : 0;
	
	if (this.style.height == "") this.style.height = "200px";
	
	this.list.style.height = (h - hh) + 'px';

	var w = this.offsetWidth;
	this.list.style.width = w + "px";
	if (this.header) this.header.style.width = w + "px";
	
	var l = this.columns.length;
	
	var c1 = (this.header) ? this.headerTable.colgroup.childNodes : null;
	var c2 = this.listTable.colgroup.childNodes;
	
	var t = 0;
	w -= BwConstants.SCROLLBAR_SIZE;
	for (var i = 0; i < l; i++)
	{
		var s = this.columns[i].size;
		if (!s) {
			s = "100px";
		}
		
		var v = parseInt (s);
		var p = (s.indexOf ('%') != -1);
			
		if (p) {
			v = (v / 100) * w;
		}
			
		t += v;
		
		c2[i].style.width = v + 'px';
		if (i == (l - 1)) v += BwConstants.SCROLLBAR_SIZE;
		if (this.header) c1[i].style.width = v + 'px';
	}
	
	if (this.header) this.headerTable.style.width = (t + BwConstants.SCROLLBAR_SIZE) + 'px';
	this.listTable.style.width = t + 'px';

	this.style.display="inline";
	this.style.display="block";
};

BwList.mouseDoubleClicked = function (event)
{
	if (!event) event = window.event;
	
	if (this.targetColumn != null) return true;

	var target = (event.target)?event.target:event.srcElement;
	var row = BwUtil.findParentElement (target, "TR");
	if (row != null && BwUtil.findParentElement (row, "DIV", "list") != null) {
		return BwUtil.call (this, this.onaction);
	}

	return true;
};

BwList.mouseClicked = function (event)
{
	if (!event) event = window.event;
	
	if (this.targetColumn != null) {
		return false;
	}

	var target = (event.target)?event.target:event.srcElement;
	
	if (BwUtil.findParentElement (target, "DIV", "header") != null)
	{
		if (this.listTable.hierarchy || !this.sortable) return;
		
		while (target != null && typeof target.columnIndex == "undefined") {
			target = target.parentNode;
		}
		
		if (target != null) {
			this.sortColumn (target.cellIndex);
		}
	}
	else
	{
		var row = BwUtil.findParentElement (target, "TR");
		if (row == null) return;
		
		if (row.openable && row.opener == target)
		{
			if (row.opened) this.closeRow (row);
			else this.openRow (row);
		}
		else
		{
			this.selectRow (row, event);
		}
	}

	return false;
};

BwList.mousePressed = function (event)
{
	if (this.targetColumn != null)
	{
		var c = this.headerTable.tbody.firstChild.childNodes[this.targetColumn.columnIndex];
		var l = BwUtil.getElementLeftPosition (c);
		l += this.targetColumn.offsetWidth;

		if (c.nextSibling == null) {
			l -= BwConstants.SCROLLBAR_SIZE;
		}
		
		this.targetColumn.lastX = this.targetColumn.offsetWidth;
		this.headerTable.lastX = this.headerTable.offsetWidth;
		this.lastX = l;
		
		if (!this.resizeMark)
		{
			var el = document.createElement ('div');
			var s = el.style;
			s.position = 'absolute';
			s.borderLeft = "1px solid #888888";
			s.height = this.list.clientHeight + 'px';
			s.top = BwUtil.getElementTopPosition (this.list) + 'px';
			
			l -= this.list.scrollLeft;
			el.style.left = l + "px";
			el.lastX = l;
			
			document.body.appendChild (el);
			this.resizeMark = el;
		}
		
		this.resizing = true;
		this.setCapture();

		return false;
	}
	
	return true;
};

BwList.mouseReleased = function (event)
{
	if (this.resizing)
	{
		var c = this.listTable.colgroup.childNodes[this.targetColumn.columnIndex];
		var l = this.targetColumn.offsetWidth;
		if (c.nextSibling == null)
		{
			l -= BwConstants.SCROLLBAR_SIZE;
		}
		c.style.width = l + "px";
		this.listTable.style.width = (this.headerTable.offsetWidth - BwConstants.SCROLLBAR_SIZE) + 'px';
		document.body.removeChild (this.resizeMark);
		this.resizeMark = null;
		if (this.header) this.header.scrollLeft = this.list.scrollLeft;
		
		this.resizing = false;
		this.releaseCapture();
	}
	
	return true;
};

BwList.mouseMoved = function (event)
{
	if (!event) event = window.event;
	
	var target = (event.target)?event.target:event.srcElement;
	var x = (event.pageX)?event.pageX:event.x;
	x += this.list.scrollLeft;
	
	if (this.resizing)
	{
		var o = x - this.lastX;
		var w = this.targetColumn.lastX + o;
		if (w <= 16) return;
		
		this.resizeMark.style.left = this.resizeMark.lastX + o + 'px';
		this.targetColumn.style.width = w + 'px';
		this.headerTable.style.width = (this.headerTable.lastX + o) + 'px';
	}
	else if (BwUtil.findParentElement (target, "DIV", "header") != null)
	{
		while (target != null && typeof target.columnIndex == "undefined") {
			target = target.parentNode;
		}
		
		if (target != null) {
			this.handleColumnHeaders (target, x);
		}
	}
	else
	{
		this.style.cursor = "default";
		this.targetColumn = null;
	}
};

BwList.handleColumnHeaders = function (target, x)
{
	var prev = target.previousSibling;
	var left = BwUtil.getElementLeftPosition (target);
	var right = left + target.offsetWidth;
	
	var next = target.nextSibling;
	if (next == null) {
		right -= BwConstants.SCROLLBAR_SIZE;
	}
	
	var res = false;
	if (prev && x <= (left + 7)) {
		target = prev;
		res = true;
	}
	else if (x >= (right - 7)) {
		res = true;
	}
	
	if (!res)
	{
		this.style.cursor = "default";
		this.targetColumn = null;
		return;
	}
	
	this.style.cursor = "e-resize";
	this.targetColumn = this.headerTable.colgroup.childNodes[target.cellIndex];
	this.targetColumn.lastX = target.offsetWidth;
	this.headerTable.lastX = this.headerTable.offsetWidth;
	this.lastX = x;
};

BwList.keyPressed = function (event)
{
	if (!event) event = window.event;

	var rows = this.listTable.tbody.rows;
	var row = (this.selection.length != 0) ? this.selection.peek() : null;
	var rowsPerPage = Math.floor (this.list.clientHeight / rows[0].offsetHeight);
	var last = rows.length - 1;
	
	switch (event.keyCode)
	{
		case 38:
			row = (row != null) ? row.previousSibling : rows[0];
			var r = row;
			while (r != null && r.style.display == 'none') {
				r = r.previousSibling;
			}
			if (r != null) row = r;
			break;
			
		case 40:
			row = (row != null) ? row.nextSibling : rows[0];
			var r = row;
			while (r != null && r.style.display == 'none') {
				r = r.nextSibling;
			}
			if (r != null) row = r;
			break;
			
		case 33:
			var i = 0;
			if (row == null) row = rows[0];
			while (row.previousSibling != null)
			{
				if (row.style.display != 'none') i++;
				if (i > rowsPerPage) break;
				row = row.previousSibling;
			}
			break;
			
		case 34:
			var i = 0;
			if (row == null) row = rows[0];
			while (row.nextSibling != null)
			{
				if (row.style.display != 'none') i++;
				if (i > rowsPerPage) break;
				row = row.nextSibling;
			}
			break;
			
		case 36:
			row = rows[0];
			break;

		case 35:
			row = rows[last];
			while (row != null && row.style.display == 'none') {
				row = row.previousSibling;
			}
			break;

		case 13:
			BwUtil.call (this, this.onaction);
			return false;
			
		default:
			return true;
	}
	
	if (row)
	{
		this.selectRow (row, event);
		this.scrollToRow (row);
	}

	return false;
};

BwList.sortColumn = function (colIndex)
{
	this.sortedAscending = (colIndex != this.sortedColumnIndex) ? true : !this.sortedAscending;
	this.sortedColumnIndex = colIndex;
	
	var l = this.columns.length;
	for (var i = 0; i < l; i++) {
		this.updateHeaderCellSortIndicator (this.columns[i].sortIndicator, i);
	}
	
	var _this = this;
	var _i = colIndex;
	var cb = function () {
		_this.listTable.sort (_i, _this.sortedAscending);
	};
	setTimeout (cb, 50);
};

BwList.closeRow = function (row)
{
	this.updateBegins();
	
	var d = row.depth;
	var n = row.nextSibling;
	while (n != null)
	{
		if (n.depth <= row.depth) break;
		
		n.style.display = 'none';
		
		n = n.nextSibling;
	}

	row.opened = false;
	row.opener.setSource ("closed.png");
	
	this.updateEnds();
};

BwList.openRow = function (row)
{
	this.updateBegins();

	var stack = [];
	var n = row;
	while ((n = n.nextSibling) != null)
	{
		if (n.depth <= row.depth) break;
		
		var d = stack.peek();
		if (d != null)
		{
			if (n.depth > d) continue;
			stack.pop();
		}
		
		if (n.openable && !n.opened)
		{
			stack.push (n.depth);
		}
		
		n.style.display = '';
	}
	
	row.opened = true;
	row.opener.setSource ("opened.png");
	
	this.updateEnds();
};

BwList.selectRow = function (row, e)
{
	var r = this.selection.lookup (row);

	if (e && e.ctrlKey)
	{
		if (r == -1) {
			if (!this.multi && this.selection.length != 0) {
				this.deselect (this.selection[0]);
			}
			
			this.select (row);
			this.primarySelection = row;
		} else {
			this.deselect (row);
			if (this.selection.length == 0) {
				this.primarySelection = null;
			}
		}
	}
	else if (this.multi && e && e.shiftKey && this.primarySelection != null)
	{
		var last = this.primarySelection;
		this.deselectAll();
		
		var i1 = last.rowIndex;
		var i2 = row.rowIndex;
		if (i1 < i2) {
			for (var i = i1; i <= i2; i++) {
				this.select (this.listTable.tbody.rows[i]);
			}
		} else {
			for (var i = i1; i >= i2; i--) {
				this.select (this.listTable.tbody.rows[i]);
			}
		}
	}
	else
	{
		this.deselectAll();
		this.select (row);
		this.primarySelection = row;
	}
	
	this.updateRowsStyle();
	
	BwUtil.call (this, this.onselect);
};

BwList.deselectAll = function ()
{
	var l = this.selection.length;
	for (var i = 0; i < l; i++) {
		this.selection[i].selected = false;
	}
	this.selection = [];
};

BwList.deselect = function (row)
{
	if (!row) return;
	row.selected = false;
	
	var i = this.selection.lookup (row);
	if (i == -1) return;
	
	this.selection.splice (i, 1);
};

BwList.selectRowByValue = function (value)
{
	var rows = this.listTable.tbody.rows;
	var l = rows.length;
	for (var i = 0; i < l; i++)
	{
		var r = rows[i];
		if (r.value == value) {
			this.selectRow (r);
			this.scrollToRow (r);
			return;
		}
	}
};

BwList.select = function (row)
{
	var c = row.childNodes;
	var l = c.length;
	
	var i = this.selection.lookup (row);
	if (i != -1) return;
	
	this.selection.push (row);
	row.selected = true;

	this.listTable.rowModel.setCursorPath (this.listTable.rowToPath (row));
};

BwList.scrollToRow = function (row)
{
	if (row.offsetTop < this.list.scrollTop) {
		this.list.scrollTop = row.offsetTop;
	}
	else if ((row.offsetTop + row.offsetHeight) > (this.list.scrollTop + this.list.clientHeight)) {
		this.list.scrollTop = row.offsetTop - this.list.clientHeight + row.offsetHeight;
	}
};

BwList.cellFocused = function (widget)
{
	var row = widget.parentNode.parentNode.parentNode;
	this.selectRow (row);
};

BwList.cellUpdated = function (widget)
{
	var td = widget.parentNode.parentNode;
	var i = td.cellIndex;
	var row = td.parentNode;
	
	/*
	if (this.sortedColumnIndex == i) {
		this.listTable.sort (i, this.sortedAscending);
		this.scrollToRow (row);
	}
	*/

	if (this.onupdate && this.onupdate != null)
	{
		this.changedRow = row;
		this.changedCellIndex = i;
		BwUtil.call (this, this.onupdate);
	}
};

BwList.getSelection = function ()
{
	return this.selection;
};

BwList.getValue = function ()
{
	var s = this.selection;
	var l = s.length;
	if (l == 0) {
		return null;
	}

	return s[l-1].value;
};
BwList.getCellValue = function (row, colIndex)
{
	return this.listTable.getCellValue (row, colIndex);
};


BwList.getLength = function ()
{
	return this.listTable.tBodies[0].rows.length;
};

BwClasses["BwNotebook"] = BwNotebook;

function BwNotebook ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.tabs = [];
	this.tabsContent = [];
	this.pages = [];
	this.selected = 0;
	
	this.initFromDOM = BwNotebook.initFromDOM;
	this.addPage = BwNotebook.addPage;
	this.redraw = BwNotebook.redraw;
	this.selectTab = BwNotebook.selectTab;
	
	this.drawTabBar = BwNotebook.drawTabBar;
	this.drawSelectedTab = BwNotebook.drawSelectedTab;
	this.drawTab = BwNotebook.drawTab;
}

BwNotebook.newInstance = function()
{
	var self = document.createElement("div");
	
	self.BwClass = BwNotebook;
	self.BwClass();
	
	self.initFromDOM();
	
	return self;
};

BwNotebook.initFromDOM = function()
{
	var bar = this.drawTabBar();

	if (this.firstChild == null) this.appendChild (bar);
	else this.insertBefore (bar, this.firstChild);
	
	this.tabBarWidth = bar.offsetWidth;
	
	this.onselect = this.getAttribute ("onselect");
	
	return true;
};

BwNotebook.removePage = function (index)
{
};

BwNotebook.addPage = function (page, label, image)
{
	var c = BwLabel.newInstance (label);
	this.tabsContent.push (c);
	
	this.pages.push (page);
	
	this.redraw();
	
	if (this.pages.length == 1) {
		page.show();
	}
};

BwNotebook.redraw = function ()
{
	var tb = this.tabBar;
	
	var l = this.tabs.length;
	for (var i = 0; i < l; i++)
	{
		var t = this.tabs[i];
		tb.removeChild (t);
	}
	
	this.tabs = [];
	
	l = this.tabsContent.length;
	for (var i = 0; i < l; i++)
	{
		var c = this.tabsContent[i];
		var tab = (this.selected == i) ? this.drawSelectedTab (c, i) : this.drawTab (c, i);
		tab.index = i;
		tab.style.cursor = 'default';
		
		
		if (i == 0) {
			if (tb.firstChild != null) tb.insertBefore (tab, tb.firstChild);
			else tb.appendChild (tab);
		} else {
			var last = this.tabs[this.tabs.length - 1]; 
			if (tb.lastChild != last) tb.insertBefore (tab, last.nextSibling);
			else tb.appendChild (tab);
		}
		
		var _this = this;
		tab.onclick = function() { _this.selectTab (this.index); };
		
		this.tabs.push (tab);
	}
};

BwNotebook.selectTab = function (index)
{
	this.pages[this.selected].hide();
	this.selected = index;
	this.pages[this.selected].show();
	this.redraw();
};

BwClasses["BwNotebookPage"] = BwNotebookPage;

function BwNotebookPage ()
{
	this.isa = BwView;
	this.isa();
	
	this.initFromDOM = BwNotebookPage.initFromDOM;
	this.setStyle = BwNotebookPage.setStyle;
}

BwNotebookPage.initFromDOM = function ()
{
	BwView.initFromDOM.call (this);
	
	this.setStyle();
	
	var l = this.getAttribute ("label");
	var i = this.getAttribute ("image");
	
	var n = this.getParentWidget (BwNotebook);
	
	var b = n.addPage (this, l, i);
	if (b) this.show();
	
	return false;
};



BwClasses["BwPopup"] = BwPopup;

function BwPopup ()
{
	this.isa = BwEditableWidget;
	this.isa();
	
	this.initFromDOM = BwPopup.initFromDOM;
	
	this.nodeAdded = BwPopup.nodeAdded;
	this.nodesRemoved = BwPopup.nodesRemoved;
	
	this.getValue = BwPopup.getValue;
	this.setValue = BwPopup.setValue;
}

BwPopup.newInstance = function (rowModel, rowValue, label, disabled)
{
	var self = document.createElement ("div");
	
	self.BwClass = BwPopup;
	self.BwClass();
	
	self.className = "BwPopup";
	
	if (rowModel) self.setAttribute ("rowModel", rowModel);
	if (rowValue) self.setAttribute ("rowValue", rowValue);
	if (label) self.setAttribute ("label", label);
	
	self.initFromDOM();
	
	if (typeof disabled != "undefined" && Boolean(disabled) == true) {
		self.disable();
	}

	return self;
};

BwPopup.initFromDOM = function ()
{
	BwEditableWidget.initFromDOM.call (this);
	
	this.style.display="inline";
	
	this.field = document.createElement ("select");
	this.appendChild (this.field);

	this.rowValue = this.getAttribute ("rowValue");
	this.label = this.getAttribute ("label");
	
	this.rowModel = BwGetById (this.getAttribute ("rowModel"));
	if (this.rowModel != null) {
		this.rowModel.subscribe (this);
	}
	
	s = this.getAttribute ("selected");
	if (s)
	{
		var _this = this;
		setTimeout (function(){_this.setValue(s);}, 5);
	}

	return false;
};

BwPopup.nodeAdded = function (newNode, depth, hasChild)
{
	var data = this.rowModel.dataFromNode (newNode);
	var v = data[this.rowValue];
	var l = data[this.label];
	var o = document.createElement ("option");
	var t = document.createTextNode (l);

	o.value  = v;
	o.appendChild (t);
	
	this.field.appendChild (o);
};

BwPopup.nodesRemoved = function ()
{
	while (this.field.firstChild != null)
	{
		this.field.removeChild (this.field.firstChild);
	}
};

BwPopup.getValue = function ()
{
	return this.field.options[this.field.selectedIndex].value;
};

BwPopup.setValue = function (v)
{
	var ops = this.field.options;
	var l = ops.length;
	for (var i = 0; i < l; i++)
	{
		var o = ops[i];
		if (o.value == v)
		{
			this.field.selectedIndex = i;
			return;
		}
	}
};


BwClasses["BwPopupNew"] = BwPopupNew;

function BwPopupNew ()
{
	this.isa = BwEditableWidget;
	this.isa();
	
	this.initFromDOM = BwPopupNew.initFromDOM;
	
	this.updateEnds = BwPopupNew.updateEnds;
	
	this.getValue = BwPopupNew.getValue;
	this.setValue = BwPopupNew.setValue;
}

/*
BwPopupNew.newInstance = function (rowModel, rowValue, label, disabled)
{
	var self = document.createElement ("div");
	
	self.BwClass = BwPopupNew;
	self.BwClass();
	
	self.className = "BwPopupNew";
	
	if (rowModel) self.setAttribute ("rowModel", rowModel);
	if (rowValue) self.setAttribute ("rowValue", rowValue);
	if (label) self.setAttribute ("label", label);
	
	self.initFromDOM();
	
	if (typeof disabled != "undefined" && Boolean(disabled) == true) {
		self.disable();
	}

	return self;
};
*/

BwPopupNew.initFromDOM = function ()
{
	BwEditableWidget.initFromDOM.call (this);
	
	this.style.display="inline";
	
	var rowModel = this.getAttribute ("rowModel");
	if (rowModel)
	{
		this.rowModel = BwGetById (rowModel);
		this.rowModel.subscribe (this);
	}
	
	this.rowValue = this.getAttribute ("rowValue");
	
	var cols = [];
	var f;
	while ((f = this.firstChild) != null)
	{
		cols.push (f);
		this.removeChild (f);
	}
	
	var f = BwFrame.newInstance ();
	this.appendChild (f);
	
	var t = document.createElement ("table");
	t.cellspacing=0;
	t.cellpadding=0;
	t.style.width = "200px";
	this.contentContainer = document.createElement ("tbody");
	t.appendChild (this.contentContainer);
	
	var _this = this;
	this.contentContainer.onclick = function () { _this.list.style.display = (_this.list.style.display == "block") ? "none" : "block"; };
	this.contentContainer.style.height="22px";
	
	f.contentContainer.appendChild (t);
	
	this.list = document.createElement ("div");
	this.list.style.width = "200px";
	this.list.style.height = "300px";
	this.list.style.display = "none";
	this.list.style.position = "absolute";
	this.list.style.overflow = "auto";
	this.list.style.backgroundColor = "#ffffff";
	
	var hierarchy = this.getAttribute ("hierarchy");
	var h;

	if (hierarchy) {
		h = hierarchy;
	}
	
	this.table = BwTable.newInstance (rowModel, this.rowValue, cols, 200, 300, h);
	this.list.appendChild (this.table);
	
	f.contentContainer.appendChild (this.list);

	/*
	s = this.getAttribute ("selected");
	if (s)
	{
		var _this = this;
		setTimeout (function(){_this.setValue(s);}, 5);
	}
	*/

	return false;
};

BwPopupNew.updateEnds = function ()
{
	var rec = this.table.tbody.childNodes[0];
	this.contentContainer.appendChild (rec.cloneNode (true));
};

BwPopupNew.getValue = function ()
{
	return this.field.options[this.field.selectedIndex].value;
};

BwPopupNew.setValue = function (v)
{
	var ops = this.field.options;
	var l = ops.length;
	for (var i = 0; i < l; i++)
	{
		var o = ops[i];
		if (o.value == v)
		{
			this.field.selectedIndex = i;
			return;
		}
	}
};

function BwQuery ()
{
	this.asyncCallback = null;

	this.impl = null;
	if (document.all) {
		this.impl = new ActiveXObject("Microsoft.XMLHTTP");
	} else {
		this.impl = new XMLHttpRequest();
	}
};

BwQuery.prototype.get = function (url, callback)
{
	this.transmit ("GET", url, null, callback);
};

BwQuery.prototype.post = function (url, obj, callback)
{
	if (typeof obj == "object" && obj.constructor == BwMessage) {
		obj = obj.dom;
	}
	this.transmit ("POST", url, obj, callback);
};

BwQuery.prototype.transmit = function (method, url, obj, callback)
{
	var async = (typeof callback != "undefined");
	if (async) {
		this.asyncCallback = callback;
	}
	
	this.impl.open (method, this.buildUrl (url), async);
	
	if (async) {
		var _this = this;
		this.impl.onreadystatechange = function () { _this.readyStateChanged(); };
	}
	
	this.impl.send (obj);
};

BwQuery.prototype.readyStateChanged = function ()
{
	if (this.impl.readyState == 4) {
		this.asyncCallback ();
	}
};

BwQuery.prototype.setHeader = function (name, value)
{
	this.impl.setHeader (name, value);
};

BwQuery.prototype.getText = function ()
{
	return this.impl.responseText;
};

BwQuery.prototype.getMessage = function ()
{
	return BwMessage.initFromXML (this.impl.responseXML);
};

BwQuery.prototype.getXML = function ()
{
	return this.impl.responseXML;
};

BwQuery.prototype.getStatus = function ()
{
	return this.impl.status;
};

BwQuery.prototype.getStatusText = function ()
{
	return this.impl.statusText;
};

BwQuery.prototype.buildUrl = function (url)
{
	var l = document.location;
	if (url.indexOf ("/") == 0)
	{
		var p = l.port;
		var h = l.host;
		var u = l.protocol + "//" + h;
		if (p != null && p != "" && h.indexOf (p) < 0) {
			u += (":" + p);
		}
		return (u + url);
	} 
	else 
	{
		var l = l.toString();
		var p = l.lastIndexOf ("/");
		var u = l.substr (0, p);
		return (u + "/" + url);
	}

	/*
		FIXME Bug !!! ne marche pas avec les URL absolues
	*/
};


BwClasses["BwRanking"] = BwRanking;

function BwRanking ()
{
	this.isa = BwEditableWidget;
	this.isa();
	
	this.disabled = false;
	this.stars = 0;
	
	this.initFromDOM = BwRanking.initFromDOM;
	
	this.draw = BwRanking.draw;
	
	this.setValue = BwRanking.setValue;
	this.getValue = BwRanking.getValue;
	
	this.mouseClicked = BwRanking.mouseClicked;
	
	this.disable = BwRanking.disable;
	this.enable = BwRanking.enable;
}

BwRanking.newInstance = function (v)
{
	var self = document.createElement ("DIV");
	
	self.BwClass = BwRanking;
	self.BwClass();
	
	self.className = "BwRanking";
	
	self.setAttribute ("value", v);
	
	self.initFromDOM ();
	
	return self;
};

BwRanking.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
	
	this.style.display="inline";
	
	var v = this.getAttribute ("value");
	if (v != null) {
		this.stars = v;
	}
	
	this.draw();
	
	this.onupdate = this.getAttribute ("onupdate");
	
	var _this = this;
	this.onclick = function(e){_this.mouseClicked(e);};
	
	return false;
};

BwRanking.draw = function ()
{
	var s = this.style;
	s.height="16px";
	s.width="80px";

	for (var i = 0; i < 5; i++)
	{
		var img = BwStockIcon.newInstance ((this.stars > i) ? "star.png" : "nostar.png");
		img.style.width = "16px";
		img.style.height = "16px";
		img.starIndex = i;
		this.appendChild (img);
	}
};

BwRanking.mouseClicked = function (event)
{
	if (this.disabled) return;
	
	if (!event) event = window.event;
	var target = (event.target)?event.target:event.srcElement;
	var i = target.starIndex;
	
	if (this.stars == ++i) i--;
	
	this.setValue (i);
};

BwRanking.getValue = function ()
{
	return this.stars;
};

BwRanking.setValue = function (v)
{
	if (v<0)v=0;
	if (v>5)v=5;
	this.stars=v;
	
	for (var i = 0; i < 5; i++)
	{
		var img = this.childNodes[i];
		var ico = (v > i) ? "star.png" : "nostar.png";
		img.setSource (ico);
	}
	
	BwUtil.call (this, this.onupdate);
};

BwRanking.disable = function ()
{
	this.disabled = true;
	var s = this.style;
	s.opacity = "0.4";
	s.filter = "alpha(opacity=40)";
};

BwRanking.enable = function ()
{
	this.disabled = false;
	var s = this.style;
	s.opacity = "1";
	s.filter = "alpha(opacity=100)";
};


BwClasses["BwStockIcon"] = BwStockIcon;

function BwStockIcon ()
{
	this.isa = BwImage;
	this.isa();
	
	this.getSource = BwStockIcon.getSource;
	this.setSource = BwStockIcon.setSource;
}

BwStockIcon.newInstance = BwImage.newInstance;
BwStockIcon.storagePath = "icons/";

BwStockIcon.getSource = function ()
{
	var src = BwImage.getSource.call (this);
	var p = BwThemePath + BwStockIcon.storagePath;
	return src.substring (p.length, this.url.length);
};

BwStockIcon.setSource = function (src)
{
	BwImage.setSource.call (this, BwThemePath + BwStockIcon.storagePath + src);
};

BwClasses["BwTable"] = BwTable;

function BwTable ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.columns = [];
	
	this.initFromDOM = BwTable.initFromDOM;
	this.initColumns = BwTable.initColumns;
	
	this.pathToRow = BwTable.pathToRow;
	this.rowToPath = BwTable.rowToPath;
	this.nodeToRow = BwTable.nodeToRow;
	
	this.nodesRemoved = BwTable.nodesRemoved;
	this.nodeAdded = BwTable.nodeAdded;
	this.nodeRemoved = BwTable.nodeRemoved;
	this.updateBegins = BwTable.updateBegins;
	this.updateEnds = BwTable.updateEnds;
	
	this.updateRowsStyle = BwTable.updateRowsStyle;
	this.drawHierarchyIndicator = BwTable.drawHierarchyIndicator;
	
	this.sort = BwTable.sort;
	this._compare = BwTable._compare;
	
	this.getCellValue = BwTable.getCellValue;
}

BwTable.newInstance= function (rowModel, rowValue, columns, width, height, hierarchy)
{
	var self = document.createElement ("table");
	
	self.BwClass = BwTable;
	self.BwClass();
	
	if (rowModel) {
		self.setAttribute ("rowModel", rowModel);
	}

	if (rowValue) {
		self.setAttribute ("rowValue", rowValue);
	}
	
	if (height && height != null) {
		self.style.height=height+"px";
	}
	
	if (width && width != null) {
		self.style.width=width+"px";
	}
	
	if (columns) {
		for (var i = 0; i < columns.length; i++) {
			self.appendChild (columns[i]);
		}
	}

	if (typeof hierarchy != 'undefined')
	{
		self.setAttribute ("hierarchy", hierarchy);
	}

	self.initFromDOM ();
	
	return self;
};

BwTable.initFromDOM = function ()
{
	this.initColumns();
	
	this.tbody = document.createElement ("tbody");
	this.appendChild (this.tbody);
	
	this.colgroup = document.createElement ("colgroup");
	this.appendChild (this.colgroup);
	
	var att = this.getAttribute ("hierarchy");
	if (att != null) {
		this.hierarchy = att;
	}
	
	this.rowValue = this.getAttribute ("rowValue");
	
	att = this.getAttribute ("rowModel");
	if (att != null) {
		this.rowModel = BwGetById (att);
		if (this.rowModel != null) {
			this.rowModel.subscribe (this);
		}
	}
	
	return false;
};

BwTable.initColumns = function ()
{
	var curr;
	while ((curr = this.firstChild) != null)
	{
		this.removeChild (curr);
		
		if (curr.className == "BwColumn")
		{
			var col = new BwColumn ();
			col.setName (curr.getAttribute ("name"));
			col.setSize (curr.getAttribute ("size"));
			col.setAlign (curr.getAttribute ("align"));
			col.loadRenderCode (curr.getAttribute ("render"));
			
			this.columns.push (col);
		}
	}
};

BwTable.rowToPath = function (row)
{
	var d = row.depth;
	var r = row;
	var l = d + 1;
	var path = new Array (l);

	for (var i = 0; i < l; i++) {
		path[i] = -1;
	}
	
	for (var i = d; i >= 0; i--)
	{
		while (r != null && r.depth >= i)
		{
			if (r.depth == i)
			{
				var v = path[i];
				path[i] = ++v;
			}
			r = r.previousSibling;
		}
	}
	
	return path;
};

BwTable.pathToRow = function (path)
{
	if (typeof path == 'number') {
		path = [ path ];
	}

	var r = this.tbody.firstChild;
	var l = path.length;
	for (var i = 0; i < l; i++)
	{
		var p = path[i];
		
		var j = -1;
		while (r != null)
		{
			if (r.depth == i) j++;
			if (j == p) break;
			r = r.nextSibling;
		}
	}
	return r;
};

BwTable.nodeToRow = function (node)
{
	if (node == null) return null;
	
	var t = this.tbody;
	var r = t.firstChild;
	
	while (r != null) {
		if (r.modelNode == node) break;
		r = r.nextSibling;
	}
	
	return r;
};


BwTable.nodeRemoved = function (path)
{
	var ref = this.pathToRow (path);
	var r = ref;
	var t = this.tbody;
	var d = ref.depth;
	var a = [];
	while ((r = r.nextSibling) != null)
	{
		if (r.depth > d)
		{
			a.push (r);
			continue;
		}
		break;
	}
	
	var l = a.length;
	for (var i = 0; i < l; i++) {
		t.removeChild (a[i]);
	}
	
	t.removeChild (ref);
	
	this.updateRowsStyle();
};

BwTable.nodesRemoved = function ()
{
	var t = this.tbody;
	var r;
	while ((r = t.firstChild) != null)
	{
		t.removeChild (r);
	}
};

BwTable.updateBegins = function (refNode, insert)
{
	var r = null;

	if (refNode != null)
	{
		r = this.nodeToRow (refNode);
		if (!insert)
		{
			var d = r.depth;
			r = r.nextSibling;
			while (r != null)
			{
				if (r.depth < d) break;
				r = r.nextSibling;
			}
		}
	}
	this.massUpdateRowRef = r;
	
	this.removeChild (this.tbody);
};

BwTable.updateEnds = function ()
{
	this.appendChild (this.tbody);
};

BwTable.nodeAdded = function (newNode, depth, hasChild)
{
	var t = this.tbody;
	var data = this.rowModel.dataFromNode (newNode);

	var cl = this.columns.length;
	var tr = document.createElement ("tr");
	tr.modelNode = newNode;
	if (this.rowHeight) tr.style.height = this.rowHeight;
	
	tr.value = data[this.rowValue];
	
	for (var i = 0; i < cl; i++)
	{
		var td = document.createElement ("td");
		td.onselectstart=function(){return typeof window.event.srcElement.editable!='undefined';};
		
		var col = this.columns[i];
		var content = col.cellContent (data, this);
		
		var div = document.createElement ("div");
		
		if (this.hierarchy && this.hierarchy == i)
		{
			var img = this.drawHierarchyIndicator (depth, hasChild);
			div.appendChild (img);
			tr.opener = img;
			tr.openable = hasChild;
			tr.opened = hasChild;
		}
		
		div.appendChild (content);
		div.style.whiteSpace = "nowrap";
		div.style.overflow = "hidden";
		
		td.appendChild (div);
		tr.appendChild (td);
		
		td.content = content;
		tr.depth = depth;
	}

	(this.massUpdateRowRef) ? t.insertBefore (tr, this.massUpdateRowRef) : t.appendChild (tr);
};

BwTable.sort = function (col, asc)
{
	this.updateBegins();
	
	var t = this.tbody;
	var r = t.firstChild;
	var a = [];
	while (r != null) {
		a.push (r);
		r = r.nextSibling;
	}
	
	var _this = this;
	a.sort (function (a,b){return _this._compare(a,b, col, asc);});
	
	var l = a.length;
	for (var i = 0; i < l; i++)
	{
		var r = a[i];
		t.removeChild (r);
		t.appendChild (r);
	}
	
	this.updateEnds();
};

BwTable._compare = function (a, b, i, asc)
{
	a = this.getCellValue (a, i);
	b = this.getCellValue (b, i);
	/*if (a.toUpperCase && b.toUpperCase)
	{
		a = a.toUpperCase();
		b = b.toUpperCase();
	}
	*/
	var r;
	if (a > b) r = 1;
	else if (a < b) r = -1;
	else r = 0;

	if (!asc) r = -r;
	
	return r;
};

BwTable.getCellValue = function (row, colIndex)
{
	var c = row.childNodes[colIndex];
	return c.content.getValue();
};


BwClasses["BwTextfield"] = BwTextfield;

function BwTextfield ()
{
	this.isa = BwEditableWidget;
	this.isa();
	
	this.input = null;
	
	this.initFromDOM = BwTextfield.initFromDOM;
	
	this.updateStyle = BwTextfield.updateStyle;
	
	this.setValue = BwTextfield.setValue;
	this.getValue = BwTextfield.getValue;
}

BwTextfield.newInstance = function (val, disabled)
{
	var self = document.createElement ("div");
	
	self.BwClass = BwTextfield;
	self.BwClass();
	
	self.className = "BwTextfield";
	
	if (val) {
		self.setAttribute ("value", val);
	}
	
	self.initFromDOM ();
	
	if (typeof disabled != "undefined" && Boolean(disabled) == true) {
		self.disable();
	}

	return self;
};

BwTextfield.initFromDOM = function ()
{
	BwEditableWidget.initFromDOM.call (this);
	
	var el = document.createElement ("input");
	el.type = "text";
	el.style.MozUserSelect="text";
	el.style.width = "100%";
	this.input = el;
	
	this.updateStyle ();
	
	this.appendChild (el);
	
	var att = this.getAttribute ("value");
	if (att != null) {
		this.setValue (att);
	}
	
	this.onupdate = this.getAttribute ("onupdate");
	
	var _this = this;
	this.input.onchange = function () { BwUtil.call (_this, _this.onupdate); };
};

BwTextfield.getValue = function ()
{
	return this.input.value;
};

BwTextfield.setValue = function (txt)
{
	this.input.value = txt;
};
function BwUtil ()
{
};

BwUtil.findParentElement = function (element, parentNodeName, parentClassName, parentId)
{
	var e = element.parentNode;
	while (e != null)
	{
		var n = (e.nodeName == parentNodeName);
		var c = (e.className == parentClassName);
		var i = (e.id == parentId);
		
		if (((parentNodeName != null && n) || (parentNodeName == null && !n)) &&
		((parentClassName != null && c) || (parentClassName == null && !c)) &&
		((parentId != null && i)  || (parentId == null && !i))) {
			return e;
		}
		
		e = e.parentNode;
	}
	
	return null;
};

BwUtil.findContainerWidget = function (element, widgetClass)
{
	var e = element.parentNode;
	while (e != null)
	{
		if (e.BwClass) {
			if (!widgetClass) {
				return e;
			} else {
				if (e.BwClass == widgetClass) {
					return e;
				}
			}
		}

		e = e.parentNode;
	}
	
	return null;
};

BwUtil.getElementTopPosition = function (e)
{
	var t = e.offsetTop;
    var p = e.offsetParent;
    while (p) 
	{
        t += p.offsetTop;
        p = p.offsetParent;
    }
    return t;
};

BwUtil.getElementLeftPosition = function (e)
{
	var l = e.offsetLeft;
    var p = e.offsetParent;
    while (p) {
        l += p.offsetLeft;
        p = p.offsetParent;
    }
    return l;
};

BwUtil.getGlobalMousePosition = function (event)
{
	if (!event) event = window.event;
	
	var p = { x: event.clientX, y: event.clientY };
	var d = document.documentElement;
	var b = document.body;
	var w = window;

	p.x += (w.scrollX) ? w.scrollX : (d.scrollLeft + b.scrollLeft);
	p.y += (w.scrollY) ? w.scrollY : (d.scrollTop + b.scrollTop);

	return p;
};

BwUtil.call = function (obj, func)
{
	if (obj == null || func == null) return;
	
	var f = (typeof func == 'string') ? new Function (func) : func;
	return f.call (obj);
};

BwClasses["BwView"] = BwView;

function BwView ()
{
	this.isa = BwWidget;
	this.isa();
	
	this.bootstrapped = false;
	
	this.initFromDOM = BwView.initFromDOM;

	this.show = BwView.show;
	this.clear = BwView.clear;
}

BwView.newInstance = function ()
{
	var self = document.createElement ("div");
	
	self.BwClass = BwView;
	self.BwClass();
	
	self.initFromDOM();
	
	return self;
	
};

BwView.initFromDOM = function ()
{
	BwWidget.initFromDOM.call (this);
	
	this.hide();
	this.bootstrapped = false;
	
	var v = this.getAttribute ("opened");
	if (v == 'true' || v == true) {
		this.show();	
	}

	return false;
};

BwView.show = function ()
{
	BwWidget.show.call (this);
	if (!this.bootstrapped) {
		BwBootstrapElement (this);
		this.bootstrapped = true;
	}
};

BwView.clear = function ()
{
	this.innerHTML='';
};

function BwWidget ()
{
	this.initFromDOM = BwWidget.initFromDOM;

	this.show = BwWidget.show;
	this.hide = BwWidget.hide;
	this.visible = BwWidget.visible;
	
	this.getValue = BwWidget.getValue;
	this.setValue = BwWidget.setValue;
	
	this.getParentWidget = BwWidget.getParentWidget;
	this.isaDescendantOf = BwWidget.isaDescendantOf;
}

BwWidget.initFromDOM = function ()
{
	return true;
};

BwWidget.show = function ()
{
	this.style.display = "block";
};

BwWidget.hide = function ()
{
	this.style.display = "none";
};

BwWidget.visible = function ()
{
	return (this.style.display != "none");
};

BwWidget.getValue = function ()
{
	return null;
};

BwWidget.setValue = function (val)
{
};

BwWidget.isaDescendantOf = function (widget)
{
	var w = this;
	while (w != null)
	{
		if (w == widget) return true;
		w = w.parentNode;
	}
	return false;
};

BwWidget.getParentWidget = function (widgetClass)
{
	return BwUtil.findContainerWidget (this, widgetClass);
};
BwClasses["BwWindow"] = BwWindow;

function BwWindow()
{
	this.isa = BwWidget;
	this.isa();
	
	this.initFromDOM = BwWindow.initFromDOM;
	this.draw = BwWindow.draw;
	this.show = BwWindow.show;
	
	this.mousePressed = BwWindow.mousePressed;
	this.mouseReleased = BwWindow.mouseReleased;
	this.mouseMoved = BwWindow.mouseMoved;
}

BwWindow.newInstance = function ()
{
	var self = document.createElement ('div');
	
	self.BwClass = BwWindow;
	self.BwClass();

	self.initFromDOM();
	
	return self;
};

BwWindow.initFromDOM = function ()
{
	var save = [];
	while (this.firstChild != null)
	{
		save.push (this.firstChild);
		this.removeChild (this.firstChild);
	}
	
	var win = this.draw();
	this.appendChild (win);
	
	this.style.position='absolute';
	this.style.zIndex=100;
	
	var l = save.length;
	for (var i = 0; i < l; i++)
	{
		this.contentContainer.appendChild (save[i]);
	}
	delete save;
	
	var c = this.titleContainer;
	var t = this.getAttribute ("title");
	if (t && t != null)
	{
		c.appendChild (BwLabel.newInstance (t));
		this.removeAttribute ("title");
	}
	c.style.whiteSpace="nowrap";
	
	this.controlsContainer.appendChild (BwLabel.newInstance ("X"));
	
	var _this = this;
	this.onmousedown=function(e){return _this.mousePressed(e);};
	this.onmouseup=function(e){_this.mouseReleased(e);};
	
	this.titleContainer.onselectstart = function() { return false; };
	this.controlsContainer.onselectstart = function() { return false; };
	
	return true;
};

BwWindow.mousePressed = function (event)
{
	var p = BwUtil.getGlobalMousePosition (event);
	
	
	var x1 = this.offsetLeft;
	var y1 = this.offsetTop;
	
	var br = this.titlebar_bottom_right;
	var x2 = BwUtil.getElementLeftPosition (br);
	var y2 = BwUtil.getElementTopPosition (br) + br.offsetHeight;
	
	if (p.x < x1 || p.x > x2 || p.y < y1 || p.y > y2) return true;
	
	this.lastX = p.x - x1;
	this.lastY = p.y - y1;
	
	var _this = this;
	this.onmousemove=function(e){_this.mouseMoved(e);};
	this.setCapture();
	
	return false;
};

BwWindow.mouseReleased = function (event)
{
	this.onmousemove = null;
	this.releaseCapture();
	
	return false;
};

BwWindow.mouseMoved = function (event)
{
	var p = BwUtil.getGlobalMousePosition (event);
	
	p.x -= this.lastX;
	p.y -= this.lastY;
	
	if (p.x < 0) p.x = 0;
	if (p.y < 0) p.y = 0;
	
	var dx = p.x - this.offsetLeft;
	var dy = p.y - this.offsetTop;
	
	var dis = Math.sqrt ((dx * dx) + (dy * dy));
	if (dis > 8)
	{
		this.style.top = p.y + 'px';
		this.style.left =  p.x + 'px';
	}
};

function BwXml() { }

BwXml.pathCache = new Object();

BwXml.compilePath = function (path)
{
	var code = "var n=r;";
	var start = 0;
	var end = false;
	
	while (!end)
	{
		var stop = path.indexOf('/', start);
		if (stop == -1) {
			stop = path.length;
			end = true;
		}
		
		var e = path.substring (start, stop);

		var a = null;
		var p = e.indexOf ('@');
		if (p != -1) {
			a = e.substring (p+1, e.length);
			e = e.substring (0, p);
		}

		var i = 0;
		var bo = e.indexOf ('[');
		if (bo != -1) 
		{
			var bc = e.indexOf (']', bo);
			if (bc != -1)
			{
				i = e.substring (bo+1,bc);
				e = e.substring (0,bo);
			}
		}
		
		if (e != "" || i != 0) {
			code=code+("n=BwXml.el(n,'"+e+"',"+i+",c);");
		}
		
		if (a != null && end) {
			code=code+("n=BwXml.at(n,'"+a+"',c);");
		}

		start=stop+1;
	}
	
	return new Function("r","c",code+"return n;");
};

BwXml.navigate = function (path, root, create)
{
	var c = BwXml.pathCache[path];
	if (!c || c == null) {
		c = BwXml.compilePath (path);
		BwXml.pathCache[path] = c;
	}
	return c(root,create);
};

BwXml._arr = function (parent, name)
{
	var n = [];
	var i = 0;
	var c = parent.firstChild;
	while (c != null)
	{
		if (c.nodeType == 1 && c.nodeName == name) {
			n[i++] = c;
		}
		c = c.nextSibling;
	}
	return n;
};

BwXml.el = function (node, name, index, create)
{
	if (node == null) return null;
	if (name == '.' || name == '') return node;
	
	var nodes = BwXml._arr (node, name);
	var l = nodes.length;
	
	if (index < l) return nodes[index];
	if (!create) return null;
	
	var gap = index - l + 1;
	var doc = node.ownerDocument;
	var n = null;
	for (var j = 0; j < gap; j++)
	{
		n = doc.createElement (name);
		node.appendChild (n);
	}
	
	return n;
};

BwXml.at = function (node, name, create)
{
	var a = node.getAttributeNode (name);
	if (a != null || (a == null && !create)) {
		return a;
	}
	node.setAttribute (name, "");
	return node.getAttributeNode (name);
};

BwXml.getNodes = function (node, path)
{
	var a = [];
	var n = BwXml.navigate (path, node, false);
	var c = n;
	while (c != null)
	{
		if (c.nodeName == n.nodeName) {
			a.push (c);
		}
		c = c.nextSibling;
	}
	
	return a;
};

BwXml.getNode = function (node, path, create)
{
	return BwXml.navigate (path, node, create);
};

BwXml.get = function (node, path)
{
	var n = BwXml.navigate (path, node, false);
	return (n == null) ? null : BwXml.getNodeValue(n);
};

BwXml.put = function (node, path, value)
{
	var n = BwXml.navigate (path, node, true);
	BwXml.setNodeValue (n, value);
	return n;
};

BwXml.getNodeValue = function (node)
{
	var c = node.childNodes;
	var l = c.length;
	var v = "";
	for (var i = 0; i < l; i++)
	{
		var n = c[i];
		var t = n.nodeType;
		if (t == 3 || t == 4) {
			v += n.nodeValue;
		}
	}
	
	return v;
};

BwXml.setNodeValue = function (node, value)
{
	if (node.nodeType == 2)
	{
		node.value = value;
		return;
	}
	
	var c = node.childNodes;
	var l = c.length;
	for (var i = 0; i < l; i++)
	{
		var n = c[i];
		if (n.nodeType == 3)
		{
			if (value != null) n.data = value;
			else node.removeChild (n);
			return;
		}
	}
	
	if (value != null)
	{
		var f = node.firstChild;
		var t = node.ownerDocument.createTextNode (value);
		if (f == null) {
			node.appendChild (t);
		} else {
			node.insertBefore (t, f);
		}
	}
};

BwXml.createDocument = function (name)
{
	var i = document.implementation;
	var d = (i.createDocument) ? i.createDocument ("","",null) : new ActiveXObject ("MSXML.DOMDocument");

	return d;
};

/*
BwXml.removeNode = function (node)
{
	var n = node;
	if (n.nodeType == 2) {
		n.ownerElement.removeAttributeNode (n);
	} else {
		n.parentNode.removeChild (n);
	}
	return n;
};
*/

BwXml.importNode = function (dom, node, deep)
{
	var n;

	if (node.nodeType == 1)
	{
		n = dom.createElement (node.nodeName);
		for (var i = 0; i < node.attributes.length; i++)
		{
			var attr = node.attributes[i];
			if (attr.nodeValue != null && attr.nodeValue != '')
			{
				n.setAttribute (attr.name, attr.nodeValue);
			}
		}
		
	}
	else if (node.nodeType == 3)
	{
		n = dom.createTextNode (node.nodeValue);
	}

	if (deep && node.hasChildNodes())
	{
		for (var i = 0; i < node.childNodes.length; i++) 
		{
			n.appendChild (BwXml.importNode (dom, node.childNodes[i], true));
		}
	}

	return n;
};

BwXml.nextHomonym = function (node)
{
	var n = node;
	while ((n = n.nextSibling) != null) {
		if (n.nodeType == node.nodeType && n.nodeName == node.nodeName) break;
	}
	return n;
};

BwXml.insertAfter = function (parent, refChild, newChild)
{
	var n = refChild.nextSibling;
	(n == null) ? parent.appendChild (newChild) : parent.insertBefore (newChild, n);
};

if (navigator.product == "Gecko")
{
	var BwCapturedEvents = ["click","mousedown","mouseup","mousemove","mouseover","mouseout" ];
	
	HTMLElement.prototype.setCapture = function()
	{
		if (this._capture != null) this.releaseCapture();
		
		var _this = this;
		this._capture = function (e)
		{
			e.preventDefault();
			e.stopPropagation();
			var f = _this['on'+e.type];
			if (f) f.call (_this, e);
		};
		
		var c = BwCapturedEvents;
		var l = c.length;
		for (var i = 0; i < l; i++)
		{
			window.addEventListener (c[i], this._capture, true);
			window.captureEvents (Event[c[i]]);
		}
	};

	HTMLElement.prototype.releaseCapture = function()
	{
		var c = BwCapturedEvents;
		var l = c.length;
		for (var i = 0; i < l; i++)
		{
			window.releaseEvents (Event[c[i]]);
			window.removeEventListener (c[i], this._capture, true);
		}
		this._capture = null;
	};
}

