// JavaScript Document
/**
 * Declare some global objects needed for sitewide operation
 */

//the 'PBUtil' object will make global references more standardized
var PBUtil = {
	module: {},					//object to store module instances
	globalModules: ['Lightbox', 'dropMenu', 'stretchLayout'],	//the global modules that should not be unloaded with just page content
	garbage: {					//object to store DOM and EVENTS for garbage collection and realted functions
		storage: {}
	}
};

/**
 * These are URL values sent to the server to specify which modules should be loaded at the front-end 
 * using the iframe that is responsible for loading content and initiating JS modules
 */
PBUtil.URLloader = {};
PBUtil.URLloader.gallery = "load=event_gallery";
PBUtil.URLloader.soloImage = "load=event_gallery";
PBUtil.URLloader.slideShow = "load=event_gallery";
PBUtil.URLloader.magnify = "load=event_gallery";
PBUtil.URLloader.leftCompare = "load=event_gallery";
PBUtil.URLloader.rightCompare = "load=event_gallery";

/* ======================================================*/
/*  			Garbage Management & Collection 		 */
/* ======================================================*/

/**
 * Function to store DOM elements and events for garbage collection.
 * This function is used in the JS module to store DOMs so they can be disposed when
 * modules' "unload" methods are called, when window reloads or when 
 * the PBUtil.garbage.unloadModule methos is called.
 *
 * This method is Private - DO NOT CALL this method from your JS, if unless used in the right
 * context
 *
 * @scope		Private
 *
 * @params 		type 		String, Required. 'event' or 'dom'.
 * @params		scope 		String, Required. Scope name - i.e. the module name
 * @params		el			DOM Element, Required. The target for event or the DOM itself
 * @params		eventType	String, Required. Event type - 'click', 'mouseover', etc.
 * @params		functionName pass the function being added as the event action
 */
PBUtil.garbage.store = function(type, scope, el, eventType, functionName){
	if (!PBUtil.garbage.storage[scope]){
		PBUtil.garbage.storage[scope] = {};
		PBUtil.garbage.storage[scope].DOM = [];
		PBUtil.garbage.storage[scope].EVENT = [];
	}
	
	//handle DOM
	if (type == 'dom'){
		var domLength = PBUtil.garbage.storage[scope].DOM.length;
		PBUtil.garbage.storage[scope].DOM[domLength] = el;
	
	
	//handle EVENTS
	} else if (type == 'event'){
		//PBUtil.log("Storing EVENT. EL: " + el + ", eventType: " + eventType +", function: "+ functionName);
		var eventLength = PBUtil.garbage.storage[scope].EVENT.length;
		PBUtil.garbage.storage[scope].EVENT[eventLength] = {};
		PBUtil.garbage.storage[scope].EVENT[eventLength].el = el;
		PBUtil.garbage.storage[scope].EVENT[eventLength].eventType = eventType;
		PBUtil.garbage.storage[scope].EVENT[eventLength].functionName = functionName;
	}
	
};
/**
 * Function to collect (dispose) DOM elements and events for garbage collection.
 * This method is used by JS modules for garbage collection. 
 *
 * This method is Private - DO NOT CALL this method from your JS, if unless used in the right
 * context
 *
 * @scope		Private
 *
 * @params 		type 		String, Required. 'event', 'dom' or 'all'.
 * @params		scope 		String, Required. Scope name - i.e. the module name
 */
PBUtil.garbage.dispose = function(type, scope){
	PBUtil.log("Start disposing for Scope: " + scope);
	if (!$defined(PBUtil.garbage.storage[scope])) return;
	
	//handle EVENTs
	if (type == 'event' || type == 'all'){
		if ($defined(PBUtil.garbage.storage[scope].EVENT)){
			for (var i=0;i<PBUtil.garbage.storage[scope].EVENT.length;i++){
				PBUtil.log("Disposing EVENT. Scope: " + scope + ", EL: " + PBUtil.garbage.storage[scope].EVENT[i].el.id + ", EVENTS: " + PBUtil.garbage.storage[scope].EVENT[i].eventType + ", Function: " + PBUtil.garbage.storage[scope].EVENT[i].functionName);
				PBUtil.garbage.storage[scope].EVENT[i].el.removeEvent(PBUtil.garbage.storage[scope].EVENT[i].eventType, PBUtil.garbage.storage[scope].EVENT[i].functionName)
			}
			PBUtil.garbage.storage[scope].EVENT = null;
		}
	}
	
	//handle DOMs
	if (type == 'dom' || type == 'all'){
		if ($defined(PBUtil.garbage.storage[scope].DOM)){
			if (PBUtil.garbage.storage[scope].DOM){
				for (var i=0;i<PBUtil.garbage.storage[scope].DOM.length;i++){
					PBUtil.log("Disposing DOM. Scope: " + scope + ", EL: " + PBUtil.garbage.storage[scope].DOM[i]);
					if (PBUtil.garbage.storage[scope].DOM[i] != window) PBUtil.garbage.storage[scope].DOM[i] = null;
				}
				PBUtil.garbage.storage[scope].DOM = null;
			}
		}
	}
	
	if (type == 'all'){
		delete PBUtil.garbage.storage[scope];
		//PBUtil.log("Disposing the Scope: " + scope + ", Check Value: " + PBUtil.garbage.storage[scope]);
	}

};
/**
 * Function to collect (dispose) DOM elements and events for garbage collection
 *
 * This method is Public - you can call this method anytime to unload the memory
 * of a local module (i.e. gallery, slideshow, etc.)
 * To unload all memory supply scope='all', otherwise supply 'local' or leave empty.
 *
 * @scope		Public
 *
 * @params		scope 		String, Required. 'all', 'local' or specific module name i.e. 'eventGallery'. Default is 'local'.
 */
PBUtil.garbage.unloadModule = function(scope){
	if (!$defined(scope)) scope = 'local';
	
	if (scope == 'local') {
		//skip the global modules
		for(var key in PBUtil.module){
			if (!PBUtil.globalModules.contains(key) && PBUtil.module[key]){
				PBUtil.module[key].unload();
				PBUtil.module[key] = null;
			}
		}
	} else if (scope == 'all') {
		for(var key in PBUtil.module){
			if (PBUtil.module[key]){
				PBUtil.module[key].unload();
				PBUtil.module[key] = null;
			}
		}
	} else {
		if (PBUtil.module[scope]){
			PBUtil.module[scope].unload();
			PBUtil.module[scope] = null;
		}
	}
}


/* ======================================================*/
/*  					Extending Natives				 */
/* ======================================================*/

/**
 * Extending the Element class. Following code extends mootools' functionality
 * to add additional DOM features.
 */
Element.extend({
	/**
	 * This method will return the inner width or height - considering margin and padding
	 */
	getInnerDimension: function(side){
		
		var coords = this.getCoordinates(), val = {}, innerSpace;
		
		if (!side || side == 'width'){
			innerSpace = coords.width ;//- this.getStyle('margin-left').toInt() - this.getStyle('margin-right').toInt();
			innerSpace -= this.getStyle('padding-left').toInt() + this.getStyle('padding-right').toInt();
			//innerSpace -= this.getStyle('border-left-width').toInt() + this.getStyle('border-right-width').toInt();
			
			val.width = innerSpace;
		}
		
		if (!side || side == 'height'){
			innerSpace = 0;
			innerSpace = coords.height ;//- this.getStyle('margin-top').toInt() - this.getStyle('margin-bottom').toInt();
			innerSpace -= this.getStyle('padding-top').toInt() + this.getStyle('padding-bottom').toInt();
			//innerSpace -= this.getStyle('border-top-width').toInt() + this.getStyle('border-bottom-width').toInt();
			
			val.height = innerSpace;
		}
		
		return val;
	},
	/**
	 * This method will return the outer width or height   - considering border
	 */
	getOuterDimension: function(side){
		
		var coords = this.getCoordinates(), val = {}, outerSpace;
		
		if (!side || side == 'width'){
			outerSpace = coords.width +  this.getStyle('margin-left').toInt() + this.getStyle('margin-right').toInt(); //this.getStyle('border-left-width').toInt() + this.getStyle('border-right-width').toInt() +
			val.width = outerSpace;
		}
		
		if (!side || side == 'height'){
			outerSpace = 0;
			outerSpace = coords.height +  this.getStyle('margin-top').toInt() + this.getStyle('margin-bottom').toInt(); //this.getStyle('border-top-width').toInt() + this.getStyle('border-bottom-width').toInt() +
			val.height = outerSpace;
		}
		
		return val;
	},
	hide: function(){
		this.setStyle("display", "none");
	},
	show: function(display){
		(display) ? this.setStyle("display", display) : this.setStyle("display", "block");
	},
	visible: function(){
		this.setStyle("visibility", "visible");
	},
	invisible: function(){
		this.setStyle("visibility", "hidden");
	}
	
});

/* ======================================================*/
/*  					Misc Methods					 */
/* ======================================================*/


/**
 * Load HTML content into a DIV tag. Use this method to load content to any HTML ELEMENT with an ID
 *
 * @scope		Public
 *
 * @params		target 		String, Required. ID of hte target ELEMENT (div, span, input or other HTML ELEMENT)
 * @params		html		String, Required. The HTML content to be inserted
 * @params		unload		Boolean, Optional. Whether to unload local modules when loading new content
 */
PBUtil.loadContent = function(target, html, unload){
	//unload previous modules

	if (unload) {
		PBUtil.garbage.unloadModule();
	}
	
	//insert content
	if ($type(target) != 'element'){
		target = $(target);
	}
	target.setHTML(html);
	
	//resize the window
	if (PBUtil.module.stretchLayout){
		PBUtil.module.stretchLayout.resizeAction();	
	}
}


/**
 * Function for updating the JSON data stored in the 'eventdata' iframe. Two updates are 
 * currently coded in - updating favorite images and selected image.
 *
 * @scope		Public
 *
 * @params		type		String, Required. the purpose i.e. 'update_selected_item', 'update_favorite'
 * @params		options		Object, Required. supply id of image and gallery in the following format.
 *							For selected image, options = {id: x, parent_id: y}
 *							For favorite, options = {id: x, favorite: 1 or 0 } //1 for yes, 0 for no
 * @params		print_log	String, Optional. Prints the status messages in window console (i.e. firebug)
 */
PBUtil.updateEventJSON = function(type, options, print_log){
	
	var data_iframe = $('ifr_eventdata');	
	
	if (print_log) PBUtil.log("Executing update JSON for - " + type);
	
	if ($type(options) == 'object'){
		if (type == 'update_selected_item'){
			//options should include {
			//	"id":23
			//}
			if (data_iframe.contentWindow.json_event_data){
				data_iframe.contentWindow.json_event_data.selected_item.id = options.id;
				data_iframe.contentWindow.json_event_data.selected_item.parent_id = options.parent_id;
				if (print_log) PBUtil.log("JSON update type '" + type + "' was successful");
			} else {
				if (print_log) PBUtil.log("JSON Data Update: ERROR. Could not find the JSON object in target iframe.");
			}
		}
		
		if (type == 'update_favorite'){
			//options should include {
			//	"id":23,
			//	"favorite": 0 || 1	
			//}
			if (data_iframe.contentWindow.json_event_data){
				for (var i=0;i<data_iframe.contentWindow.json_event_data.items.length;i++){
					//window.console.log(data_iframe.contentWindow.json_event_data.items[i].id + " == " + options.id);
					if (data_iframe.contentWindow.json_event_data.items[i].id == options.id){
						data_iframe.contentWindow.json_event_data.items[i].favorite = options.favorite;
						if (print_log) PBUtil.log("JSON update type '" + type + "' was successful");
						break;
					}
				}
			} else {
				if (print_log) PBUtil.log("JSON Data Update: ERROR. Could not find the JSON object in target iframe.");
			}
		}
	} else {
		if (print_log) PBUtil.log("JSON Data Update: ERROR. Wrong 'options' supplied for update type '" + type + "'.");
	}
	
	data_iframe = null;
}

PBUtil.log = function(text){
	if (window.console)	{
		//window.console.log("LOG: " + text)	;
	}
}

//Attach unload to the window event
window.addEvent("beforeunload", function(){ PBUtil.garbage.unloadModule('all') });

window.addEvent("domready", function(){
	
});
