public void Unsuspend(Fixture fixture)
        {
            IMarketStateCollection state = _stateProvider.GetMarketsState(fixture.Id);
            List <IMarketState>    marketStates;

            if (state == null)
            {
                _logger.WarnFormat($"State is not present for {fixture} - can't unsuspend");
                return;
            }

            var unsuspendedFixture = GetUnsuspendedFixture(state, out marketStates);

            if (unsuspendedFixture.Markets.Any())
            {
                _logger.InfoFormat("Unsuspending previously suspended markets in {0}", unsuspendedFixture);
                try
                {
                    _plugin.ProcessStreamUpdate(unsuspendedFixture);
                }
                catch (Exception ex)
                {
                    throw new PluginException($"Plugin ProcessStreamUpdate {fixture} error occured", ex);
                }
            }

            ((IUpdatableMarketStateCollection)state).OnMarketsForcedUnsuspension(marketStates);

            try
            {
                _plugin.UnSuspend(fixture);
            }
            catch (Exception ex)
            {
                throw new PluginException($"Plugin UnSuspend {fixture} error occured", ex);
            }
        }
        private void BuildDefaultStrategies()
        {
            DoNothingStrategy = x => { };

            SuspendFixtureStrategy = x => _plugin.Suspend(x.FixtureId);

            SuspendFixtureIfInPlayStrategy = x => { if (x.FixtureStatus == MatchStatus.InRunning)
                                                    {
                                                        _plugin.Suspend(x.FixtureId);
                                                    }
            };

            SuspendAllMarketsStrategy = x =>
            {
                IEnumerable <IMarketState> includedMarketStates;
                var fixture = GetFixtureWithSuspendedMarkets(x, out includedMarketStates);

                _logger.DebugFormat("Sending suspension command through the plugin for fixtureId={0}", x.FixtureId);

                _plugin.ProcessStreamUpdate(fixture);

                _logger.InfoFormat("Marking markets for fixtureId={0} as suspended", x.FixtureId);
                ((IUpdatableMarketStateCollection)x).OnMarketsForcedSuspension(includedMarketStates);
            };

            SuspendAllMarketsAndSetMatchStatusDeleted = x =>
            {
                IEnumerable <IMarketState> includedMarketStates;

                var fixture = GetFixtureWithSuspendedMarkets(x, out includedMarketStates);
                fixture.MatchStatus = ((int)MatchStatus.Deleted).ToString();

                _logger.DebugFormat("Sending suspension command through the plugin for fixtureId={0} and setting its MatchStatus as deleted", x.FixtureId);
                _plugin.ProcessStreamUpdate(fixture);

                _logger.InfoFormat("Marking markets for fixtureId={0} as suspended", x.FixtureId);
                ((IUpdatableMarketStateCollection)x).OnMarketsForcedSuspension(includedMarketStates);
            };

            SuspendFixtureAndSetMatchStatusDeleted = x =>
            {
                var fixture = new Fixture
                {
                    Id          = x.FixtureId,
                    MatchStatus = ((int)MatchStatus.Deleted).ToString(),
                    Sequence    = x.FixtureSequence
                };


                _logger.DebugFormat("Sending suspension command through the plugin for fixtureId={0} and setting its MatchStatus as deleted", x.FixtureId);
                _plugin.ProcessStreamUpdate(fixture);

                _logger.InfoFormat("Marking markets for fixtureId={0} as suspended", x.FixtureId);
            };

            SuspendInPlayMarketsStrategy = x =>
            {
                List <IMarketState> includedMarketStates = new List <IMarketState>();

                var fixture = new Fixture
                {
                    Id          = x.FixtureId,
                    MatchStatus = ((int)x.FixtureStatus).ToString(),
                    Sequence    = x.FixtureSequence
                };

                foreach (var mkt_id in x.Markets)
                {
                    // we take a conservative approach here.
                    // If, for any reason, the traded_in_play
                    // is not present, we assume it is. Better
                    // to suspend more markets, than less
                    IMarketState state = x[mkt_id];
                    if (state.HasTag("traded_in_play") &&
                        string.Equals(state.GetTagValue("traded_in_play"), "false", StringComparison.OrdinalIgnoreCase))
                    {
                        _logger.DebugFormat("marketId={0} of fixtureId={1} will not be suspended as it is not traded in play", mkt_id, fixture.Id);
                        continue;
                    }

                    if (!state.HasBeenActive)
                    {
                        _logger.DebugFormat("marketId={0} of fixtureId={1} will not be suspended as it has not been active before", mkt_id, fixture.Id);
                        continue;
                    }

                    includedMarketStates.Add(state);
                    fixture.Markets.Add(CreateMarket(x[mkt_id]));
                }


                _logger.DebugFormat("Sending suspension command through the plugin for in-play markets of fixtureId={0}", x.FixtureId);
                _plugin.ProcessStreamUpdate(fixture);

                _logger.InfoFormat("Marking markets for fixtureId={0} as suspended", x.FixtureId);
                ((IUpdatableMarketStateCollection)x).OnMarketsForcedSuspension(includedMarketStates);
            };
        }
        private void ProcessSnapshot(Fixture snapshot, bool isFullSnapshot, bool hasEpochChanged, bool setErrorState = true, bool skipMarketRules = false)
        {
            var logString = isFullSnapshot ? "snapshot" : "stream update";

            if (snapshot == null || (snapshot != null && string.IsNullOrWhiteSpace(snapshot.Id)))
            {
                throw new ArgumentException(string.Format("Received empty {0} for {1}", logString, _resource));
            }

            _logger.InfoFormat("Processing {0} for {1}", logString, snapshot);

            Stopwatch timer = new Stopwatch();

            timer.Start();

            try
            {
                if (isFullSnapshot && !VerifySequenceOnSnapshot(snapshot))
                {
                    return;
                }
                if (IsDisposing || IsStopping)
                {
                    _logger.WarnFormat("Shutting down stream listener, the snapshot {0} won't be processed.", snapshot);
                    return;
                }

                bool is_inplay = string.Equals(snapshot.MatchStatus, ((int)MatchStatus.InRunning).ToString(), StringComparison.OrdinalIgnoreCase);
                IsInPlay = is_inplay;

                if (!skipMarketRules)
                {
                    _marketsRuleManager.ApplyRules(snapshot);

                    snapshot.IsModified = true;
                }
                else
                {
                    _marketsRuleManager.ApplyRules(snapshot, isRemovalDisabled: true);
                }

                if (isFullSnapshot)
                {
                    _platformConnector.ProcessSnapshot(snapshot, hasEpochChanged);
                }
                else
                {
                    _platformConnector.ProcessStreamUpdate(snapshot, hasEpochChanged);
                }

                UpdateState(snapshot, isFullSnapshot);

                IsErrored = false;
            }
            catch (FixtureIgnoredException ex)
            {
                _logger.WarnFormat("{0} received a FixtureIgnoredException", _resource);
                IsIgnored = true;

                _Stats.IncrementValue(AdapterCoreKeys.ERROR_COUNTER);
                RaiseEvent(OnError, ex);
            }
            catch (AggregateException ex)
            {
                _marketsRuleManager.RollbackChanges();

                int total = ex.InnerExceptions.Count;
                int count = 0;
                foreach (var e in ex.InnerExceptions)
                {
                    _logger.Error(string.Format("Error processing {0} for {1} ({2}/{3})", logString, snapshot, ++count, total), e);
                }

                _Stats.IncrementValue(AdapterCoreKeys.ERROR_COUNTER);
                RaiseEvent(OnError, ex);

                if (setErrorState)
                {
                    SetErrorState();
                }
                else
                {
                    throw;
                }
            }
            catch (Exception ex)
            {
                _marketsRuleManager.RollbackChanges();

                _Stats.IncrementValue(AdapterCoreKeys.ERROR_COUNTER);

                _logger.Error(string.Format("Error processing {0} {1}", logString, snapshot), ex);

                RaiseEvent(OnError, ex);

                if (setErrorState)
                {
                    SetErrorState();
                }
                else
                {
                    throw;
                }
            }
            finally
            {
                timer.Stop();
                if (isFullSnapshot)
                {
                    _Stats.AddValue(AdapterCoreKeys.SNAPSHOT_PROCESSING_TIME, timer.ElapsedMilliseconds.ToString());
                }
                else
                {
                    _Stats.AddValue(AdapterCoreKeys.UPDATE_PROCESSING_TIME, timer.ElapsedMilliseconds.ToString());
                }
            }

            _logger.InfoFormat("Finished processing {0} for {1}", logString, snapshot);
        }
        private void ProcessSnapshot(Fixture snapshot, bool isFullSnapshot, bool hasEpochChanged, bool skipMarketRules = false)
        {
            var logString = isFullSnapshot ? "snapshot" : "stream update";

            if (snapshot == null || (snapshot != null && string.IsNullOrWhiteSpace(snapshot.Id)))
            {
                throw new ArgumentException($"Received empty {logString} for {_resource}");
            }

            _logger.Info($"Processing {logString} for {snapshot}");

            try
            {
                if (isFullSnapshot && !VerifySequenceOnSnapshot(snapshot))
                {
                    return;
                }

                _streamStatsActor.Tell(new UpdateStatsStartMsg
                {
                    Fixture          = snapshot,
                    Sequence         = snapshot.Sequence,
                    IsSnapshot       = isFullSnapshot,
                    UpdateReceivedAt = DateTime.UtcNow
                });

                _logger.Info($"BeforeMarketRules MarketsCount={snapshot.Markets.Count} ActiveMarketsCount={snapshot.Markets.Count(_ => _.IsActive)} SelectionsCount={snapshot.Markets.SelectMany(_ => _.Selections).Count()}  {snapshot}");
                if (!skipMarketRules)
                {
                    _marketsRuleManager.ApplyRules(snapshot);
                    snapshot.IsModified = true;
                }
                else
                {
                    _marketsRuleManager.ApplyRules(snapshot, true);
                }
                _logger.Info($"AfterMarketRules MarketsCount={snapshot.Markets.Count} ActiveMarketsCount={snapshot.Markets.Count(_ => _.IsActive)} SelectionsCount={snapshot.Markets.SelectMany(_ => _.Selections).Count()}  {snapshot}");

                if (isFullSnapshot)
                {
                    try
                    {
                        _streamStatsActor.Tell(new UpdatePluginStatsStartMsg()
                        {
                            Fixture          = snapshot,
                            Sequence         = snapshot.Sequence,
                            IsSnapshot       = true,
                            UpdateReceivedAt = DateTime.UtcNow,
                            PluginMethod     = "ProcessSnapshot"
                        });
                        _platformConnector.ProcessSnapshot(snapshot, hasEpochChanged);
                        _streamStatsActor.Tell(new UpdatePluginStatsFinishMsg
                        {
                            CompletedAt = DateTime.UtcNow
                        });
                    }
                    catch (Exception ex)
                    {
                        var pluginError = new PluginException($"Plugin ProcessSnapshot {snapshot} error occured", ex);
                        UpdateStatsError(pluginError);
                        throw pluginError;
                    }
                }
                else
                {
                    try
                    {
                        _streamStatsActor.Tell(new UpdatePluginStatsStartMsg()
                        {
                            Fixture          = snapshot,
                            Sequence         = snapshot.Sequence,
                            IsSnapshot       = false,
                            UpdateReceivedAt = DateTime.UtcNow,
                            PluginMethod     = "ProcessStreamUpdate"
                        });
                        _platformConnector.ProcessStreamUpdate(snapshot, hasEpochChanged);
                        _streamStatsActor.Tell(new UpdatePluginStatsFinishMsg
                        {
                            CompletedAt = DateTime.UtcNow
                        });
                    }
                    catch (Exception ex)
                    {
                        var pluginError = new PluginException($"Plugin ProcessStreamUpdate {snapshot} error occured", ex);
                        UpdateStatsError(pluginError);
                        throw pluginError;
                    }
                }


                UpdateFixtureState(snapshot, isFullSnapshot);
                UpdateSupervisorState(snapshot, isFullSnapshot);

                _streamStatsActor.Tell(new UpdateStatsFinishMsg
                {
                    CompletedAt = DateTime.UtcNow
                });
            }
            catch (FixtureIgnoredException)
            {
                _logger.Warn($"{_resource} received a FixtureIgnoredException");
            }
            catch (AggregateException ex)
            {
                _marketsRuleManager.RollbackChanges();

                int total = ex.InnerExceptions.Count;
                int count = 0;
                foreach (var e in ex.InnerExceptions)
                {
                    _logger.Error($"Error processing {logString} for {snapshot} ({++count}/{total})", e);
                }
                throw;
            }
            catch (Exception ex)
            {
                _marketsRuleManager.RollbackChanges();

                _logger.Error($"Error processing {logString} {snapshot}", ex);
                throw;
            }

            _logger.Info($"Finished processing {logString} for {snapshot}");
        }