/*************************************************************
 *
 * EventManager.js
 * 
 * Handles inter-object communication of data through subscription
 * to single events and two-phased events.
 *
 *************************************************************/

//This object is used to route simple events containers that have registered to receive eventTypes
var _eventListeners			=	{};
//This variable determines which containers to send a commit Event of a particular event type
var _commitListeners		=	{};
//This variable determines which containers to send a request event of a particular event type
var _requestListeners		=	{};
//This variable is used to collect the status of a phasedEvents responders
var _requestResponders		=	{};
//This variable is used to persist the data of an initial request event and to insure that two requests of the same event type are not issued simultaneously
var _responseEvents			=	{};

var _rejectionListeners		=	{};


 /*************************************************************
 *
 * addRequestListener(eventType, containerId, moduleId)
 * 
 * Called from within containers when an event blocker is added to a
 * phased event cycle.  Since there can be multiple blockers per container,
 * the containers registering for event requests are stored in a seperate
 * object from the responses object.  This is to simplify the aggregation
 * of the responses without complicating the submission process for request
 * events.
 * 
 * @param - eventType :String - the event type for the request listener
 * @param - containerId : String - the container requesting to be notified of requests
 * @param - moduleId : String - the unique identifier used to enumerate the response
 * listeners
 *************************************************************/
 function addRequestListener(eventType, containerId, moduleId){
	if(!_requestListeners[eventType]){
		_requestListeners[eventType] = {};
		_requestResponders[eventType] = {};
	}
	_requestListeners[eventType][containerId]	=	true;
	//placing the containerId in the _requestResponders[eventType][moduleId] object in case it is needed later
	_requestResponders[eventType][moduleId]		=	{container : containerId	,	commit : "empty"};
 }
 
 /*************************************************************
 *
 * removeRequestListener(eventType, containerId, moduleId)
 * 
 * Called from within containers when an event blocker is removed from a
 * phased event cycle.  Each container is responsible for unsubscribing itself should it have
 * no additional request listeners remaining for the current eventType
 *
 * If there are no listeners left in _requestResponders[eventType], then the object is deleted.
 * This is to prevent emPhasedEventBroadcast from initiating the request phase for phased events
 * that no longer have request listeners.
 * 
 * @param - eventType :String - the event type for the request listener
 * @param - moduleId : String - the unique identifier used to enumerate the response listeners
 *************************************************************/
 function removeRequestListener(eventType, moduleId){
	if(_requestResponders[eventType]){
		delete _requestResponders[eventType][moduleId];
		var active = false;
		for(var item in _requestResponders[eventType]){
		  active = true;
		}
		if(!active){
		  delete _requestResponders[eventType];
		  delete _requestListeners[eventType];
		}
	}
 }

 /*************************************************************
 * processResponseEvent(eventType, moduleId, commitValue)
 * 
 * This function receives the individual responses from the request listeners and populates
 * the _responders[eventType] object with the commit values.  After the responder has been
 * updated, it loops through the responders to see if the responders are complete
 * 
 * 
 * @param - eventType The type of phasedEvent triggering the responder
 * @param - moduleId The unique identifier associated with a responder
 * @param - commitValue  The Boolean representing go or nogo from a responder
 * a value of "empty" indicates that a responder has not been received yet.
 *************************************************************/
 function processResponseEvent(eventType, moduleId, commitValue, responseInfo){
	_requestResponders[eventType][moduleId].commit	=	commitValue;
	var respond = true;
	var complete = true;
	for (var module in _requestResponders[eventType]){
		if(_requestResponders[eventType][module].commit == "empty"){
			complete = false;
			break;
		}
		else if(!_requestResponders[eventType][module].commit)
			respond = false;  //Need to do something to assemble the error messages here, etc.
	}
	if (complete && respond){
		dispatchPhasedEvent(eventType);
	}else if(complete)
		dispatchPhasedEventRejection(eventType);
 }
 
 /*************************************************************
 *
 * addPhasedEventSubscription(eventType:String, containerId:String)
 *
 * Called from within a container when a child element subscribes
 * for a phased event so that only subscribed events are dispatched
 * to a SWF container.
 *
 * @param - eventType : String - the event type for the phased Event listener
 * @param - containerId : String - the container requesting to be notified
 *
 *************************************************************/
 function addPhasedEventSubscription(eventType, containerId){
	 if(!_commitListeners[eventType])
		_commitListeners[eventType] = {};
	_commitListeners[eventType][containerId] = true;
 }
 
  /*************************************************************
 *
 * addRejectionSubscription(eventType:String, containerId:String)
 *
 * Called from within a container when a child element subscribes for a phased event
 * rejection so that only subscribed events are dispatched to a SWF container.
 *
 * @param - eventType : String - the event type for the phased Event listener
 * @param - containerId : String - the container requesting to be notified
 *
 *************************************************************/
 function addRejectionSubscription(eventType, containerId){
	 if(!_rejectionListeners[eventType])
		_rejectionListeners[eventType] = {};
	_rejectionListeners[eventType][containerId] = true;
 }
 
 
 /*************************************************************
 * dispatchPhasedEvent(eventType)
 * 
 * This function handles the dispatching of a phased event after all responders have
 * authorized the dispatch.  The function loops through all containers that have
 * registered for the event and calls their "dispatchCommitEvent" callback with the data
 * persisted by the responseEvents[eventType] object.
 * 
 * @param - eventType The type of phasedEvent triggering the responder
 *************************************************************/
 function dispatchPhasedEvent(eventType, execute){
	if(execute != undefined){
		var payload = _responseEvents[eventType].payload;
		var moduleId = _responseEvents[eventType].moduleId;
		for (var container in _commitListeners[eventType]){
			getObjectByName(container).dispatchCommitEvent(eventType, payload, moduleId);
		}
		resetResponder(eventType);
	}else
		setTimeout(function(){dispatchPhasedEvent(eventType, true)}, EventDelay);
 }
 
 
 
 
 /*************************************************************
 * dispatchPhasedEventRejection(eventType)
 * 
 * This function handles a rejected phased event and calls the original container
 * that dispatched the event, so that it's onRejected callback function can receive
 * the rejection data.
 * 
 * @param - eventType The type of phasedEvent triggering the responder
 *************************************************************/
 function dispatchPhasedEventRejection(eventType, execute){
	if(execute != undefined){
		var payload = _responseEvents[eventType].payload;
		var moduleId = _responseEvents[eventType].moduleId;
		for (var container in _rejectionListeners[eventType]){
			getObjectByName(container).dispatchRejectedEvent(eventType, payload, moduleId);
		}
		resetResponder(eventType);
	}else
		setTimeout(function(){dispatchPhasedEventRejection(eventType, true)}, EventDelay);
 }
 
/*************************************************************
 *
 * emEventBroadcast(eventType, payload, source)
 * 
 * @param eventType - the type of Simple Event being dispatched
 * @param payload - the payload object of the event
 * @param source - the id of the module sending the event
 *
 *************************************************************/
function emEventBroadcast(eventType, payload, source, container, execute){
	if(execute != undefined){
		for (var p in _eventListeners[eventType]){
			getObjectByName(p).dispatchEvent(eventType, payload, source);
		}
	}else
		setTimeout(function(){emEventBroadcast(eventType, payload, source, container, true)}, EventDelay);
}

var queuedPhasedEvents = {};
/*************************************************************
 *
 * emPhasedEventBroadcast(eventType, payload, source)
 * 
 * This function will persist the original request data as well as insure that
 * a phased event of the same type is not dispatched before the orinal event has
 * completed.
 * 
 * @param eventType - the type of PhasedEvent being dispatched
 * @param payload - the payload object of the event
 * @param moduleId - the id of the module sending the event
 * @param containerId - the id of the container sending the event (unused)
 *
 *************************************************************/
function emPhasedEventBroadcast(eventType, payload, moduleId, containerId, execute){
	if(execute != undefined){
		if(!_responseEvents[eventType]){
			_responseEvents[eventType]				=	{};
			_responseEvents[eventType].payload		= payload;
			_responseEvents[eventType].moduleId		= moduleId;
			_responseEvents[eventType].containerId	= containerId;
			if(_requestListeners[eventType]){
				for (var container in _requestListeners[eventType]){
					getObjectByName(container).dispatchRequestEvent(eventType, payload, moduleId);
				}
			}
			else{
				dispatchPhasedEvent(eventType, true);
			}
		}else{
			queuedPhasedEvents[eventType]				= {};
			queuedPhasedEvents[eventType].payload		= payload;
			queuedPhasedEvents[eventType].moduleId		= moduleId;
			queuedPhasedEvents[eventType].containerId	= containerId;
		}
	}else
		setTimeout(function(){emPhasedEventBroadcast(eventType, payload, moduleId, containerId, true)}, EventDelay);
}

var EventDelay = 0;
 
 /*************************************************************
 *
 * addSimpleEventSubscription(eventType:String, containerId:String)
 *
 * Called from within all containers when a child element subscribes
 * for a simple event so that only subscribed events are dispatched
 * to a SWF container.
 *
 *************************************************************/
 function addSimpleEventSubscription(eventType, containerId){
	 if(!_eventListeners[eventType])
		_eventListeners[eventType] = {};
	_eventListeners[eventType][containerId] = true;
 }
 

 /*************************************************************
 *
 * removePhasedEventSubscription(eventType:String, containerId:String)
 *
 * Called from within a container when a child element unsubscribes
 * from a phased event request.
 *
 * @param - eventType : String - the event type for the phased Event listener
 * @param - containerId : String - the container requesting to be notified
 *
 *************************************************************/
function removePhasedEventSubscription(eventType, containerId){
	 if(_commitListeners[eventType][containerId])
		delete _commitListeners[eventType][containerId];
 }
 
  /*************************************************************
 *
 * removeRejectionSubscription(eventType:String, containerId:String)
 *
 * Called from within a container when a child element unsubscribes
 * from a phased event rejection.
 *
 * @param - eventType : String - the event type for the phased Event rejection listener
 * @param - containerId : String - the container requesting to be notified
 * @param - containerId : String - the container requesting to be notified
 *
 *************************************************************/
function removeRejectionSubscription(eventType, containerId){
	 if(_rejectionListeners[eventType][containerId])
		delete _rejectionListeners[eventType][containerId];
 }
 
 /*************************************************************
 * resetResponder(eventType)
 * 
 * This function deletes the responseEvent object for the specified event type 
 * so that a new event can be dispatched and resets the response objects
 * commit flags to "empty".
 * 
 * @param eventType - the responder event type to be reset
 * 
 *************************************************************/
 function resetResponder(eventType)
 {
 	delete _responseEvents[eventType];
	for (var module in _requestResponders[eventType]){
		_requestResponders[eventType][module].commit = "empty";
	}
	if(queuedPhasedEvents[eventType]){
		var payload		= queuedPhasedEvents[eventType].payload;
		var moduleId	= queuedPhasedEvents[eventType].moduleId;
		var containerId	= queuedPhasedEvents[eventType].containerId;
		delete queuedPhasedEvents[eventType];
		emPhasedEventBroadcast(eventType,	payload,	moduleId,	containerId);
	}
 }
 
 function getFrameBodyWidth(){
	if (top === self){
		return -1
	}else{
		return document.body.clientWidth;
	}
}

function getFrameBodyHeight(){
	if (top === self){
		return -1;
	}else
		return document.body.clientHeight;
}
 
 /*************************************************************
 *
 * getObjectByName(name:String)
 *
 * Returns a reference to and object on the page.
 * Used to allow us to call a function on a flash-swf.
 *
 *************************************************************/
 function getObjectByName(name)
 {
	if(window.document[name]){
		return window.document[name];
	}
	return document.getElementById(name);
 }

