BaseKit.Widget = function()
{
	if (arguments.length)
	{
		if (this == window)
		{
			BaseKit.Widget.prototype.extend.call(arguments[0], arguments.callee.prototype);
		}
		else
		{
			this.extend(arguments[0]);
		}
	}
};

BaseKit.Widget.prototype =
{
	extend: function(source, value)
	{
		var extend = BaseKit.Widget.prototype.extend;
		if (arguments.length == 2) {
			var ancestor = this[source];
			if ((ancestor instanceof Function) && (value instanceof Function) &&
				ancestor.valueOf() != value.valueOf() && /\bcallBase\b/.test(value)) {
				var method = value;
				value = function() {
					var previous = this.callBase;
					this.callBase = ancestor;
					var returnValue = method.apply(this, arguments);
					this.callBase = previous;
					return returnValue;
				};
				value.valueOf = function() {
					return method;
				};
				value.toString = function() {
					return String(method);
				};
			}
			return this[source] = value;
		} else if (source) {
			var _prototype = {toSource: null};
			var _protected = ['toString', 'valueOf'];
//			if (BaseKit.Widget._prototyping) _protected[2] = '__install';
			for (var i = 0; (name = _protected[i]); i++) {
				if (source[name] != _prototype[name]) {
					extend.call(this, name, source[name]);
				}
			}
			for (var name in source) {
				if (!_prototype[name]) {
					extend.call(this, name, source[name]);
				}
			}
		}
		return this;
	},

	callBase: function()
	{
	}
};

BaseKit.Widget.extend = function(_instance, _static)
{
	var extend = BaseKit.Widget.prototype.extend;
	if (!_instance) _instance = {};
	BaseKit.Widget._prototyping = true;
	var _prototype = new this;
	extend.call(_prototype, _instance);
	var __install = _prototype.__install;
	_prototype.__install = this;
	delete BaseKit.Widget._prototyping;
	var klass = function() {
		if (!BaseKit.Widget._prototyping) __install.apply(this, arguments);
		this.__install = klass;
	};
	klass.prototype = _prototype;
	klass.extend = this.extend;
	klass.implement = this.implement;
	klass.toString = function() {
		return String(__install);
	};
	extend.call(klass, _static);
	var object = __install ? klass : _prototype;
	if (object.init instanceof Function) object.init();
	return object;
};

BaseKit.Widget.implement = function(_interface)
{
	if (_interface instanceof Function) _interface = _interface.prototype;
	this.prototype.extend(_interface);
};

BaseKit.Widget.uninstall = function(id)
{
	for (var i = 0; i < BaseKit.Widget.__all.length; )
	{
		var widget = BaseKit.Widget.__all[i];

		if (widget.__id.substr(0, id.length).toLowerCase() == id.toLowerCase())
		{
			widget.destruct();
			delete widget;
			BaseKit.Widget.__all.splice(i, 1);
		}
		else
		{
			i++;
		}
	}

/*
	var widgets = $A(BaseKit.Widget.__all).collect(function(obj, index)
	{
		if (obj.__id.substr(0, id.length) == id)
		{
			return index;
		}

		throw $continue;
	});

	for (var i = 0, removed = 0; i < widgets.length; i++)
	{
		var widget = BaseKit.Widget.__all[widgets[i] - removed];
		widget.destruct();
		delete widget;
		BaseKit.Widget.__all.splice(widgets[i] - removed, 1);
		removed++;
	}
*/
};

BaseKit.Widget.exists = function(id)
{
	return $A(BaseKit.Widget.__all).detect(function(widget)
	{
		return (widget.getID() == id);
	});
};

BaseKit.Widget.getByID = function(id)
{
	var detected = $A(BaseKit.Widget.__all).detect(function(widget)
	{
		if (widget.getID() == id)
		{
			return widget;
		}
	});

	if (!detected)
	{
		alert('BaseKit Error!\n\nWidget ' + id + ' does not exist');
	}

	return detected;
};

BaseKit.Widget.__all = [];

BaseKit.Widget.Base = BaseKit.Widget.extend(
{
	__install: function(setup)
	{
		BaseKit.Widget.__all.push(this);

		this.__events = setup.events;
		this.__observing = [];

		for (var name in setup.events)
		{
			eval('if(!this.' + name + '){this.' + name + '=function(){if(this.__events.' + name + '){BaseKit.Core.callMulti(this.__events.' + name + ',this.onAsyncStart,this.onAsyncFinish);}}}');
		}

		setup.exports.each(function(name)
		{
			eval("if (!this." + name + "){this." + name + "=function(arg){BaseKit.Core.call(this.getID(),'" + name + "',arg,this.onAsyncStart,this.onAsyncFinish);}}");
		}.bind(this));

		for (var name in setup.properties)
		{
			this[name] = setup.properties[name];
		}

		this.construct();
	},

	onAsyncStart: function()
	{
	},

	onAsyncFinish: function()
	{
	},

	construct: function()
	{
	},

	destruct: function()
	{
		this.stopObservingAllEvents();
	},

	serialize: function()
	{
		return null;
	},

	getID: function(element)
	{
		if (element && element.length)
		{
			return this.__id + ':' + element.toLowerCase();
		}
		else
		{
			return this.__id;
		}
	},

	observeEvent: function(method, element, event, useCapture)
	{
		if (!element)
		{
			element = $(this.getID());
		}

		if (!event)
		{
			event = method.toLowerCase();
		}

		if (this[method])
		{
			var bind = this[method].bindAsEventListener(this);
			Event.observe(element, event, bind, useCapture);
			this.__observing.push({method:method, element:element, event:event, bind:bind});
		}
		else
		{
			alert('BaseKit Error!\n\nNo ' + method + ' method for ' + this.getID());
		}
	},

	startObservingEvent: function(method, element, event, useCapture)
	{
		this.observeEvent(method, element, event, useCapture);
	},

	stopObservingEvent: function(method, element, event)
	{
		var events = $A(this.__observing).collect(function(event, index)
		{
			if (event.method == method && event.element == element)
			{
				return index;
			}

			throw $continue;
		});

		for (var i = 0, stopped = 0; i < events.length; i++)
		{
			var event = this.__observing[events[i] - stopped];
			delete event;
			this.__observing.splice(events[i] - stopped, 1);
			stopped++;
		}
	},

	stopObservingAllEvents: function()
	{
		$A(this.__observing).each(function(temp)
		{
			Event.stopObserving(temp.element, temp.event, temp.bind);
		});

		this.__observing = [];
	}
});

$W = BaseKit.Widget.getByID;
