/*
* ajaxQueue - jQuery plugin 1.3
* Copyright (c) 2008 Nick Sutton
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*
* Usage
*
* To set defaults for all items added to the queue use the global $.queueDefaults.varName = value
* e.g:
*   $.queueDefaults.url = "test.php";
*
* Use the plugin the same way you would call ajax.
* e.g: 
*   $.queue({
*      type: "POST",
*      url: "test.php",
*      dataType: "json",
*      data: "someVariable=" + someValue,
*      success: success,
*      error: error
*   });
*
* function success(data)
* {
*   alert(data.message);
* }
*
* function error(data)
* {
*   alert(data.message);
* }
*
* Whatever options the $.ajax function takes can be passed along.  The plugin simply extends
* the options to an array of option objects and calls them when it's their turn.
*
* If your backend application finds an error and you need to stop the rest of the queue from executing
* send back a variable back called stopQueue with a value of 1
*
* If you send a variable back called error and set it to 1 the queue will be stopped and an error
* message will be displayed.  Place your error message in the variable errorMessage
* (Need to change it so it just uses error instead of stopQueue and error, basically ditch stop queue)
*
* The one extra option this plugin takes over the ajax standards is 'passAlong'.  This is used if you
* want one item in the queue to pass along any values that are returned to the next item in the queue
*
* For example.  Say you are saving a users account details as the first command in the queue.  Then
* the second command wants to save some other information but requires the account id you created 
* with the first command.  You can't set the value into a hidden field in the first commands callback
* function because all parameters are processed for a command before the execution takes place. What 
* you would do instead is call queue like this (assuming your save account backend code returned 'accountID'
* as a variable
*
*   $.queue({
*      type: "POST",
*      url: "saveAccount.php",
*      dataType: "json",
*      data: "Name=Bob",
*      success: success,
*      error: error,
*      passAlong
*      [
*          "acccountID"
*      ]
*   });
*
* Note that the passAlong option is an array so you can pass along as many variables as you like.  This
* will then tack the name/value pair '&accountID=x' where x is the value returned, onto the end of the
* next item in the queue's data option. 
*
* If the next item in the queue is a function they will be sent to the function in the order they are entered
* in the passAlong array.
*/
;(function($) {
    var arrQueue = new Array();
    var manageQueueID;
    var waiting = false;
    var doDebug = false;
    var dataType = "json";

    $.extend({
        queue: function ( options ) {
            var helper = {};
            helper = $.extend({}, $.queueDefaults, options);
            dataType = helper.dataType;
            helper.done = false;
            helper.params = "";
            addToQueue(helper);
        },
        debug: function debug(str)
        {
            if ( doDebug ) $("#debug").append(str + "<br>");
        },
        stopQueue: function()
        {
            $.debug("Stopping queue");
            clearInterval(manageQueueID);
            manageQueueID = "";
            waiting = false;
        },
        clearQueue: function()
        {
            $.debug("Clearing Queue");
            arrQueue = new Array();
        },
        executeQueue: function()
        {
            if (manageQueueID) return;
            $.debug("Starting Queue");
            manageQueueID = setInterval(manageQueue, 200);
        }
    });

    $.queueDefaults =  {
        dataType: "json",
        type: "POST",
        timeout: 5000
    };

    function addToQueue(helper)
    {
        $.debug("Adding process to queue");
        arrQueue.push(helper);
    }

    function manageQueue( options )
    {
        if (waiting === true)
        {
            $.debug("Waiting for process to finish");
            return;
        }
        var numItems = arrQueue.length - 1;
        $(arrQueue).each(function(i)
        {
            if (waiting === true) //Still waiting for a command to finish
            {
                $.debug("Waiting for process to finish");
                return;
            }

            if (arrQueue.length == 0) return;

            var item = arrQueue[i];
            if (item.done === false)
            {
                // Set waiting to true so that we don't execute any more commands
                    waiting = true;

                    if ( item.isFunction )
                    { // This is a function so just execute it and test the response
                        //var func = eval( item.codeBase + "()"); 
                        if ( ! item.codeBase( item.params ) && ! item.ignoreReturn)
                        {
                            $.stopQueue();
                            $.clearQueue();
                            return;
                        } else {
                            item.done = true;
                            waiting = false;
                        }
                    } else { // This is an ajax request so do a little extra

                        // Create an object that extends this commands options
                            var objSend = $.extend({}, objSend, item);

                        // Set the success function for this command
                            objSend.success = function(data)
                            {
                                $.debug("Process finished");
    
                                // No point in calling the callback if there was an error
                                // ( data.error is only set in the event of an exception being thrown by
                                // the serverside code.  For debuging really)
                                    if ( data.error )
                                    {
                                        $.prompt( data.errorMessage );
                                        $.stopQueue();
                                        $.clearQueue();
                                        return;
                                    }
    
                                // Get a response from the callback function and only continue
                                // the queue if it returns true
                                    if ( ! item.success.apply(this, arguments) )
                                    {
                                        $.stopQueue();
                                        $.clearQueue();
                                        return;
                                    } else {
                                        // Check to see if there are any parameters to pass along to the next item
                                        // in the queue
                                        if (arrQueue[i + 1])
                                        {
                                            if ( arrQueue[i + 1].isFunction)
                                            {
                                                if ( item.passAlong )
                                                {
                                                    var seperator = (item.params == "" ? "" : ",");
                                                    $(item.passAlong).each(function(y)
                                                    {
                                                        var param = item.passAlong[y];
                                                        var value = eval("data." + item.passAlong[y]);
                                                        arrQueue[i + 1].params += seperator + value;
                                                        seperator = ",";
                                                    });
                                                }
                                            } else {
                                                if ( item.passAlong )
                                                {
                                                    $(item.passAlong).each(function(y)
                                                    {
                                                        var param = item.passAlong[y];
                                                        var value = eval("data." + item.passAlong[y]);
                                                        arrQueue[i + 1].data += "&" + param + "=" + + value;
                                                    });
                                                }
                                            }
                                        }
                                    }

                                // Check to see if the serverside code wants to stop the queue
                                    var stopQueue = 0;
                                    switch(dataType)
                                    {
                                        case "json":
                                            if (data.stopQueue == "1") stopQueue = 1;
                                        case "xml":
                                            if ( $("stopQueue", data).text() == "1" ) stopQueue = 1;
                                    }
                                    if (stopQueue == "1")
                                    {
                                        $.stopQueue();
                                        $.clearQueue();
                                        return;
                                    }
                                item.done = true;
                                waiting = false;
                            };
    
                        // Set the error function for this command
                            objSend.error = function(data)
                            {
                                $.debug("Error in process");
                                item.error.apply(this, arguments);
            
                                // Stop the rest of the queue executing
                                $.stopQueue();
                                $.clearQueue();
                            };
        
                        // For ajax commands send the xmlhttp request
                            $.ajax(objSend);
                    }

                // If i = numItems we're at the end of the queue so clear it up ready for new commands
                    if (i == numItems)
                    {
                        $.debug("Reached end of queue");
                        $.stopQueue();
                        $.clearQueue();
                    }
            }
        });
    }
})(jQuery);
