//Copyright Garwin sprl
//garwin.events.js version 2.5 13-10-2008 used to be called modsevents.js
//SEE My Document/_ref/JavaScript Events.doc
////////////////////////////////////////////////////////////////////////////////////////////////////////
//source:http://www.scottandrew.com/weblog/jsjunk#events" //fails silently in IE5/Mac
//source:http://phrogz.net/JS/AttachEvent_js.txt
//------- Constructor -------//
var _Garwin_Events = function (){
	this.Type = "Garwin.Events";
	this.EventCache = [];
}
_Garwin_Events.prototype = {
	AddEvents:function(obj, evTypes, fn) {
		for (i=0; i<evTypes.length; i++) this.AddEvent(obj, evTypes[i], fn);
	},
	AddEvent:function(obj, evType, fn, useCapture) {
		//alert('this.AddEvent obj.id='+obj.id+' evType='+evType+' fn='+fn+' useCapture='+useCapture);
		if (useCapture==undefined)
			useCapture=false;//Event bubbling default
	
		if(obj.addEventListener)//NN6+ AND FF
			obj.addEventListener(evType,fn,useCapture);
		else if(obj.attachEvent)//IE3+
			obj.attachEvent('on'+evType,fn);
		else // IE 5 Mac and some others
			obj['on'+evType] = this.FireCachedEvent(obj,evType);
		this.EventCache.push([obj, evType, fn, useCapture]);
	},
	RemoveEvent:function(obj, evType, fn, useCapture) {//GOOD TO REMOVE A SPECIFIC EVENT
		//alert('this.RemoveEvent obj.id='+obj.id+' evType='+evType+' fn='+fn+' useCapture='+useCapture);
		if(useCapture==undefined) 
			useCapture=false;
		
		if(obj.removeEventListener)//NN6+ AND FF
			obj.removeEventListener(evType, fn, useCapture);
		else if(obj.detachEvent) //IE3+
			obj.detachEvent('on' + evType, fn);
		else
			//obj['on'+evType] = null;//NO GOOD CAUSE REMOVES ALL EVENTS FROM OBJECT NOT JUST A SPECIFIC function (ANYWAY NOT NEEDED BECAUSE REMOVED FROM CACHE (this.EventCache) WITH CODE BELOW)
		for (var i = 0; i < this.EventCache.length; i++) 
   		{
			if(this.EventCache[i][0]==obj&&this.EventCache[i][1]==evType&&this.EventCache[i][2]==fn)
			{
				//alert("this.RemoveEvent="+this.EventCache[i][2]);
				if(this.EventCache.deleteindex)
				{
					//alert("this.EventCache.length="+this.EventCache.length);
					this.EventCache.deleteindex(i);
					//alert("this.EventCache.length="+this.EventCache.length);
				}
				break;
			}
		}
	},
////////////////////////////////////////////////////////////////
	//http://jibbering.com/faq/faq_notes/closures.html see Associating Functions with Object Instance Methods
	//This should be used only if the event handling functions ("methodName") needs reference to the event object ("e") AND the DOM object source of the event within the event handling function ("methodName"). 
	//Otherwise just use garwin.createDelegate straight away
	associateObjWithEvent:function(obj, methodName){
	    return (function(e){
	    	//"this" = object to which the event handler function has been assigned because the inner function is executed as a method of 
	    	//that object because it has been assigned as an event handler.
	    		    	
		//The event object that will have been parsed as the - e - parameter on DOM standard browsers is normalised to the IE
		//event object if it has not been passed as an argument to the event handling inner function:
	        e = e||window.event;
	        
 	        //In firefox the following is unnecessary because (this == sourceobj) they are the same given the current object context.
 	        //However in "ie" it is necessary because the Microsoft event registration model is that attachEvent()
 	        //creates a reference to the function and does not copy it.
 	        //for more details :D:\My Documents\_Ref Computer Knowlegde\Javascript\JavaScript Object-Oriented Programming-This Keyword.doc
		//normalising the event source/target dom object BY ME
	     	//var sourceobj;
		if (e.target) sourceobj = e.target;
		else if (e.srcElement) sourceobj = e.srcElement;
		if (sourceobj.nodeType == 3) // defeat Safari bug
			sourceobj = sourceobj.parentNode;

	        //return obj[methodName](e, this);   
	        return garwin.createDelegate(obj,obj[methodName])(e,sourceobj);//event function arguments =>(e, sourceobj)
	    });
	},
	FireCachedEvent:function(obj,evType){
		var _this = this;
		return(function(e){
			for(var i=0;i<_this.EventCache.length;i++){	
				if(_this.EventCache[i][0]==obj&&_this.EventCache[i][1]==evType){
					_this.EventCache[i][2]();
					//alert("this.FireCachedEvent----->"+_this.EventCache[i][2]);
				}
			}
		});
	},
////////////////////////////////////////////////////////
//The following handles IE memory leaks with closures 
//http://jibbering.com/faq/faq_notes/closures.html#clMem
//http://www.bazon.net/mishoo/articles.epl?art_id=824
//http://localhost/_JS_GENERAL/modsevents2IeMemoryLeak.htm
//"using IE's onunload event to null event handling function references"
	unloadHandlers:function(){
		if(navigator.userAgent.toLowerCase().indexOf('msie') == -1)//Only memory leaks with Ie
			return(function(e){});
		var _this = this;
		return(function(e){
			for (var i = _this.EventCache.length-1; i > -1; i--) 
   			{
				//alert("this.Unload _this.EventCache["+i+"][0]="+_this.EventCache[i][0].id);
				//alert("this.Unload _this.EventCache["+i+"][1]="+_this.EventCache[i][1]);
				//alert("this.Unload _this.EventCache["+i+"][2]="+_this.EventCache[i][2]);
		
				(_this.EventCache[i][0]).detachEvent('on'+_this.EventCache[i][1],_this.EventCache[i][2]);
				(_this.EventCache[i][0])['on'+_this.EventCache[i][1]] = null;
		
      				//_this.RemoveEvent.apply(_this, _this.EventCache[i]);//WORKS but this.RemoveEvent is to slow compared to the above way; using straight away detachEvent and setting object event to null
      				//_this.EventCache[i][0] = null;//is this really needed, do we have to make the object null??????? just the event should be set to null
    			}
    			_this.EventCache = null;//here used to this.EventCache = false;
    		});
	},
////////////////////////////////////////////////////////////////////////////////////////////////////////
//source:http://simonwillison.net/2004/May/26/addLoadEvent/ //PB with this:What if you want to remove one of the event handlers, but not the other?
	addEventBasic:function(obj, evType, fn) {
		var OldEvent = obj[evType];
		if (typeof OldEvent != 'function')
		{
			obj[evType] = fn;
		} 
		else
		{
			obj[evType] = 	function(e){
				OldEvent(e);
				fn(e);
			}
		 }
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
garwin.events = new _Garwin_Events;
////////////////////////////////////////////////////////////////////////////////////////////////////////
if(navigator.userAgent.toLowerCase().indexOf('msie') != -1)//Only memory leaks with Ie
	garwin.events.AddEvent(window,'unload',garwin.events.unloadHandlers(), false);
