var $breakEvent;
function createBeforeEvent(oThis, f_name, name){
	var func = oThis[f_name];
	oThis['on' + name] = new DOMEvent(oThis);		
	oThis[f_name] = function(){
		try{
			oThis['on' + name].fire.apply(oThis['on' + name], $A(arguments));
			func.apply(oThis, $A(arguments));
			return true;
		}catch(e){
			if(e != $breakEvent){
				throw e;
			}
			return false;
		}
	}
}
function createAfterEvent(oThis, f_name, name){
	var func = oThis[f_name];
	oThis['on' + name] = new DOMEvent(oThis);
	oThis[f_name] = function(){
		func.apply(oThis, $A(arguments));
		oThis['on' + name].fire.apply(oThis['on' + name], $A(arguments));
		return true;
	}
}
function $Break(obj){
	if(typeof obj == "string"){
		this.message = obj;
	}else if(typeof obj == "object"){
		for(var i in obj){
			this[i] = obj[i];
		}
	}else{
		this.message = this._default_message;
	}
}
$Break.prototype.toString = __toString;
$Break.prototype.__name = "$Break";
$Break.prototype._default_message = "Sorry, event is broken";

function DOMEvent(oThis){
	this.listeners = [];
	this.oThis = oThis || false;
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
DOMEvent.prototype.register = function(name, lnr, callslimit, place){
	if(this.hasNamedListener(name)){
		return false;
	}
	var func = lnr.bound ? lnr : !this.oThis ? lnr : lnr.bind(this.oThis);
	var ev = {
		name: name,
		func: func,
		calls: 0,
		callslimit: callslimit ? callslimit : -1
	};
	if(typeof place != "undefined"){
		this.listeners.insert(ev, place);
	}else{
		this.listeners.push(ev);
	}
};
DOMEvent.prototype.register_c = function(name, lnr, callslimit){
	this.register(name, lnr, callslimit, 0);
};
DOMEvent.prototype.set_break = function(){
};
DOMEvent.prototype.remove = function(name){
	this.listeners.each(
		function(lnr, index){
			if(lnr.name == name){
				this.listeners.remove(index);
				throw $break;
			}
		}.bind(this)
	);	
}
DOMEvent.prototype.fire = function(){
	var args = arguments;
	this.listeners.each(
		function(lnr){
			var obj = lnr.func.bound ? lnr.func.bound[0] : this.defaultThis || lnr;
			var ret = lnr.func.apply(obj, args);
			lnr.calls++;
			if(lnr.calls == lnr.callslimit){
				this.remove(lnr.name);
			}
			if(!undefined(ret) && (ret === false || ret instanceof $Break)){
				this._break(ret);
				throw $breakEvent;
			}
		}.bind(this)
	);
}
DOMEvent.prototype.length = function(){
	return this.listeners.length;
}
DOMEvent.prototype.hasNamedListener = function(name, no_bool){
	var ret = false;
	this.listeners.each(
		function(lnr){
			if(lnr.name == name){
				ret = lnr;
				throw $break;
			}
		}
	);
	return !no_bool ? !!(ret) : ret;
}
DOMEvent.prototype.get = function(name){
	return this.hasNamedListener(name, true);
};
DOMEvent.prototype._listeners = function(){
	var str = "";
	this.listeners.each(function(lnr){
		str += " " + lnr.name + " ::";
	})
	return str.replace(/::$/, "");
}
DOMEvent.prototype.__name = "DOMEvent";
DOMEvent.prototype.toString = __toString;
DOMEvent.cloneEvent = function(d_event, oThis){
	var obj = {};
	obj.oThis = typeof oThis == "undefined" ? null : oThis;
	obj.register = function(name, lnr, callslimit, place){
		var func = lnr.bound ? lnr : this.oThis != null ? lnr.bind(this.oThis) : lnr;
		d_event.register(name, func, callslimit, place);
	}
	obj.remove = function(name){
		d_event.remove(name)
	}
	obj.length = function(){
		return d_event.length();
	}
	obj.hasNamedListener = function(name){
		return d_event.hasNamedListener(name);
	}
	obj.get = function(name){
		return d_event.get(name);
	}
	obj.eachLnr = function(iterator){
		d_event.eachLnr(iterator);
	}
	obj.toString = __toString;
	obj.__name = "DOMEvent - cloned";
	obj._listeners = function(){
		return d_event._listeners();
	}
	obj._EVENT_CLONE = true;
	return obj;
}
DOMEvent.prototype._break = _eF;
DOMEvent.prototype.set_break = function(func){
	this._break = func;
};
function E_Connection(oThis){
	this.name = "e-connection";
	this.oThis = oThis;
	this.listeners = [];
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
E_Connection.prototype.register = DOMEvent.prototype.register;
E_Connection.prototype.remove = DOMEvent.prototype.remove;
E_Connection.prototype.hasNamedListener = DOMEvent.prototype.hasNamedListener;
E_Connection.prototype.length = DOMEvent.prototype.length;
E_Connection.prototype.add = function(d_event, args){
	d_event.register(this.name, function(){
		this.listeners.each(function(lnr){
			lnr.func.apply(lnr.func.bound, args);
		}.bind(this))
	}.bind(this));
}

function _initEvents(){
	this._events.each(function(obj){
		createEvent(this, obj.func_name, obj.name);
	}.bind(this));
}