function widget()   
{ 
	// -----------------------------------------------------------
	this.tagName = function(obj)
	{
		if (!(obj instanceof jQuery)) 
			return obj.tagName;

		var ctype = null;
		obj.each(function() { 
			if (ctype == null) 
				ctype = this.tagName.toLowerCase(); 
		});
		return ctype;
	}
	// -----------------------------------------------------------
	this.open = function(obj)
	{
		alert("WIDGET OPEN");
	}
	// -----------------------------------------------------------
	this.close = function(obj)
	{
		alert("WIDGET CLOSE");
	}
	// -----------------------------------------------------------
	this.submitForm = function(obj, callback)
	{
		if (!(obj instanceof jQuery)) obj = this.getWidget(obj);
		if (this.tagName(obj) != 'form') obj = obj.find('form');
		$.post(obj.attr('action'), this.formToData(obj), callback, 'json');
	}
	// -----------------------------------------------------------
	this.dataToForm = function(obj, data)
	{
		if (data == undefined) return;

		for (var name in data) {
			//$(":input[name='" + name + "']", obj).setValue(data[name]);
			$("input[name=" + name + "]", obj).setValue(data[name]);
		}
	}
	// -----------------------------------------------------------
	this.formToData = function(obj)
	{
		var data = obj.formHash();
		data.ajax = true;

		return data;
	}
	// --------------------------------------------------------------
	this.dataToView = function(obj, data)
	{
		if (data == undefined) return;

		for (var label in data) {
			if (label == undefined) continue;
			$("." + label, obj).html(data[label]);
		} 
		return data;
	}
	// --------------------------------------------------------------
	this.viewToData = function(obj, data)
	{
		for (name in data) {
			svalue = '' + data[name];
			dvalue = $('.' + name, obj).html();
			if (svalue.substr(0,1) == '>') 
				data[svalue.substr(1)] = dvalue;
			else if (svalue == '') data[name] = dvalue;
		}
		return data;
	}
	// --------------------------------------------------------------
	this.filterData = function(data, filter)
	{
		for (name in filter) {
			fvalue = filter[name];
			if (fvalue.substr(0,1) == '>')
				filter[fvalue.substr(1)] = data[name];
			else if (fvalue == '') filter[name] = data[name];
		}
		return filter;
	}
	// -----------------------------------------------------------
	this.widgetType = function(obj)
	{
		var ctype = this.tagName(obj);
		if (ctype == 'ul') return 'li';
		if (ctype == 'table') return 'tr';

		return 'div';
	}
	// -----------------------------------------------------------
	this.getWidget = function(obj, name)
	{
		var cname = (name == undefined) ? this.widgetName : name;
		var widget = null;

		$(obj).parents().andSelf().each(function() {
			if ($(this).hasClass(cname)
				&& $(this).hasClass('widget')
				&& (widget == null)) {
				widget = $(this);
			}
		});
		return widget;
	}
	// -----------------------------------------------------------	
	this.makeWidget = function(tag)
	{
		widget_id++;
		oNew = $(
			'<' + tag + ' id="widget_' + widget_id.toString() + 
			'" class="widget ' + this.widgetName + '" style="display: none;">' + 
			this.template + '</' + tag + '>'
		);
		return oNew;
	}
	// -----------------------------------------------------------	
	//	'container' will contain the widget, and can be specified by:
	//	1. '#elementID' = container for the widget.
	//	2. jQueryObj = container for the widget.
	//	3. domNode (this) = used with 'type' to find parent container
	//	
	//	'type' is used with DOMptr to find a parent container.
	//	If a type is not specified, the first parent container that
	//	is a widget will be used. Otherwise, type should be a class
	//	name or any valid jQuery parent(selector).
	//
	//	Examples: 
	//
	//		newWidget('#listBox');
	//		newWidget(this, '.widget');
	//
	// -----------------------------------------------------------	
	this.newWidget = function(container, type, position)
	{
		if (!(container instanceof jQuery)) {
			if (typeof container == 'string') {
				container = $(container);
			} else {
				if (type == undefined) type = '.widget';
				container = $(container).parents(type).eq(0);
			}
		}
		tag = this.widgetType(container);
		oNew = this.makeWidget(tag);
		
		if (position == undefined) position = 'append';
		switch (position) {
			case 'before':
				oNew.insertBefore(container);
				break;
			case 'after':
				oNew.insertAfter(container);
			case 'append':
				oNew.appendTo(container);
				break;
			case 'prepend':
			default:
				oNew.prependTo(container);
		}
		return oNew;
	}
	// -----------------------------------------------------------
	this.subFormOpen = function(obj, data, view, subview)
	{
		var oEdit = this.newWidget(obj);
		var oView = this.getWidget(obj, view);

		this.dataToForm(oEdit, this.viewToData(oView, data));
		if (subview != undefined) oView.find(subview).hide();
		oEdit.show();

		return false;
	}
	// -----------------------------------------------------------
	this.subFormClose = function(obj, filter, view, subview, message)
	{
		oEdit = this.getWidget(obj);
		oView = this.getWidget(obj, view);
		oThis = this;

		if (message == undefined) message = 'Saving...';

		oEdit.find('.message').html(message);

		this.submitForm(obj, function(data) {
			if (data.errors != undefined) {
				oEdit.find('.message').html('Watch your language!');
			} else {
				filter = oThis.filterData(data.data, filter);
				oThis.dataToView(oView, filter);
				oEdit.remove();
				oView.find(subview).show();
			}
		});
		return false;
	}
	// -----------------------------------------------------------
}
