/// <summary>
            /// Uses list func to fetch fresh data on the instances in the predicate.
            /// Instances that fail the condition are enqueued for the next pass.
            /// </summary>
            /// <returns></returns>
            internal async Task CallListAndProcessResults()
            {
                // extract the predicate that restricts the list call
                string predicate = _odataFilterSB.ToString();

                // clear the sb for the next batch
                _odataFilterSB.Clear();

                // early exit if there is no work to do
                if (string.IsNullOrWhiteSpace(predicate))
                {
                    return;
                }

                // update the detail level
                _odataDetailLevel.FilterClause = predicate;

                // get the enumerable to refresh the instances
                IPagedEnumerable <T> tEnumberable = _listObjects();

                // get the enumerator for asycn walk of the collection
                IPagedEnumerator <T> tEnumerator = tEnumberable.GetPagedEnumerator();

                // used to enumerate until out of data
                bool thereIsMoreData;

                do
                {
                    // move to next instance, possibley make call to server to get next batch
                    Task <bool> asyncTask = tEnumerator.MoveNextAsync(this.CancellationToken);

                    thereIsMoreData = await asyncTask.ConfigureAwait(continueOnCapturedContext : false);

                    if (thereIsMoreData)
                    {
                        // get the current instance
                        T refreshedInstance = tEnumerator.Current;

                        // test it to see if it is done
                        if (!_condition(refreshedInstance))
                        {
                            // we will have to refresh it again so put in queue for next pass

                            // box it up
                            MonitorLastCall <T> mlc = new MonitorLastCall <T>(refreshedInstance, DateTime.UtcNow + _odataMonitorControl.DelayBetweenDataFetch);

                            // enqueue it for next pass
                            this.NextPassQueue.Enqueue(mlc);
                        }
                    }
                }while (thereIsMoreData);
            }
        /// <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();
        }
            internal async Task ProcessOneInstance(MonitorLastCall <T> nextInstance, Func <T, string> getName)
            {
                // we will loop until this is null
                MonitorLastCall <T> processThisInstance = nextInstance;

                while (null != processThisInstance)
                {
                    bool     usePredicateToCallList = false;
                    DateTime utcNow = DateTime.UtcNow;

                    // if it is not too early, we can use this instance
                    if (utcNow >= nextInstance.DoNotRefreshUntilUTC)
                    {
                        // now check to see if it will fit
                        // remember the limit on the name is 64 and the limit on the predicate is 500
                        // the assumption is that even if these #s evolve at least one max-sized-name will fit.

                        StringBuilder possibleAdditionalExpression = new StringBuilder();

                        // if this is not the first name then we must "or" this name in
                        if (0 != _odataFilterSB.Length)
                        {
                            possibleAdditionalExpression.Append(OrOperator);
                        }

                        // add in the name prefix
                        possibleAdditionalExpression.Append(IdPrefix);

                        // get the name of the object
                        string name = getName(nextInstance.Instance);

                        // add in the name
                        possibleAdditionalExpression.Append(name);

                        // add the name postfix
                        possibleAdditionalExpression.Append(IdPostfix);

                        // if it will fit then append the clause to the predicate
                        if ((_odataFilterSB.Length + possibleAdditionalExpression.Length) < _odataMonitorControl.ODATAPredicateLimit)
                        {
                            // amend the predicate to refresh the object
                            _odataFilterSB.Append(possibleAdditionalExpression.ToString());

                            processThisInstance = null;  // we are done
                        }
                        else
                        {
                            // it will not fit so we are done with this predicate
                            usePredicateToCallList = true;
                        }
                    }
                    else // if the next instance cannot be refreshed yet we may need to wait a bit
                    {
                        // if we have work to do... return to process that work and use up time
                        if (_odataFilterSB.Length > 0)
                        {
                            usePredicateToCallList = true;
                        }
                        else  // if we have no work to do we should delay until the instance can be refreshed
                        {
                            TimeSpan delayThisMuch = processThisInstance.DoNotRefreshUntilUTC - utcNow;

                            if (delayThisMuch.Ticks > 0)
                            {
                                await System.Threading.Tasks.Task.Delay(delayThisMuch).ConfigureAwait(continueOnCapturedContext: false);
                            }
                        }
                    }

                    // should we call the server with the current predicate data?
                    if (usePredicateToCallList)
                    {
                        usePredicateToCallList = false;

                        // start the new list operation
                        Task asyncListTask = CallListAndProcessResults();

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