/** 
  *  Support for all javascript extensions.
  */


// -- GARBAGE COLLECTOR -- 

/** 
  * Implementation of garbage collector. Collects DOM 
  * references and releases it on before unload. 
  * 
  */
  
function Garbage() 
{ 
}

/** 
  * Initialise garbage collections of data to be destroyed 
  */
Garbage.init = function() 
{
	if (!window._OBJECTS_)  {
		
		// create storage array 
		window._OBJECTS_ = []; 
		window._FUNCTIONS_ = []; 
		window._EVENTS_ = []; 
		window._CLASSES_ = []; 
	}
}

/** 
  * Called before unload. Goes through all reference 
  * arrays and releases DOM elements. 
  */
Garbage.release = function() 
{
	if (!window._OBJECTS_) 
		return false; 
	
	// release events first. 
	Garbage.release_events(); 
	
	// release objects 
	for (var index in window._OBJECTS_) {
		var element = window._OBJECTS_[index]; 
		
		if (typeof element == "function") 
			continue; 
		
		window._OBJECTS_[index] = null; 
	}
	
	window._OBJECTS_ = null; 
	
	// delete all functions as well 
	for (var index in window._FUNCTIONS_) { 
		var funct = window._FUNCTIONS_[index]; 
		
		funct = null; 
	} 
	
	window._FUNCTIONS_ = null
	
	// call unload 
	for (var index in window._CLASSES_) {
		var cls = window._CLASSES_[index]; 

		if (cls.dispose)
			cls.dispose(); 
			
		window._CLASSES_[index] = null; 
	}
	
	window._CLASSES_ = null; 
	
	return true; 
}

/** 
  * Detaches all events installed using event_install 
  * function. 
  */
Garbage.release_events = function () 
{
	var events = window._EVENTS_; 

	for (var i = 0; i < events.length; i++) { 
		var event = events[i]; 

		detach_event(event[0],event[1],event[2]); 
	}
	
	window._EVENTS_ = null; 
}

/** 
  * Picks up an event to be released on before unload 
  * @argument DOM element event has to be attached to 
  * @argument name of the event i.e. onclick etc.. 
  * @argumetn f function to action on event 
  */
Garbage.push_event = function(obj, event, f) 
{ 
	// init storage arrays 
	Garbage.init(); 

	var length = window._EVENTS_.length; 
	window._EVENTS_[length] = [obj,event,f]; 
}

/** 
  * Collect garbage information about a single object 
  * specified in arguments. 
  */
Garbage.collect = function(obj) {
	
	// initialise garbage 
	Garbage.init(); 
	
	var func = this; 
	
	// populate objects array 
	var object_id = obj._OBJID; 
	if (!object_id) {
		// object id is the last item in the objects array 
		object_id = obj_OBJID = window._OBJECTS_.length;
		window._OBJECTS_ [object_id] = obj; 
	}
	
	// do the same stuff for functions 
	var funct_id = func._FUNCID; 
	if (!funct_id) {
		funct_id = func._FUNCID = window._FUNCTIONS_.length; 
		window._FUNCTIONS_[funct_id] = obj._FUNCT = func; 
	}

	if (!obj._CLOSURES) 	
		obj._CLOSURES = []; 
	
	var closure = obj._CLOSURES[funct_id]; 
	if (closure) 
		return closure; 
		
	// release 
	obj = func = null; 
	
	// Create the closure, store in cache and return result.
	return window._OBJECTS_[object_id]._CLOSURES[funct_id] = function() {
		// page unloaded 
		if (!window._FUNCTIONS_) 
			return; 
			
		return window._FUNCTIONS_[funct_id].apply(window._OBJECTS_[object_id], arguments);
	};	
}


// assign closure function to garbage collector
Function.prototype.garbage = Garbage.collect;	

/** 
  * Function for attaching events to a
  * DOM element. 
  */
function event_install(obj,event_name,f){

	if (obj.addEventListener){	//W3C
		obj.addEventListener(event_name.substr(2), f.garbage(obj),false);
	}else if (obj.attachEvent){	 //IE 
		obj.attachEvent(event_name,f.garbage(obj));
	}
	
	Garbage.push_event(obj, event_name, f); 
}

/** 
  * Detach event from the DOM object 
  */
function detach_event(obj,event_name, f){

	if (obj.removeEventListener) { 
		obj.removeEventListener(event_name.substr(2), f,false);
	} else if (obj.detachEvent) { 
		obj.detachEvent(event_name, f.garbage(obj)); 

	}
}

/** 
  * Extension to custom classes which will implement dispose 
  * method. This allows classes clean their data from memory before page is unloaded
  * 
  * Note that calls will be static 
  * 
  * @argument name of the class
  */
function IMPLEMENT_GARBAGE(f) {
	Garbage.init(); 
	window._CLASSES_[ window._CLASSES_.length ] = f; 
}

event_install(window,"onunload",Garbage.release); 
