private IEnumerator <int> ProcessUpdateLookups(AsyncEnumerator asyncEnumerator, QuotePage[] pages)
        {
            QuotePage page;

            for (int i = 0; i < pages.Length; i++)
            {
                page = pages[i];
                LookupResolver.BeginNormalizeTopicOmitChecks(page.Topic, page.Culture,
                                                             asyncEnumerator.End(AsyncEnumeratorDiscardGroup, LookupResolver.EndNormalizeTopic), page);
            }

            IAsyncResult result;
            bool         updateQuotes = false;

            for (int i = 0; i < pages.Length; i++)
            {
                yield return(1);

                if (asyncEnumerator.IsCanceled())
                {
                    yield break;
                }

                result = asyncEnumerator.DequeueAsyncResult();
                page   = result.AsyncState as QuotePage;

                try
                {
                    page.Topic = LookupResolver.EndNormalizeTopic(result);
                    page.Uri   = LookupResolver.GetUri(page.Topic, page.Culture);
                }
                catch
                {
                    OnTopicNotFound(new TopicNotFoundEventArgs(page.Topic, page.Culture));
                    yield break;
                }

                lock (_lookupsInProgress)
                {
                    if (!_lookupsInProgress.Contains(page.Uri))
                    {
                        _lookupsInProgress.Add(page.Uri);
                        updateQuotes = true;
                    }
                }

                if (updateQuotes)
                {
                    QuoteCollector.UpdateQuotesAsync(page);
                }
            }

            lock (_asyncEnumerators)
            {
                _asyncEnumerators.Remove(asyncEnumerator);
            }
        }
        private IEnumerator <int> ProcessLookup(AsyncEnumerator asyncEnumerator, string topic, CultureInfo culture)
        {
            LookupResolver.BeginNormalizeTopicOmitChecks(topic, culture,
                                                         asyncEnumerator.End(AsyncEnumeratorDiscardGroup, LookupResolver.EndNormalizeTopic), null);

            yield return(1);

            if (asyncEnumerator.IsCanceled())
            {
                yield break;
            }

            try
            {
                topic = LookupResolver.EndNormalizeTopic(asyncEnumerator.DequeueAsyncResult());
            }
            catch
            {
                OnTopicNotFound(new TopicNotFoundEventArgs(topic, culture));
                yield break;
            }

            Uri  uri           = LookupResolver.GetUri(topic, culture);
            bool collectQuotes = false;

            lock (_playlist)
            {
                if (_playlist.Contains(uri))
                {
                    OnTopicAlreadyExists(new TopicAlreadyExistsEventArgs(topic, culture));
                    yield break;
                }
            }

            lock (_lookupsInProgress)
            {
                if (!_lookupsInProgress.Contains(uri))
                {
                    _lookupsInProgress.Add(uri);
                    collectQuotes = true;
                }
            }

            if (collectQuotes)
            {
                QuoteCollector.CollectQuotesAsync(topic, culture, uri);
            }

            lock (_asyncEnumerators)
            {
                _asyncEnumerators.Remove(asyncEnumerator);
            }
        }
        public LookupManager(Playlist playlist, CultureMapper cultureMapper)
        {
            // precondition checking
            if (playlist == null || cultureMapper == null)
            {
                throw new ArgumentNullException();
            }

            _cultureMapper  = cultureMapper;
            _playlist       = playlist;
            _quoteCollector = new QuoteCollector(playlist, cultureMapper);

            RegisterQuoteCollectorEventHandler();
        }
        public void CancelAllPendingLookups()
        {
            QuoteCollector.CancelAllPendingLookups();

            lock (_asyncEnumerators)
            {
                foreach (AsyncEnumerator asyncEnumerator in _asyncEnumerators)
                {
                    asyncEnumerator.Cancel(null);
                    asyncEnumerator.DiscardGroup(AsyncEnumeratorDiscardGroup);
                }

                _asyncEnumerators.Clear();
            }

            lock (_lookupsInProgress)
            {
                _lookupsInProgress.Clear();
            }

            IsBusy = false;
        }