/**
* @version $ Id; cjtserverqueue.js 21-03-2012 03:22:10 Ahmed Said $
*
* CJTServerQueue class.
*/

/*
* Put CJTServerQueue class at global scope.
*
* @var CJTServerQueue
*/
var CJTServerQueue;

/*
* JQuery wrapper for the CJTServerQueue object.
*/
(function($) {

	/*
	*	Abstract base class for Ajax Queue classes.
	*
	* This is a prototype and cannot be used without a derivided class.
	* There is two abstract method must be implemented in the child class.
	*
	* Abstracts:
	* 	- getData() : This method get called when this.send method is called right before
	* 								sending the request to the server. The purpose of the method is to Encapsulate the
	*									queues data and prepare it for sending.
	*		- getResponseParameters(response, data): This method called when server response. The method will be called
	*									for every added queue. The purpose of the method is to de-encapsulate response object
	*									to pass for every queue.
	*
	* @author Ahmed Said
	* @version 6
	*/
	CJTServerQueue = function() {

		/*
		* Operation Action.
		*
		* @var string
		*/
		this.action = null;

		/*
		* Controller map name.
		*
		* @var string
		*/
		this.controller = null;

		/*
		* Queue object unique identifier.
		*
		* @internal
		* @var string
		*/
		this.key = '';

		/*
		* Lock or Unlock queue object allow and disallow sending
		* the request to the server when .send() method is called.
		*
		* @var boolean
		*/
		this.locked = false;

		/*
		* Operations queue.
		*
		* All queued operations are stored here waiting
		* for sending.
		*
		* @var object
		*/
		this.queue = [];

		this.errors = [];

		/*
		* Derived classed constructor.
		*
		* Call this from child classes for initialize objects.
		*
		* @param string Controller map name.
		* @param string Action name.
		* @param string Queue key.
		* @return void
		*/
   	this._init = function(controller, action, key) {
			this.controller = controller;
			this.action = action;
			this.key = key;
			// Reset prototype copy vars.
			this.queue = [];
			this.locked = false;
   	}

		/*
		* Add request to the queue.
		*
		* The method push the new data to the queue list.
		*
		* The returned object is jQuery Ajax-Like object that has .success and .error
		* methods implemented. You can add callbacks to the returned object as like as you
		* need. When the queue is sent to the server and the response received,
		* all these methods will be called with the context parameter as "this" pointer.
		*
		* Possible values for queue type is 'queue' and endpoint.
		*
		* endpoint is extension to send method when the object is locked.
		* This allow dispatch method to call deferred methods added through send method
		* when the object was locked.
		*
		* @param object Data to add to queue.
		* @param mixed context to be used for deferred callbacks (e.g success, error).
		* @param string Queue type.
		* @return CJTServer.getDeferredObject.promise()
		*/
		this.add = function (data, context, type) {
			// Check for special characters in block name.
			if (data.property === 'name') {
				if (!data.value.match(/^[A-Za-z0-9\!\#\@\$\&\*\(\)\[\]\x20\-\_\+\?\:\;\.]{1,50}$/)) {
					alert('The block name cannot contain special characters. Please use A-Z, 0-9, -, _ and space characters only.')

					this.errors = data.value
				} else {
					this.errors = []
				}
			}

			if (this.errors.length <= 0) {
				var queue = {
					deferred: CJTServer.getDeferredObject(),
					data: data,
					context: context,
					type: ((type == undefined) ? 'queue' : type)
				};
				var promise = queue.deferred.promise();
				// Add queue object to the queue.
				this.queue.push(queue);
				return promise;
			} else {
				return CJTServer.getDeferredObject().promise()
			}
		}

		/*
		* Clear queues list.
		*
		* The method quietly clear queue list.
		*
		* No callbacks called when queue is cleared.
		*
		* @return void
		*/
		this.clear = function() {
			this.queue = [];
		}

		/*
		* Dispatch callbacks associated for the all the available queues.
		*
		* @internal
		*
		* state parameter possible values are:
		* 	- resolve
		*		- reject
		*
		* @param string jQuery.Deferred states.
		* @param object Response Object to pass to the callbacks.
		* @return void
		*/
		this.dispatch = function(state, response) {
			var method = state + 'With';
			var serverQueue = this; // To use inside .each().
			var queueParams = null;
			$(this.queue).each(function(index, queue) {
        // If rejected don't call getResponseParameters() to avoid error
        // This is a temporary solution for version 6.0 to be releases!
        // Get queue parameters based on queue type.
        if ((state == 'reject') || (queue.type == 'endpoint')) {
            // endpoint type queue is queue to handle the typical/native
            // ajax response without setting up response parameters.
            queueParams = [response];
        }
				else if (queue.type == 'queue') {
					// Customize response data based on derivded class.
					queueParams = serverQueue.getResponseParameters(response, queue.data)
				}
				queue.deferred[method](queue.context, queueParams);
				// Always call completed callbacks.
				queue.deferred.completeDeferred.resolveWith(queue.context, queueParams);
			});
			// Clear queue.
			this.clear();
		}

		/*
		* Don't send the queue when send method is called.
		*
		* This method is great when an operation need to control the behavior of
		* another operation. An operation may prevent the queue from sending the request
		* and do that in alternative ways.
		*
		* @return void
		*/
		this.lock = function() {
			this.locked = true;
		}

		/*
		* Merge queue object to current queue.
		*
		* @param CJTServerQueue Queue object to merge to this queue.
		* @return void
		*/
		this.merge = function(serverQueue) {
			this.queue = $.merge(this.queue, serverQueue.queue);
		}

		/*
		* Send queue data to server.
		*
		* If the object is locked nothing will happen at all.
		* If the object is unlocked a call to CJTServer.send method will be
		* processed with the data returned from the abstract method .getData().
		*
		* @param string Http Request Method @see CJTServer.send for more details.
		* @param object Data to pass along with the queue data.
		* @return CJTServer.getDeferredObject.promise()
		*/
		this.send = function(method, data) {
			var ajaxPromise = null;
			// Process only of not locked.

			if (!this.locked && this.errors.length <= 0) {
				var queue = this; // To be used inside .each().
				// Merge data param with derived class data for the final request.
				// But first mask usre data param is passed.
				data = (data != undefined) ? data : {};
				data = $.extend(data, this.getData());
				// Send request to CJTServer object.
				ajaxPromise = CJTServer.send(this.controller, this.action, data, method)
				.success(
					function(response) {
						queue.dispatch('resolve', response);
					}
				)
				.error(
					function(response) {
						queue.dispatch('reject', response);
					}
				);
			}
			else {
				// Use Dummy Deferred object in case the object is locked.
				ajaxPromise = this.add(data, undefined, 'endpoint');
			}
			return ajaxPromise;
		}

		/*
		* Unlock queue object.
		*
		* @return void
		*/
		this.unlock = function() {
			this.locked = false;
		}

	} // End class.

})(jQuery);