/// <summary>
        /// Polls the collection of instances until each has passed the condition at least once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collectionToMonitor"></param>
        /// <param name="condition"></param>
        /// <param name="getName"></param>
        /// <param name="listObjects"></param>
        /// <param name="cancellationToken"></param>
        /// <param name="detailLevel">Controls the detail level of the data returned by a call to the Azure Batch Service.</param>
        /// <param name="control"></param>
        /// <returns></returns>
        public static async Task WhenAllAsync <T>(
            IEnumerable <T> collectionToMonitor,
            Func <T, bool> condition,
            Func <T, string> getName,
            ListDelegate <T> listObjects,
            CancellationToken cancellationToken,
            ODATADetailLevel detailLevel,
            ODATAMonitorControl control) where T : IRefreshable
        {
            if (null == collectionToMonitor)
            {
                throw new ArgumentNullException("collectionToMonitor");
            }

            if (null == condition)
            {
                throw new ArgumentNullException("condition");
            }

            RefreshViaODATAFilterList <T> odataRefresher = new RefreshViaODATAFilterList <T>(cancellationToken, detailLevel, condition, listObjects, control);

            // populate for first pass
            foreach (T curT in collectionToMonitor)
            {
                // filter out the instances that already meet the condition
                if (!condition(curT))
                {
                    MonitorLastCall <T> box = new MonitorLastCall <T>(curT, /* flags each instance as available to refresh "now" */ DateTime.MinValue);

                    odataRefresher.CurrentPassQueue.Enqueue(box);
                }
            }

            // process the instances in the current pass... swap queues to begin next pass
            while (!odataRefresher.CancellationToken.IsCancellationRequested &&
                   odataRefresher.CurrentPassQueue.Count > 0)
            {
                // get next instance
                MonitorLastCall <T> nextInstanceToProcess = odataRefresher.CurrentPassQueue.Dequeue();

                // build an odata filter with as many names as the limit will allow and call refresh instances as needed
                Task asyncProcessOneInstance = odataRefresher.ProcessOneInstance(nextInstanceToProcess, getName);

                // a-wait for completion
                await asyncProcessOneInstance.ConfigureAwait(continueOnCapturedContext : false);

                // if the current pass queue is empty, swap the queues to begin next pass
                if (0 == odataRefresher.CurrentPassQueue.Count)
                {
                    odataRefresher.SwapQueues();

                    // if we appear to be done, the stringbuilder might have the last predicate in it so flush that
                    if (0 == odataRefresher.CurrentPassQueue.Count)
                    {
                        // start the call to process the last predicate
                        Task asyncListTask = odataRefresher.CallListAndProcessResults();

                        // a-wait for completion
                        await asyncListTask.ConfigureAwait(continueOnCapturedContext : false);

                        // if the last predicate created new work... the swap will bring it into a new pass
                        odataRefresher.SwapQueues();
                    }
                }
            }

            //Were we cancelled?
            odataRefresher.CancellationToken.ThrowIfCancellationRequested();
        }
        private async Task WhenAllImplAsync(
            IEnumerable <CloudTask> tasksToMonitor,
            Common.TaskState desiredState,
            CancellationToken cancellationToken,
            ODATAMonitorControl controlParams,
            IEnumerable <BatchClientBehavior> additionalBehaviors)
        {
            if (null == tasksToMonitor)
            {
                throw new ArgumentNullException("tasksToMonitor");
            }

            // we only need the id and state for this monitor.  the filter clause will be updated by the monitor
            ODATADetailLevel odataSuperOptimalPredicates = new ODATADetailLevel()
            {
                SelectClause = "id,state"
            };

            // for validation and list calls we need the parent name values
            string jobId = null;

            // set up behaviors
            BehaviorManager bhMgr = new BehaviorManager(this.CustomBehaviors, additionalBehaviors);

            // set up control params if needed
            if (null == controlParams)
            {
                controlParams = new ODATAMonitorControl(); // use defaults
            }

            tasksToMonitor = await UtilitiesInternal.EnumerateIfNeededAsync(tasksToMonitor, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);

            // validation: job schedule id and jobId
            foreach (CloudTask curTask in tasksToMonitor)
            {
                // can only monitor bound objects
                if (curTask.BindingState != BindingState.Bound)
                {
                    Exception ex = UtilitiesInternal.OperationForbiddenOnUnboundObjects;

                    throw ex;
                }

                // set or validate job Id
                if (null == jobId)
                {
                    jobId = curTask.ParentJobId;
                }
                else
                {
                    // all instances must have same parent
                    if (!jobId.Equals(curTask.ParentJobId, StringComparison.OrdinalIgnoreCase))
                    {
                        Exception ex = UtilitiesInternal.MonitorRequiresConsistentHierarchyChain;

                        throw ex;
                    }
                }
            }

            // start call
            Task asyncTask = ODATAMonitor.WhenAllAsync(
                tasksToMonitor,
                x =>
            {
                // return true if is desired state
                bool hasReachedDesiredState = x.State == desiredState;
                return(hasReachedDesiredState);
            },
                x => { return(x.Id); },                                                                                          // return the Id of the task
                () => _parentUtilities.ParentBatchClient.JobOperations.ListTasksImpl(jobId, bhMgr, odataSuperOptimalPredicates), // call this lambda to (re)fetch the list
                cancellationToken,
                odataSuperOptimalPredicates,
                controlParams);

            await asyncTask.ConfigureAwait(continueOnCapturedContext : false);
        }