Example #1
0
        /// <summary>
        /// Asynchronously gets a <see cref="ITeamCompetitor" /> representing away competitor of the match associated with the current instance
        /// </summary>
        /// <returns>A <see cref="Task{ITeamCompetitor}"/> representing the retrieval operation</returns>
        public async Task <ITeamCompetitor> GetAwayCompetitorAsync()
        {
            var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id);

            if (matchCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No match cache item for id={Id}.");
                return(null);
            }
            var items = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await matchCI.GetCompetitorsAsync(Cultures).ConfigureAwait(false)
                : await new Func <IEnumerable <CultureInfo>, Task <IEnumerable <URN> > >(matchCI.GetCompetitorsAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("Competitors")).ConfigureAwait(false);

            if (items == null)
            {
                return(null);
            }

            var competitorUrns = items.ToList();

            if (competitorUrns.Count == 2)
            {
                return(await _sportEntityFactory.BuildTeamCompetitorAsync(competitorUrns[1], Cultures, matchCI).ConfigureAwait(false));
            }

            ExecutionLog.LogError($"Received {competitorUrns.Count} competitors for match[Id = {Id}]. Match can have only 2 competitors.");
            throw new InvalidOperationException($"Invalid number of competitors. Match must have exactly 2 competitors, received {competitorUrns.Count}");
        }
Example #2
0
        /// <summary>
        /// Asynchronously gets the associated category
        /// </summary>
        /// <returns>The associated category</returns>
        public async Task <ICategorySummary> GetCategoryAsync()
        {
            var lotteryCI = (LotteryCI)SportEventCache.GetEventCacheItem(Id);

            if (lotteryCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No lottery cache item for id={Id}.");
                return(null);
            }

            var categoryId = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await lotteryCI.GetCategoryIdAsync().ConfigureAwait(false)
                : await new Func <Task <URN> >(lotteryCI.GetCategoryIdAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("CategoryId")).ConfigureAwait(false);

            if (categoryId == null)
            {
                ExecutionLog.LogDebug($"Missing data. No categoryId for lottery cache item with id={Id}.");
                return(null);
            }
            var categoryData = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await _sportDataCache.GetCategoryAsync(categoryId, Cultures).ConfigureAwait(false)
                : await new Func <URN, IEnumerable <CultureInfo>, Task <CategoryData> >(_sportDataCache.GetCategoryAsync).SafeInvokeAsync(categoryId, Cultures, ExecutionLog, GetFetchErrorMessage("CategoryData")).ConfigureAwait(false);

            return(categoryData == null
                ? null
                : new CategorySummary(categoryData.Id, categoryData.Names, categoryData.CountryCode));
        }
Example #3
0
        public async Task <IStage> GetParentStageAsync()
        {
            var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id);

            if (stageCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No stage cache item for id={Id}.");
                return(null);
            }

            var parentStageId = await stageCI.GetParentStageAsync(Cultures).ConfigureAwait(false);

            if (parentStageId != null)
            {
                //var parentStageCI = (StageCI) SportEventCache.GetEventCacheItem(parentStageId);
                //if (parentStageCI == null)
                //{
                //    return new Stage(parentStageId, GetSportAsync().Result.Id, _sportEntityFactory, SportEventCache, _sportDataCache, SportEventStatusCache, _matchStatusesCache, Cultures, ExceptionStrategy);
                //}

                return(new Stage(parentStageId, GetSportAsync().Result.Id, _sportEntityFactory, SportEventCache, _sportDataCache, SportEventStatusCache, MatchStatusCache, Cultures, ExceptionStrategy));
            }

            return(null);
        }
        /// <summary>
        /// Asynchronously gets a <see cref="IEnumerable{T}"/> representing competitors in the sport event associated with the current instance
        /// </summary>
        /// <returns>A <see cref="Task{T}"/> representing the retrieval operation</returns>
        public async Task <IEnumerable <ICompetitor> > GetCompetitorsAsync()
        {
            var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id);

            if (competitionCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No sportEvent cache item for id={Id}.");
                return(null);
            }
            var items = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await competitionCI.GetCompetitorsAsync(Cultures).ConfigureAwait(false)
                : await new Func <IEnumerable <CultureInfo>, Task <IEnumerable <URN> > >(competitionCI.GetCompetitorsAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("Competitors")).ConfigureAwait(false);

            var competitorUrns = items as List <URN>;

            if (competitorUrns == null || !competitorUrns.Any())
            {
                return(null);
            }

            var tasks = competitorUrns.Select(s =>
            {
                var t = _sportEntityFactory.BuildTeamCompetitorAsync(s, Cultures, competitionCI);
                t.ConfigureAwait(false);
                return(t);
            }).ToList();
            await Task.WhenAll(tasks).ConfigureAwait(false);

            return(tasks.Select(s => s.Result));
        }
Example #5
0
        public async Task <StageType?> GetStageTypeAsync()
        {
            var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id);

            if (stageCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No stage cache item for id={Id}.");
                return(StageType.Child);
            }
            return(await stageCI.GetStageTypeAsync().ConfigureAwait(false));
        }
Example #6
0
        /// <summary>
        /// Adds the sport event status to the internal cache
        /// </summary>
        /// <param name="eventId">The eventId of the sport event status to be cached</param>
        /// <param name="sportEventStatus">The sport event status to be cached</param>
        /// <param name="statusOnEvent">The sport event status received directly on event level</param>
        /// <param name="source">The source of the SES</param>
        private void AddSportEventStatus(URN eventId, SportEventStatusCI sportEventStatus, string statusOnEvent, string source)
        {
            if (_isDisposed)
            {
                return;
            }

            if (sportEventStatus == null)
            {
                return;
            }

            Guard.Argument(eventId, nameof(eventId)).NotNull();

            if (string.IsNullOrEmpty(source) ||
                source.Equals("OddsChange", StringComparison.InvariantCultureIgnoreCase) ||
                source.Equals("SportEventSummary", StringComparison.InvariantCultureIgnoreCase) ||
                !_sportEventStatusCache.Contains(eventId.ToString()))
            {
                lock (_lock)
                {
                    if (!string.IsNullOrEmpty(source))
                    {
                        if (OperationManager.IgnoreBetPalTimelineSportEventStatus && source.Contains("Timeline") && _ignoreEventsTimelineCache.Contains(eventId.ToString()))
                        {
                            ExecutionLog.LogDebug($"Received SES for {eventId} from {source} with EventStatus:{sportEventStatus.Status} (timeline ignored) {statusOnEvent}");
                            return;
                        }

                        source = $" from {source}";
                    }

                    ExecutionLog.LogDebug($"Received SES for {eventId}{source} with EventStatus:{sportEventStatus.Status}");
                    var cacheItem = _sportEventStatusCache.AddOrGetExisting(
                        eventId.ToString(),
                        sportEventStatus,
                        new CacheItemPolicy
                    {
                        AbsoluteExpiration =
                            DateTimeOffset.Now.AddSeconds(OperationManager.SportEventStatusCacheTimeout.TotalSeconds)
                    })
                                    as SportEventStatusCI;
                    if (cacheItem != null)
                    {
                        cacheItem.SetFeedStatus(sportEventStatus.FeedStatusDTO);
                        cacheItem.SetSapiStatus(sportEventStatus.SapiStatusDTO);
                    }
                }
            }
            else
            {
                ExecutionLog.LogDebug($"Received SES for {eventId} from {source} with EventStatus:{sportEventStatus.Status} (ignored)");
            }
        }
Example #7
0
        /// <summary>
        /// Asynchronously gets a <see cref="IFixture"/> instance containing information about the arranged sport event
        /// </summary>
        /// <returns>A <see cref="Task{IFixture}"/> representing the retrieval operation</returns>
        /// <remarks>A Fixture is a sport event that has been arranged for a particular time and place</remarks>
        public async Task <IFixture> GetFixtureAsync()
        {
            var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id);

            if (matchCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No match cache item for id={Id}.");
                return(null);
            }
            return(ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await matchCI.GetFixtureAsync(Cultures).ConfigureAwait(false)
                : await new Func <IEnumerable <CultureInfo>, Task <IFixture> >(matchCI.GetFixtureAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("Fixture")).ConfigureAwait(false));
        }
        /// <summary>
        /// Asynchronously gets a <see cref="BookingStatus"/> enum member providing booking status for the associated @event or a null reference if booking status is not known
        /// </summary>
        /// <returns></returns>
        public async Task <BookingStatus?> GetBookingStatusAsync()
        {
            var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id);

            if (competitionCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No sportEvent cache item for id={Id}.");
                return(null);
            }
            return(ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await competitionCI.GetBookingStatusAsync().ConfigureAwait(false)
                : await new Func <Task <BookingStatus?> >(competitionCI.GetBookingStatusAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("BookingStatus")).ConfigureAwait(false));
        }
Example #9
0
        /// <summary>
        /// Asynchronously gets <see cref="T:System.Collections.Generic.IEnumerable`1" /> list of associated <see cref="T:Sportradar.OddsFeed.SDK.Entities.REST.IDrawResult" />
        /// </summary>
        /// <returns>A <see cref="T:System.Threading.Tasks.Task`1" /> representing an async operation</returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task <IEnumerable <IDrawResult> > GetResultsAsync()
        {
            var drawCI = (DrawCI)SportEventCache.GetEventCacheItem(Id);

            if (drawCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No draw cache item for id={Id}.");
                return(null);
            }
            var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await drawCI.GetResultsAsync(Cultures).ConfigureAwait(false)
                : await new Func <IEnumerable <CultureInfo>, Task <IEnumerable <DrawResultCI> > >(drawCI.GetResultsAsync).SafeInvokeAsync(Cultures, ExecutionLog, "DrawResults").ConfigureAwait(false);

            return(item?.Select(s => new DrawResult(s)));
        }
Example #10
0
        /// <summary>
        /// Asynchronously gets the list of associated <see cref="IDraw"/>
        /// </summary>
        /// <returns>A <see cref="Task{T}"/> representing an async operation</returns>
        public async Task <IEnumerable <IDraw> > GetDrawsAsync()
        {
            var lotteryCI = (LotteryCI)SportEventCache.GetEventCacheItem(Id);

            if (lotteryCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No lottery cache item for id={Id}.");
                return(null);
            }
            var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await lotteryCI.GetScheduledDrawsAsync().ConfigureAwait(false)
                : await new Func <Task <IEnumerable <URN> > >(lotteryCI.GetScheduledDrawsAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("ScheduledDraws")).ConfigureAwait(false);

            return(item.Select(selector: s => new Draw(s, SportId, SportEventCache, Cultures, ExceptionStrategy)));
        }
Example #11
0
        /// <summary>
        /// Asynchronously gets <see cref="DrawStatus" /> associated with the current instance
        /// </summary>
        /// <returns>A <see cref="T:System.Threading.Tasks.Task`1" /> representing an async operation</returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task <DrawStatus> GetStatusAsync()
        {
            var drawCI = (DrawCI)SportEventCache.GetEventCacheItem(Id);

            if (drawCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No draw cache item for id={Id}.");
                return(DrawStatus.Unknown);
            }
            var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await drawCI.GetStatusAsync().ConfigureAwait(false)
                : await new Func <Task <DrawStatus> >(drawCI.GetStatusAsync).SafeInvokeAsync(ExecutionLog, "DrawStatus").ConfigureAwait(false);

            return(item);
        }
 /// <summary>
 /// Asynchronously loads the list of market descriptions from the Sports API
 /// </summary>
 /// <returns>Returns true if the action succeeded</returns>
 public async Task <bool> LoadMarketDescriptionsAsync()
 {
     try
     {
         ExecutionLog.LogDebug($"Loading invariant market descriptions for [{string.Join(",", _prefetchLanguages.Select(l => l.TwoLetterISOLanguageName))}] (user request).");
         _fetchedLanguages.Clear();
         await GetMarketInternalAsync(0, _prefetchLanguages).ConfigureAwait(false);
     }
     catch (Exception ex)
     {
         ExecutionLog.LogWarning($"An error occurred while fetching market descriptions. The exception:{ex.Message}");
         return(false);
     }
     return(true);
 }
        /// <summary>
        /// Asynchronously gets a liveOdds
        /// </summary>
        /// <returns>A liveOdds</returns>
        public async Task <string> GetLiveOddsAsync()
        {
            var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id);

            if (competitionCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No match cache item for id={Id}.");
                return(null);
            }
            var liveOdds = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await competitionCI.GetLiveOddsAsync().ConfigureAwait(false)
                : await new Func <Task <string> >(competitionCI.GetLiveOddsAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("LiveOdds")).ConfigureAwait(false);

            return(liveOdds);
        }
Example #14
0
        /// <summary>
        /// Asynchronously gets a list of additional ids of the parent stages of the current instance or a null reference if the represented stage does not have the parent stages
        /// </summary>
        /// <returns>A <see cref="Task{StageCI}"/> representing the asynchronous operation</returns>
        public async Task <IEnumerable <IStage> > GetAdditionalParentStagesAsync()
        {
            var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id);

            if (stageCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No stage cache item for id={Id}.");
                return(null);
            }
            var cacheItems = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await stageCI.GetAdditionalParentStagesAsync(Cultures).ConfigureAwait(false)
                : await new Func <IEnumerable <CultureInfo>, Task <IEnumerable <URN> > >(stageCI.GetAdditionalParentStagesAsync)
                             .SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("AdditionalParentStages")).ConfigureAwait(false);

            return(cacheItems?.Select(c => new Stage(c, GetSportAsync().Result.Id, _sportEntityFactory, SportEventCache, _sportDataCache, SportEventStatusCache, MatchStatusCache, Cultures, ExceptionStrategy)));
        }
        /// <summary>
        /// Asynchronously gets a <see cref="ISportEventConditions"/> instance representing live conditions of the sport event associated with the current instance
        /// </summary>
        /// <returns>A <see cref="Task{IVenue}"/> representing the retrieval operation</returns>
        /// <remarks>A Fixture is a sport event that has been arranged for a particular time and place</remarks>
        public async Task <ISportEventConditions> GetConditionsAsync()
        {
            var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id);

            if (competitionCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No sportEvent cache item for id={Id}.");
                return(null);
            }
            var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await competitionCI.GetConditionsAsync(Cultures).ConfigureAwait(false)
                : await new Func <IEnumerable <CultureInfo>, Task <SportEventConditionsCI> >(competitionCI.GetConditionsAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("EventConditions")).ConfigureAwait(false);

            return(item == null
                ? null
                : new SportEventConditions(item, Cultures));
        }
Example #16
0
        /// <summary>
        /// Asynchronously gets a <see cref="ILongTermEvent"/> representing the tournament to which the sport event associated with the current instance belongs to
        /// </summary>
        /// <returns>A <see cref="Task{ILongTermEvent}"/> representing the retrieval operation</returns>
        public async Task <ILongTermEvent> GetTournamentAsync()
        {
            var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id);

            if (matchCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No match cache item for id={Id}.");
                return(null);
            }
            var tournamentId = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await matchCI.GetTournamentIdAsync().ConfigureAwait(false)
                : await new Func <Task <URN> >(matchCI.GetTournamentIdAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("ILongTermEvent")).ConfigureAwait(false);

            return(tournamentId == null
                ? null
                : _sportEntityFactory.BuildSportEvent <ILongTermEvent>(tournamentId, null, Cultures, ExceptionStrategy));
        }
Example #17
0
        /// <summary>
        /// Asynchronously gets <see cref="IDrawInfo"/> associated with the current instance
        /// </summary>
        /// <returns>A <see cref="Task{T}"/> representing an async operation</returns>
        public async Task <IDrawInfo> GetDrawInfoAsync()
        {
            var lotteryCI = (LotteryCI)SportEventCache.GetEventCacheItem(Id);

            if (lotteryCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No lottery cache item for id={Id}.");
                return(null);
            }
            var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await lotteryCI.GetDrawInfoAsync().ConfigureAwait(false)
                : await new Func <Task <DrawInfoCI> >(lotteryCI.GetDrawInfoAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("DrawInfo")).ConfigureAwait(false);

            return(item == null
                ? null
                : new DrawInfo(item));
        }
        /// <summary>
        /// Invoked when the <code>_timer</code> ticks in order to periodically fetch market descriptions for configured languages
        /// </summary>
        /// <param name="sender">The <see cref="ITimer"/> raising the event</param>
        /// <param name="e">A <see cref="EventArgs"/> instance containing the event data</param>
        private async void OnTimerElapsed(object sender, EventArgs e)
        {
            if (_isDisposed)
            {
                return;
            }

            //when the timer first elapses fetch data only for languages which were not yet fetched. On subsequent timer elapses fetch data for all configured languages
            var languagesToFetch = _prefetchLanguages.Where(language => !_fetchedLanguages.Contains(language) || _hasTimerElapsedOnce).ToList();

            if (!languagesToFetch.Any())
            {
                _hasTimerElapsedOnce = true;
                return;
            }
            try
            {
                _fetchedLanguages.Clear();
                ExecutionLog.LogDebug($"Loading invariant market descriptions for [{string.Join(",", languagesToFetch.Select(l => l.TwoLetterISOLanguageName))}] (timer).");
                await GetMarketInternalAsync(0, languagesToFetch).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                if (ex is CommunicationException || ex is DeserializationException || ex is FormatException)
                {
                    var languagesString = string.Join(",", languagesToFetch.Select(l => l.TwoLetterISOLanguageName));
                    ExecutionLog.LogWarning($"An error occurred while periodically fetching market description of languages {languagesString}", ex);
                    return;
                }
                var disposedException = ex as ObjectDisposedException;
                if (disposedException != null)
                {
                    ExecutionLog.LogWarning($"An error occurred while periodically fetching market descriptions because the object graph is being disposed. Object causing the exception:{disposedException.ObjectName}");
                    return;
                }
                if (ex is TaskCanceledException)
                {
                    ExecutionLog.LogWarning("An error occurred while periodically fetching market descriptions because the object graph is being disposed.");
                    return;
                }
                ExecutionLog.LogWarning("An error occurred while periodically fetching market description.", ex);
            }

            _hasTimerElapsedOnce = true;
        }
Example #19
0
        public async Task <IStage> GetParentStageAsync()
        {
            var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id);

            if (stageCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No stage cache item for id={Id}.");
                return(null);
            }
            var cacheItem = ExceptionStrategy == ExceptionHandlingStrategy.CATCH
                ? await stageCI.GetParentStageAsync(Cultures).ConfigureAwait(false)
                : await new Func <IEnumerable <CultureInfo>, Task <StageCI> >(stageCI.GetParentStageAsync)
                            .SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("ParentStage")).ConfigureAwait(false);

            return(cacheItem == null
                ? null
                : new Stage(cacheItem.Id, GetSportAsync().Result.Id, _sportEntityFactory, SportEventCache, _sportDataCache, SportEventStatusCache, _matchStatusesCache, Cultures, ExceptionStrategy));
        }
        /// <summary>
        /// Gets the associated event timeline
        /// </summary>
        /// <returns>A <see cref="T:System.Threading.Tasks.Task`1" /> representing the retrieval operation</returns>
        public async Task <IEventTimeline> GetEventTimelineAsync()
        {
            var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id);

            if (matchCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No match cache item for id={Id}.");
                return(null);
            }

            //var oneCulture = new List<CultureInfo> {Cultures.First()};
            var eventTimelineCI = ExceptionStrategy == ExceptionHandlingStrategy.THROW
                ? await matchCI.GetEventTimelineAsync(Cultures).ConfigureAwait(false)
                : await new Func <IEnumerable <CultureInfo>, Task <EventTimelineCI> >(matchCI.GetEventTimelineAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("EventTimeline")).ConfigureAwait(false);

            return(eventTimelineCI == null
                ? null
                : new EventTimeline(eventTimelineCI));
        }
Example #21
0
        public async Task <ISportSummary> GetSportAsync()
        {
            var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id);

            if (stageCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No stage cache item for id={Id}.");
                return(null);
            }
            var sportId = await stageCI.GetSportIdAsync().ConfigureAwait(false);

            if (sportId == null)
            {
                ExecutionLog.LogDebug($"Missing data. No sportId for stage cache item with id={Id}.");
                return(null);
            }
            var sportCI = await _sportDataCache.GetSportAsync(sportId, Cultures).ConfigureAwait(false);

            return(sportCI == null ? null : new SportSummary(sportCI.Id, sportCI.Names));
        }
Example #22
0
        public async Task <ICategorySummary> GetCategoryAsync()
        {
            var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id);

            if (stageCI == null)
            {
                ExecutionLog.LogDebug($"Missing data. No stage cache item for id={Id}.");
                return(null);
            }
            var categoryId = await stageCI.GetCategoryIdAsync(Cultures).ConfigureAwait(false);

            if (categoryId == null)
            {
                ExecutionLog.LogDebug($"Missing data. No categoryId for stage cache item with id={Id}.");
                return(null);
            }
            var categoryCI = await _sportDataCache.GetCategoryAsync(categoryId, Cultures).ConfigureAwait(false);

            return(categoryCI == null
                ? null
                : new CategorySummary(categoryCI.Id, categoryCI.Names, categoryCI.CountryCode));
        }
        public async Task <PlayerProfileCI> GetPlayerProfileAsync(URN playerId, IEnumerable <CultureInfo> cultures)
        {
            Guard.Argument(playerId, nameof(playerId)).NotNull();
            Guard.Argument(cultures, nameof(cultures)).NotNull();
            if (!cultures.Any())
            {
                throw new ArgumentOutOfRangeException(nameof(cultures));
            }

            var timerOptions = new TimerOptions {
                Context = "ProfileCache", Name = "GetPlayerProfileAsync", MeasurementUnit = Unit.Requests
            };

            using (SdkMetricsFactory.MetricsRoot.Measure.Timer.Time(timerOptions, $"{playerId}"))
            {
                await _semaphorePlayer.WaitAsync().ConfigureAwait(false);

                PlayerProfileCI cachedItem;
                try
                {
                    cachedItem = (PlayerProfileCI)_cache.Get(playerId.ToString());
                    var wantedCultures   = cultures.ToList();
                    var missingLanguages = LanguageHelper.GetMissingCultures(wantedCultures, cachedItem?.Names.Keys).ToList();
                    if (!missingLanguages.Any())
                    {
                        return(cachedItem);
                    }

                    // try to fetch for competitor, to avoid requests by each player
                    if (cachedItem?.CompetitorId != null)
                    {
                        var competitorCI = (CompetitorCI)_cache.Get(cachedItem.CompetitorId.ToString());
                        if (competitorCI != null &&
                            (competitorCI.LastTimeCompetitorProfileFetched < DateTime.Now.AddSeconds(-30) ||
                             LanguageHelper.GetMissingCultures(wantedCultures, competitorCI.CultureCompetitorProfileFetched).Any()))
                        {
                            ExecutionLog.LogDebug($"Fetching competitor profile for competitor {competitorCI.Id} instead of player {cachedItem.Id} for languages=[{string.Join(",", missingLanguages.Select(s => s.TwoLetterISOLanguageName))}].");

                            try
                            {
                                await _semaphoreCompetitor.WaitAsync().ConfigureAwait(false);

                                var cultureTasks = missingLanguages.ToDictionary(c => c, c => _dataRouterManager.GetCompetitorAsync(competitorCI.Id, c, null));
                                await Task.WhenAll(cultureTasks.Values).ConfigureAwait(false);
                            }
                            catch (Exception)
                            {
                                // ignored
                            }
                            finally
                            {
                                if (!_isDisposed)
                                {
                                    _semaphoreCompetitor.Release();
                                }
                            }

                            cachedItem       = (PlayerProfileCI)_cache.Get(playerId.ToString());
                            missingLanguages = LanguageHelper.GetMissingCultures(wantedCultures, cachedItem?.Names.Keys).ToList();
                            if (!missingLanguages.Any())
                            {
                                return(cachedItem);
                            }
                        }
                    }

                    var cultureTaskDictionary = missingLanguages.ToDictionary(c => c, c => _dataRouterManager.GetPlayerProfileAsync(playerId, c, null));
                    await Task.WhenAll(cultureTaskDictionary.Values).ConfigureAwait(false);

                    cachedItem = (PlayerProfileCI)_cache.Get(playerId.ToString());
                }
                catch (Exception ex)
                {
                    if (ex is DeserializationException || ex is MappingException)
                    {
                        throw new CacheItemNotFoundException($"An error occurred while fetching player profile for player {playerId} in cache", playerId.ToString(), ex);
                    }

                    throw;
                }
                finally
                {
                    if (!_isDisposed)
                    {
                        _semaphorePlayer.Release();
                    }
                }

                return(cachedItem);
            }
        }