/**
 * This file contains the JavaScript Class for creating Drop Menu Widget for navigations
 *
 * This file contains a single JavaScript Class that provides the said 
 * functionality
 *
 * Language: JavaScript
 * Depenedancies: MooTools 1.1 Core
 * 				  utilities.js
 *
 * @package    	dropMenu
 * @author     	ProjectMiso.net <email@projectmiso.net>
 * @version    	1.0
 * @since      	September 2007
 * @deprecated 	N/A
 * @license		Developed by ProjectMiso for ProjectMiso's internal use only. This widget may be used for developing websites
 *				for ProjectMiso's clients. In that event, ProjectMiso grants license to the client for life time use of the 
 *				widget in the said website developed by ProjectMiso. ProjectMiso DOES NOT GRANT the Client or client's future 
 *				development teams the right of distribution or the right to use this widget on other websites created by the client. 
 * @copyright	Author
*/
 
/**
 * Features
 *	-- create a drop down
 *	-- size the drop down
 *	-- position the drop down

*/
/**
 * Public Methods
 *	-- Class.unload();		no arguments. this method is for garbage collection - will clear DOM and other objects from the memory if called on window.unload
*/


//function for creating drop down menus

var dropMenu = new Class({
	options: {
		moduleName: 		'dropMenu',	//the name of the module so it can be detected for debugging and garbage collection  - REQUIRED
		delay: 				200,		//closing delay for the menu - OPTIONAL
		showLog:			false
	},
	initialize: function(options){
		this.setOptions(options);				//set options if custom options are being supplied
		this.parseOptions(this.options);		//parse optionsand convert them into class properties
		
		this.EL = {}; 	//temporary store
	},
	/**
	 * This methd should be called to render a new drop down menu
	 * @options - options. This is an object with the following key-value pairs
	 * {
	 *		element: 			null,		//the ID of the source element - the trigger element  - REQUIRED
	 *		target: 			null,		//the ID of the dropdown element - the target element  - REQUIRED
	 *		where:				null,		//"bottom" or "right"  - OPTIONAL. "bottom" is default.
	 *		leftOffset:			null,		//the left offset number - OPTIONAL
	 *		topOffset:			null,		//the left top number - OPTIONAL
	 *		width:				null		//if the dropdown needs fixed width - OPTIONAL
	 *	}
	 */
	attach: function(options){
		var self = this;
		
		//get the main containers from the XHTML DOM
		var trigger = $(options.element); if (!trigger) {  this.log("ERR1: " + this.moduleName + " was aborted for element: '" + options.element + "'! Supplied 'element' value is not a valid ID."); return; }
		var target = $(options.target); if (!target) { this.log("ERR2: " + this.moduleName + " was aborted for element: '" + options.target + "'! Supplied 'element' value is not a valid ID."); return; }
		
		//set defaults
		if (!options.where || options.where == "") options.where = "bottom";
		if (!options.topOffset) options.topOffset = 0;
		if (!options.leftOffset) options.leftOffset = 0;
		
		//trigger enter event
		var triggerEnter = function(event){
			if (event) { var e = new Event(event); e.stopPropagation(); e.stop(); }
			var coords = this.getCoordinates();
			var t_coords = target.getCoordinates();
			
			self.log (self.moduleName + "::attach(): coords.top = " + coords.top);
			self.log (self.moduleName + "::attach(): t_coords.top = " + t_coords.top + ", t_coords.left = " + t_coords.left);
			self. log(self.moduleName + "::attach(): options.where = " + options.where);
			self. log(self.moduleName + "::attach(): target = " + target + ", target.id = " + target.id);
			
			if (options.where == "bottom"){
				target.setStyles({top: coords.top + coords.height + options.topOffset, left: coords.left + options.leftOffset});
			} else if (options.where == "top"){
				target.setStyles({top: coords.top - t_coords.height + options.topOffset, left: coords.left + options.leftOffset});
			} else if (options.where == "left"){
				target.setStyles({top: coords.top + options.topOffset, left: coords.left - t_coords.width + options.leftOffset});
			} else if (options.where == "right"){
				target.setStyles({top: coords.top + options.topOffset, left: coords.left + coords.width + options.leftOffset});
			}
			
			if (options.width){
				if ($type(options.width) == "number") {
					target.setStyle("width", options.width);
				} else {
					target.setStyle("width", coords.width);
				}
			}
			target.visible();
			target.closeNow = false;
		};
		trigger.addEvent("mouseenter", triggerEnter);
		
		PBUtil.garbage.store ('event', self.moduleName, trigger, 'mouseenter', triggerEnter); //store event for garbage collection
		
		//trigger leave event
		var triggerLeave = function(event){
			if (event) { var e = new Event(event); e.stopPropagation(); e.stop(); }
			target.closeNow = true;
			
			(function(){ 
				if (target.closeNow){
					target.invisible(); 
				}
			}).delay(self.delay);
		};
		trigger.addEvent("mouseleave", triggerLeave);
		PBUtil.garbage.store ('event', self.moduleName, trigger, 'mouseenter', triggerLeave); //store event for garbage collection
		
		var triggerClick = function(event){
			if (!target.closeNow){
				this.fireEvent('mouseleave');
			} else {
				this.fireEvent('mouseenter');
			}
		}
		trigger.addEvent("click", triggerClick);
		PBUtil.garbage.store ('event', self.moduleName, trigger, 'click', triggerClick); //store event for garbage collection
		
		//body leave event
		var bodyClick = function(event){	
			var e = new Event(event);
			if (!$defined(e.target.id)) { 
				target.invisible(); 
			} else {
				if(e.target.id != trigger.id) target.invisible(); 
			}
		};
		var docBody = $(document.body);
		$(document.body).addEvent("click", bodyClick);
		PBUtil.garbage.store ('event', self.moduleName, docBody, 'click', bodyClick); //store event for garbage collection
		docBody = null;
		
		//target enter event
		var targetEnter = function(event){
			var e = new Event(event); e.stopPropagation(); e.stop();
			this.closeNow = false;
		};
		target.addEvent("mouseenter", targetEnter);
		PBUtil.garbage.store ('event', self.moduleName, target, 'mouseenter', targetEnter); //store event for garbage collection
		
		//target leave event
		var targetLeave = function(event){
			var e = new Event(event); e.stopPropagation(); e.stop();
			this.closeNow = true;
			
			(function(){ 
				if (target.closeNow){
					target.invisible(); 
				}
			}).delay(self.delay);
		};
		target.addEvent("mouseleave", targetLeave);
		PBUtil.garbage.store ('event', self.moduleName, target, 'mouseenter', targetLeave); //store event for garbage collection
		
		//target enter event
		var tempLinks = target.getElements('a');
		if (tempLinks.length){
			var targetLinkEnter = function(event){
				target.invisible(); 
			};
			tempLinks.addEvent("click", targetLinkEnter);
			PBUtil.garbage.store ('event', self.moduleName, tempLinks, 'click', targetLinkEnter); //store event for garbage collection
		}
		
		//tempLinks = trigger = target = null;
		
	},
	parseOptions: function(optionsObj, ignoreUndefinedProps){
		if (!optionsObj){ return; } else {
			for (var optionName in optionsObj){
				if (ignoreUndefinedProps && optionsObj[optionName] == undefined){ continue; } else { this[optionName] = optionsObj[optionName]; }
			}
		}
	},
	unload: function(){
		var self = this;
		self.log("Executing the 'unload' method");
		
		//******** Unload local DOMs
		for (var key in this.EL){
			this.EL[key] = null;
		}
		
		//******* Unload global DOMs and EVENTs
		PBUtil.garbage.dispose ('all', self.moduleName)
		
		//***** Unload the class
		var moduleName = this.moduleName;
		for (var key in this){
			self.log(key + " --- " + $type(this[key]) + " --- " + this[key]);
			if ($type(this[key]) == 'object'){
				delete this[key];
				self.log("DELETED object: " + key );
			} else if ($type(this[key]) == 'string' || $type(this[key]) == 'number' || $type(this[key]) == 'collection' || $type(this[key]) == 'regexp' || $type(this[key]) == 'function'){
				if (key != 'log'){
					this[key] = null;
					delete this[key];
					self.log("DELETED: " + key );
				} 
			} else {
				self.log("****** NOT DELETED: " + key )	
			}
		}
		for (var key in this){
				self.log("DELETED Left Over: " + key  + " --- " + $type(this[key]) + " --- " + this[key]);
				this[key] = null;
				delete this[key];
		}
		
		this.log = null;
		PBUtil.log("Deleting the LOG method. Check: " + this.log);
		
		if (!window.ie) delete this;
		
		PBUtil.module[moduleName] = null;
		delete PBUtil.module[moduleName];
		
		PBUtil.log("Deleting the PBUtil store. Check: " + PBUtil.module[moduleName]);
		
		moduleName = null;
	},
	log: function(txt){
		if (window.console && this.showLog){
			window.console.log(txt);
		}
	}
});

// implementing the events and options
dropMenu.implement(new Events, new Options);

PBUtil.module.dropMenu = new dropMenu({delay: 100});
