/// <summary>
        /// Initializes a new instance of the <see cref="EvaluateReactionRegistrationResult"/> class.
        /// </summary>
        /// <param name="reactionEvent">The reaction.</param>
        /// <param name="recordSetHandlingMementos">The mementos for completing or canceling.</param>
        public EvaluateReactionRegistrationResult(
            ReactionEvent reactionEvent,
            IReadOnlyCollection <RecordSetHandlingMemento> recordSetHandlingMementos)
        {
            if (reactionEvent != null)
            {
                recordSetHandlingMementos.MustForArg(nameof(recordSetHandlingMementos)).NotBeNullNorEmptyEnumerableNorContainAnyNulls();
            }
            else
            {
                recordSetHandlingMementos.MustForArg(nameof(recordSetHandlingMementos)).NotBeNull();
            }

            this.ReactionEvent             = reactionEvent;
            this.RecordSetHandlingMementos = recordSetHandlingMementos;
        }
        public override EvaluateReactionRegistrationResult Execute(
            EvaluateReactionRegistrationOp operation)
        {
            if (operation.ReactionRegistration.Dependencies.Count != 1)
            {
                throw new NotSupportedException(Invariant($"Only 1 single {typeof(RecordFilterReactorDependency)} is supported, {operation.ReactionRegistration.Dependencies.Count} were supplied."));
            }

            var dependency             = operation.ReactionRegistration.Dependencies.Single();
            var recordFilterDependency = dependency as RecordFilterReactorDependency;

            if (recordFilterDependency == null)
            {
                throw new NotSupportedException(Invariant($"Only {typeof(RecordFilterReactorDependency)} is supported, {dependency?.GetType().ToStringReadable()}."));
            }

            var reactionId = Invariant($"{operation.ReactionRegistration.Id}___{DateTime.UtcNow.ToStringInvariantPreferred()}");

            var streamRepToHandledDependencyRecordIdToBeIncludedMap = new Dictionary <IStreamRepresentation, HashSet <long> >();
            var handledRecordMementos = new List <RecordSetHandlingMemento>();
            var allRequiredSeen       = true;

            foreach (var recordFilterEntry in recordFilterDependency.Entries)
            {
                try
                {
                    var stream = this.streamFactory.Execute(new GetStreamFromRepresentationOp(recordFilterEntry.StreamRepresentation));
                    stream.MustForOp(nameof(stream)).BeAssignableToType <ISyncReturningProtocol <StandardTryHandleRecordOp, TryHandleRecordResult> >();
                    var streamProtocol = (ISyncReturningProtocol <StandardTryHandleRecordOp, TryHandleRecordResult>)stream;

                    var tryHandleConcern = EvaluateReactionRegistrationOp.BuildHandlingConcern(operation.ReactionRegistration, recordFilterEntry);

                    var          handledIds    = new HashSet <long>(); // this is because we could get duplicates...
                    StreamRecord currentRecord = null;
                    do
                    {
                        var tryHandleRecordOp = new StandardTryHandleRecordOp(
                            tryHandleConcern,
                            recordFilterEntry.RecordFilter,
                            streamRecordItemsToInclude: StreamRecordItemsToInclude.MetadataOnly,
                            tags: new[]
                        {
                            new NamedValue <string>(TagNames.PotentialReactionId, reactionId),
                        });

                        var tryHandleRecordResult = streamProtocol.Execute(tryHandleRecordOp);

                        currentRecord = tryHandleRecordResult?.RecordToHandle;
                        if (currentRecord != null)
                        {
                            handledIds.Add(currentRecord.InternalRecordId);
                        }
                    }while (currentRecord != null);

                    if (handledIds.Any())
                    {
                        var streamProtocolFactoryForActions  = (IStreamRecordHandlingProtocolFactory)stream;
                        var streamHandlingProtocolForActions = streamProtocolFactoryForActions.GetStreamRecordHandlingProtocols();

                        void CompleteAction()
                        {
                            foreach (var handledInternalRecordId in handledIds)
                            {
                                var completeHandlingOp = new CompleteRunningHandleRecordOp(
                                    handledInternalRecordId,
                                    tryHandleConcern);
                                streamHandlingProtocolForActions.Execute(
                                    completeHandlingOp);
                            }
                        }

                        void CancelAction()
                        {
                            foreach (var handledInternalRecordId in handledIds)
                            {
                                var cancelHandlingOp = new CancelRunningHandleRecordOp(
                                    handledInternalRecordId,
                                    tryHandleConcern,
                                    "Not all required dependencies present.");
                                streamHandlingProtocolForActions.Execute(
                                    cancelHandlingOp);
                            }
                        }

                        var actionableSetForTracking = new RecordSetHandlingMemento(CompleteAction, CancelAction);
                        handledRecordMementos.Add(actionableSetForTracking);

                        if (recordFilterEntry.IncludeInReaction)
                        {
                            if (streamRepToHandledDependencyRecordIdToBeIncludedMap.ContainsKey(recordFilterEntry.StreamRepresentation))
                            {
                                streamRepToHandledDependencyRecordIdToBeIncludedMap[recordFilterEntry.StreamRepresentation].AddRange(handledIds);
                            }
                            else
                            {
                                streamRepToHandledDependencyRecordIdToBeIncludedMap.Add(recordFilterEntry.StreamRepresentation, handledIds);
                            }
                        }
                    }
                    else
                    {
                        if (recordFilterEntry.RequiredForReaction && !operation.OverrideRequired)
                        {
                            allRequiredSeen = false;
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new ReactorException(Invariant($"Failed to process entry: {recordFilterEntry}."), ex, operation);
                }
            }

            EvaluateReactionRegistrationResult result;

            if (!allRequiredSeen)
            {
                foreach (var recordSetHandlingMemento in handledRecordMementos)
                {
                    recordSetHandlingMemento.CancelSet();
                }

                // no reaction created since not all requirement met.
                result = new EvaluateReactionRegistrationResult(null, new List <RecordSetHandlingMemento>());
            }
            else if (!handledRecordMementos.Any())
            {
                // no reaction created since there wasn't anything to react to.
                result = new EvaluateReactionRegistrationResult(null, new List <RecordSetHandlingMemento>());
            }
            else
            {
                var streamRepresentationToInternalRecordIdsMap =
                    streamRepToHandledDependencyRecordIdToBeIncludedMap.ToDictionary(
                        k => k.Key,
                        v => (IReadOnlyList <long>)v.Value.ToList());

                var reactionTags =
                    (operation.ReactionRegistration.Tags ?? new List <NamedValue <string> >())
                    .Union(
                        new[]
                {
                    new NamedValue <string>(
                        TagNames.ReactionRegistrationId,
                        operation.ReactionRegistration.Id),
                })
                    .ToList();

                var reactionEvent = new ReactionEvent(
                    reactionId,
                    operation.ReactionRegistration.Id,
                    operation.ReactionRegistration.ReactionContext,
                    streamRepresentationToInternalRecordIdsMap,
                    DateTime.UtcNow,
                    reactionTags);

                result = new EvaluateReactionRegistrationResult(reactionEvent, handledRecordMementos);
            }

            return(result);
        }