Source: workers/scionQueueWorker.js


/**
 * This is a Worker script that is used as "threaded queue" for managing SCION event execution:
 *
 * New events for SCION are queued in order to allow raising new events from within SCION-event-processing.
 *
 * <p>
 * This "threaded queue" receives messages from the "WebWorker environment engine" of
 * {@link mmir.dialogEngine} - see {@link mmir.state.StateEngineFactory.StateEngineWebWorkerImpl}.
 *
 * <p>
 * The message / work flow is as follows:
 * <ul>
 * 	<li>on receiving <code>queueJob</code>: add new event-job to the queue</li>
 * 	<li>on receiving <code>finishedJob</code>:
 * 		<li>if queue is empty: does nothing</li>
 * 		<li>if queue is not empty: take next job from queue and send it as a <code>processNextJob</code> message to SCION</li>
 * 	</li>
 * </ul>
 *
 * @module workers/scion-queue
 */

if(typeof self === 'undefined' && typeof process !== 'undefined'){
	require('./nodeWorkerThreadsInit');
}


/**
 * A JobQueue is an Array with additional property JobQueue.readyForJob {Boolean}
 *
 * @private
 * @interface
 * @name JobQueue
 * @augments Array
 * @property {Boolean} readyForJob flag that indicates if queue is ready for the next job.
 *
 * @see ~Job
 * @see Array
 */

/**
 * the Job object, describing jobs on a JobQueue
 *
 * @private
 * @interface
 * @name Job
 * @property {Number | String} [engineId] the engine's ID for which this job should be queued
 * @property {String} [event] OPTIONAL the event name (must be present for command "queueJob")
 * @property {any} [eventData] OPTIONAL event data
 *
 * @see ~JobQueue
 */

/**
 * dictionary of <code>jobId -> JobQueue</code>
 *
 * @private
 * @type {PlainObject}
 *
 * @see ~JobQueue
 */
var queues = {};

/**
 * Handler for received messages.
 *
 * @function
 * @name onmessage
 * @param {Object} evt the message object with<br>
 * @param {"finishedJob" | "queueJob" | "destroyQueue"} evt.data.command the message type / name (e.g. <tt>finishedJob</tt>)<br>
 * @param {Number | String} evt.data.engineId Number the engine's ID for which this job should be queued
 * @param {module:workers/scion-queue~Job} [evt.data.job] the job object (e.g. in case of command <tt>queueJob</tt> the job that will be queued)
 *
 * @public
 * @memberOf module:workers/scion-queue#
 */
self.onmessage = function(evt){
	var data = evt.data;
	var queue = getQueue(data.engineId, data.command !== 'destroyQueue');
	switch(data.command){
		case 'finishedJob':
			queue.readyForJob = true;
			distributeJobs(queue);
			break;
		case 'queueJob':
			queue.push(data.job);
			distributeJobs(queue);
			break;
		case 'destroyQueue':
			delete queues[data.engineId];
			break;
		default:
			console.warn('ScionQueueWorker: received unknown message ', evt);
	}
};

/**
 * HELPER get queue for an engine (ID)
 *
 * @function
 * @private
 *
 * @param  {Number | String} engineId the engine ID
 * @param  {Boolean} [isCreate] if TRUE, the queue will be created if it does not exist yet
 * @return {module:workers/scion-queue~JobQuee} the queue for the engineId (if isCreate is FALSE, and no queue exits for the engineId, it will return UNDEFINED)
 */
function getQueue(engineId, isCreate){
	var queue;
	if(queues[engineId]){
		queue = queues[engineId];
	} else if(isCreate){
		queue = new Array();
		queue.readyForJob = true;
		queues[engineId] = queue;
	}
	return queue;
}

/**
 * Handler for sending messages.
 *
 * <p>
 * In case of <code>finishedJob</code>:
 * take next job for the engine-queue and send it to SCION, i.e. post a message <tt>e</tt> with <br>
 *
 * 	{String} event.data.command = <tt>processNextJob</tt><br>
 * 	{Object} event.data.job the job object (that was added before to the queue with command / message <tt>queueJob</tt>
 *
 *
 * @function
 * @public
 * @param {module:workers/scion-queue~JobQueue} queue the job queue
 */
function distributeJobs(queue){
	if(queue.readyForJob && queue.length > 0){
		readyForJob = false;
		var job = queue.shift();
		self.postMessage({
			command: 'processNextJob',
			job: job
		});
	}
};