    /**
     * @author Ed Spencer
     * @class Ext.data.Batch
     *
     * <p>Provides a mechanism to run one or more {@link Ext.data.Operation operations} in a given order. Fires the 'operationcomplete' event
     * after the completion of each Operation, and the 'complete' event when all Operations have been successfully executed. Fires an 'exception'
     * event if any of the Operations encounter an exception.</p>
     *
     * <p>Usually these are only used internally by {@link Ext.data.proxy.Proxy} classes</p>
     *
     */
    Ext.define('Ext.data.Batch', {
        mixins: {
            observable: 'Ext.mixin.Observable'
        },

        config: {
            /**
             * @cfg {Boolean} autoStart true to immediately start processing the batch as soon as it is constructed (defaults to false)
             */
            autoStart: false,

            /**
             * @cfg {Boolean} pauseOnException true to automatically pause the execution of the batch if any operation encounters an exception (defaults to true)
             */
            pauseOnException: true,

            /**
             * @cfg {Ext.data.Proxy} proxy The proxy this Batch belongs to. Used to make the requests for each operation in the Batch.
             */
            proxy: null
        },

        /**
         * The index of the current operation being executed
         * @property current
         * @type Number
         */
        current: -1,

        /**
         * The total number of operations in this batch. Read only
         * @property total
         * @type Number
         */
        total: 0,

        /**
         * True if the batch is currently running
         * @property isRunning
         * @type Boolean
         */
        isRunning: false,

        /**
         * True if this batch has been executed completely
         * @property isComplete
         * @type Boolean
         */
        isComplete: false,

        /**
         * True if this batch has encountered an exception. This is cleared at the start of each operation
         * @property hasException
         * @type Boolean
         */
        hasException: false,

        /**
         * @event complete
         * Fired when all operations of this batch have been completed
         * @param {Ext.data.Batch} batch The batch object
         * @param {Object} operation The last operation that was executed
         */

        /**
         * @event exception
         * Fired when a operation encountered an exception
         * @param {Ext.data.Batch} batch The batch object
         * @param {Object} operation The operation that encountered the exception
         */

        /**
         * @event operationcomplete
         * Fired when each operation of the batch completes
         * @param {Ext.data.Batch} batch The batch object
         * @param {Object} operation The operation that just completed
         */

        /**
         * Creates new Batch object.
         * @param {Object} config (optional) Config object
         */
        constructor: function(config) {
            var me = this;

            me.initConfig(config);

            /**
             * Ordered array of operations that will be executed by this batch
             * @property {Ext.data.Operation[]} operations
             */
            me.operations = [];
        },

        /**
         * Adds a new operation to this batch
         * @param {Object} operation The {@link Ext.data.Operation Operation} object
         */
        add: function(operation) {
            this.total++;

            operation.setBatch(this);

            this.operations.push(operation);
        },

        /**
         * Kicks off the execution of the batch, continuing from the next operation if the previous
         * operation encountered an exception, or if execution was paused
         */
        start: function() {
            this.hasException = false;
            this.isRunning = true;

            this.runNextOperation();
        },

        /**
         * @private
         * Runs the next operation, relative to this.current.
         */
        runNextOperation: function() {
            this.runOperation(this.current + 1);
        },

        /**
         * Pauses execution of the batch, but does not cancel the current operation
         */
        pause: function() {
            this.isRunning = false;
        },

        /**
         * Executes a operation by its numeric index
         * @param {Number} index The operation index to run
         */
        runOperation: function(index) {
            var me = this,
                operations = me.operations,
                operation = operations[index],
                onProxyReturn;

            if (operation === undefined) {
                me.isRunning = false;
                me.isComplete = true;
                me.fireEvent('complete', me, operations[operations.length - 1]);
            } else {
                me.current = index;

                onProxyReturn = function(operation) {
                    var hasException = operation.hasException();

                    if (hasException) {
                        me.hasException = true;
                        me.fireEvent('exception', me, operation);
                    } else {
                        me.fireEvent('operationcomplete', me, operation);
                    }

                    if (hasException && me.getPauseOnException()) {
                        me.pause();
                    } else {
                        operation.setCompleted();
                        me.runNextOperation();
                    }
                };

                operation.setStarted();

                me.getProxy()[operation.getAction()](operation, onProxyReturn, me);
            }
        }
    });