function DOMEvent(oThis){
	this.listeners = [];
	this.oThis = oThis || false;
}
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.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;
			lnr.func.apply(obj, args);
			lnr.calls++;
			if(lnr.calls == lnr.callslimit){
				this.remove(lnr.name)
			}
		}.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.toString = function(){
	var str = "object DOMEvent\n";
	str += "\n";
	str += "Listeners: ";
	this.listeners.each(function(lnr){
		str += lnr.name + ", ";
	});
	var reg = new RegExp(", $");
	str = str.replace(reg, "");
	str += "\nListeners length: " + this.listeners.length;
	return str;
}
*/
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 = function(){
		return d_event.toString();
	}
	obj._EVENT_CLONE = true;
	return obj;
}
DOMEvent.createEventLink = function(obj, name){
	obj["_" + name] = new DOMEvent();
	obj[name] = function(){
		this["_" + name].fire();
	}
	DOMEvent.cloneEvent(obj["_" + name], obj[name]);
	obj[name].register = function(n, func, callslimit){
		func = func.bound ? func : func.bind(obj);
		obj["_" + name].register(n, func, callslimit);
	}
}
DOMEvent.linkObjects = function(elem, d_event, name){
	elem.d_event = d_event;
	elem[name] = function(){
		this.d_event.fire.apply(this.d_event, arguments);
	}
}
DOMEvent.createLinkedEvent = function(elem, name){
	var d_event = new DOMEvent();
	DOMEvent.linkObjects(elem, d_event, name);
	return d_event;
}

function MajorDOMEvent(name){
	this.name = name ? name : "major_dom_event";
	this.listeners = [];
}
MajorDOMEvent.prototype.register = DOMEvent.prototype.register;
MajorDOMEvent.prototype.remove = DOMEvent.prototype.remove;
MajorDOMEvent.prototype.hasNamedListener = DOMEvent.prototype.hasNamedListener;
MajorDOMEvent.prototype.length = DOMEvent.prototype.length;
MajorDOMEvent.prototype._link = function(d_event, arg){
	d_event.register(this.name, function(){
		this.listeners.each(function(lnr){
			lnr.func(arg);
		}.bind(this))
	}.bind(this))
}
MajorDOMEvent.cloneEvent = function(m_d_event){
	var obj = {};
	obj.register = function(name, lnr, callslimit){
		m_d_event.register(name, lnr, callslimit)
	}
	obj.remove = function(name){
		m_d_event.remove(name)
	}
	obj.length = function(){
		return m_d_event.length();
	}
	obj.hasNamedListener = function(name){
		return m_d_event.hasNamedListener(name);
	}
	obj._link = function(d_event, arg){
		m_d_event._link(d_event, arg);
	}
	return obj;
}
