/// <summary>
        /// see RepeatTemplate#WaitForResults
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        protected override bool WaitForResults(IRepeatInternalState state)
        {
            IResultQueue <IResultHolder> queue = ((ResultQueueInternalState)state).ResultQueue;
            bool result = true;

            while (queue.IsExpecting())
            {
                // Careful that no runnables that are not going to finish ever get
                // onto the queue, else this may block forever.
                IResultHolder future;
                try
                {
                    future = queue.Take();
                }
                catch (ThreadInterruptedException)
                {
                    Thread.CurrentThread.Interrupt();
                    throw new RepeatException("InterruptedException while waiting for result.");
                }

                if (future.Error != null)
                {
                    state.GetExceptions().Add(future.Error);
                    result = false;
                }
                else
                {
                    RepeatStatus status = future.Result;
                    result = result && CanContinue(status);
                    ExecuteAfterInterceptors(future.Context, status);
                }
            }
            Assert.State(queue.IsEmpty(), "Future results queue should be empty at end of batch.");
            return(result);
        }
        /// <summary>
        /// see RepeatTemplate#WaitForResults
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        protected override bool WaitForResults(IRepeatInternalState state)
        {
            IResultQueue<IResultHolder> queue = ((ResultQueueInternalState)state).ResultQueue;
            bool result = true;
            while (queue.IsExpecting())
            {
                // Careful that no runnables that are not going to finish ever get
                // onto the queue, else this may block forever.                 
                IResultHolder future;
                try
                {
                    future = queue.Take();
                }
                catch (ThreadInterruptedException)
                {
                    Thread.CurrentThread.Interrupt();
                    throw new RepeatException("InterruptedException while waiting for result.");
                }

                if (future.Error != null)
                {
                    state.GetExceptions().Add(future.Error);
                    result = false;
                }
                else
                {
                    RepeatStatus status = future.Result;
                    result = result && CanContinue(status);
                    ExecuteAfterInterceptors(future.Context, status);
                }
            }
            Assert.State(queue.IsEmpty(), "Future results queue should be empty at end of batch.");
            return result;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="callback"></param>
        /// <returns></returns>
        private RepeatStatus ExecuteInternal(RepeatCallback callback)
        {
            // Reset the termination policy if there is one...
            IRepeatContext context = Start();

            // Make sure if we are already marked complete before we start then no
            // processing takes place.
            bool running = !IsMarkedComplete(context);

            foreach (IRepeatListener interceptor in _listeners)
            {
                interceptor.Open(context);
                running = running && !IsMarkedComplete(context);
                if (!running)
                {
                    break;
                }
            }

            // Return value, default is to allow continued processing.
            RepeatStatus result = RepeatStatus.Continuable;

            IRepeatInternalState state = CreateInternalState(context);
            // This is the list of exceptions thrown by all active callbacks
            ICollection <System.Exception> exceptions = state.GetExceptions();
            // Keep a separate list of exceptions we handled that need to be
            // rethrown
            ICollection <System.Exception> deferred = new List <System.Exception>();

            try
            {
                while (running)
                {
                    #region WhileRunning

                    /*
                     * Run the before interceptors here, not in the task executor so
                     * that they all happen in the same thread - it's easier for
                     * tracking batch status, amongst other things.
                     */
                    foreach (IRepeatListener interceptor in _listeners)
                    {
                        interceptor.Before(context);
                        // Allow before interceptors to veto the batch by setting
                        // flag.
                        running = running && !IsMarkedComplete(context);
                    }

                    // Check that we are still running (should always be true) ...
                    if (running)
                    {
                        #region Running
                        try
                        {
                            result = GetNextResult(context, callback, state);
                            ExecuteAfterInterceptors(context, result);
                        }
                        catch (System.Exception exception)
                        {
                            DoHandle(exception, context, deferred);
                        }

                        // N.B. the order may be important here:
                        if (IsComplete(context, result) || IsMarkedComplete(context) || deferred.Any())
                        {
                            running = false;
                        }
                        #endregion
                    }
                    #endregion
                }

                result = result.And(WaitForResults(state));
                foreach (System.Exception exception in exceptions)
                {
                    DoHandle(exception, context, deferred);
                }

                // Explicitly drop any references to internal state...
                // useless ?
                state = null;
            }

            /*
             * No need for explicit catch here - if the business processing threw an
             * exception it was already handled by the helper methods. An exception
             * here is necessarily fatal.
             */
            finally
            {
                #region HandleFinally
                HandleFinally(deferred, _listeners, context);
                #endregion
            }
            return(result);
        }