
(function(){
	var NS = namespace = {};
	
	var EVENTS = NS.events = {};
	//eventify - make an object event ready
	var eventify = EVENTS.eventify = function(target1, targetN){
		for(var t=0; t<arguments.length; t++){
			var target = arguments[t];
			if(!target.__listeners){
				if(!target.events) target.events={};
				target.__listeners={};
				
				target.dispatchEvent=function(eventType, eventData){
					if(this.events[eventType]) this.events[eventType].dispatch(this, eventData);
				};
				target.addEventListener=function(eventType, callback, bubbles){
					return new EVENTS.Listener(this, eventType, callback, bubbles);
				};
				target.removeEventListener=function(eventType, callback){
					var listeners = this.__listeners[eventType];
					for(var l=0;listeners && l<listeners.length;l++)
						if(listeners[l]===callback || listeners[l].callback===callback) listeners.splice(l,1);
				};
			}
		}
	}
	
	//Event class
	var Event = EVENTS.Event = function(type){
		this.type=type;
		this.history=[];
	}			
	Event.prototype={
		bubbleTo:null,
		currentTarget:null,
		dispatch:function(target, eventData, currentTarget){
			this.target=target;							
			this.currentTarget=currentTarget||target;

			var timeStamp = new Date();
			this.timeStamp = timeStamp;				
			this._stopProp=false;
			
			if(!currentTarget){
				var histObj = {
					eventData:eventData,
					timeStamp:timeStamp					
				};
			}else{
				var histObj = currentTarget.events[this.type].history[currentTarget.events[this.type].history.length-1];
			}
			histObj.target = target;
			histObj.currentTarget=currentTarget||target;
			
			this.history.push(histObj);
			
			var listeners = target.__listeners[this.type],
				result;
			for(var l=0; listeners && l<listeners.length; l++){
				var listener = listeners[l];					
				if(eventData) result = listener.callback.call(target, this, eventData);
				else result = listener.callback.call(target, this);
				if(typeof(result)!=="undefined" && result!==null) this.result=result;
				if(this._stopImmProp) break;
			}	
			if(this.bubbleTo!==null && !this._stopProp) this.bubbleTo.events[this.type].dispatch(this.bubbleTo, eventData, this.currentTarget);
			
		},
		result:true,
		_stopImmProp:false,
		stopImmediatePropagation:function(){this._stopImmProp=true},
		_stopProp:false,
		stopPropagation:function(){this._stopProp=true},		
		target:null,
		type:null,
		history:null
	}
		
	//Listener class
	var Listener = EVENTS.Listener = function(target, eventType, callback, bubbles){
		this.target = target;
		this.callback = callback;			
		this.bubbles = (bubbles!==null) ? bubbles : true;
		//add the event to the target if it doesn't exist
		if(!target.events[eventType]) target.events[eventType] = this.event = new EVENTS.Event(eventType);
		this.event = target.events[eventType];			
		//create the listeners collection for this event type
		if(!target.__listeners[eventType]) target.__listeners[eventType]=[];			
		target.__listeners[eventType].push(this);
	}
	Listener.prototype={
		bubbles:true,
		callback:function(evt, data){},
		remove:function(){
			var idx = Array.indexOf(this.target.__listeners[this.event.type], this);
			this.target.__listeners[this.event.type].splice(idx,1);
			delete this;
		},		
		event:null,
		target:null
	}
		
		
	/*
	var grandchild = {events:{hello:new EVENTS.Event("hello")},name:"grandchild"},
		parent = {events:{hello:new EVENTS.Event("hello")},name:"parent"},
		grandparent = {events:{hello:new EVENTS.Event("hello")},name:"grandparent"};
	EVENTS.eventify(grandchild,parent,grandparent);
	
	function lstnr(evt){
		console.log(evt.target.name+"/"+evt.currentTarget.name);
		if(this.name==="parent") evt.stopPropagation();
	}
	//grandchild.addEventListener("hello", lstnr);
	grandchild.events.hello.bubbleTo=parent;
	parent.addEventListener("hello", lstnr);
	parent.events.hello.bubbleTo=grandparent;
	grandparent.addEventListener("hello", lstnr);
	
	
	grandchild.dispatchEvent("hello");
	grandchild.removeEventListener("hello", lstnr);
	console.dir(grandchild);
	console.dir(parent);
	console.dir(grandparent);
	*/
	

})();