private static IssueProcessor CreateIssueProcessor(
            [NotNull] TestContainer testContainer,
            [NotNull] IIssueWriter issueWriter,
            [CanBeNull] AreaOfInterest areaOfInterest,
            [CanBeNull] IExceptionObjectRepository exceptionObjectRepository,
            [NotNull] IDictionary <ITest, QualitySpecificationElement> elementsByTest)
        {
            IGeometry testPerimeter = GetTestPerimeter(areaOfInterest, testContainer);

            return(new IssueProcessor(
                       issueWriter,
                       elementsByTest,
                       testPerimeter,
                       exceptionObjectRepository?.ExceptionObjectEvaluator));
        }
        /// <summary>
        /// Verifies the specified object classes.
        /// </summary>
        /// <param name="qualitySpecification">The quality specification to verify.</param>
        /// <param name="datasetContext">The model context.</param>
        /// <param name="datasetResolver">The resolver for getting the object dataset based on a table name, in the context of a quality condition</param>
        /// <param name="issueRepository">The issue repository.</param>
        /// <param name="exceptionObjectRepository">The exception object repository</param>
        /// <param name="tileSize">Tile size for the quality verification.</param>
        /// <param name="getKeyFieldName">Function for getting the key field name for an object dataset</param>
        /// <param name="areaOfInterest">The area of interest for the verification (optional).</param>
        /// <param name="trackCancel">The cancel tracker.</param>
        /// <returns></returns>
        public bool Verify(
            [NotNull] QualitySpecification qualitySpecification,
            [NotNull] IDatasetContext datasetContext,
            [NotNull] IQualityConditionObjectDatasetResolver datasetResolver,
            [CanBeNull] IIssueRepository issueRepository,
            [CanBeNull] IExceptionObjectRepository exceptionObjectRepository,
            double tileSize,
            [CanBeNull] Func <IObjectDataset, string> getKeyFieldName,
            [CanBeNull] AreaOfInterest areaOfInterest,
            [CanBeNull] ITrackCancel trackCancel)
        {
            int errorCount;
            int warningCount;
            int rowCountWithStopConditions;

            return(Verify(qualitySpecification, datasetContext, datasetResolver,
                          issueRepository, exceptionObjectRepository, tileSize,
                          getKeyFieldName, areaOfInterest, trackCancel,
                          out errorCount,
                          out warningCount,
                          out rowCountWithStopConditions));
        }
        /// <summary>
        /// Verifies the specified object classes.
        /// </summary>
        /// <param name="qualitySpecification">The quality specification to verify.</param>
        /// <param name="datasetContext">The model context.</param>
        /// <param name="datasetResolver">The resolver for getting the object dataset based on a table name, in the context of a quality condition</param>
        /// <param name="issueRepository">The issue repository.</param>
        /// <param name="exceptionObjectRepository">The exception object repository</param>
        /// <param name="tileSize">Tile size for the quality verification.</param>
        /// <param name="getKeyFieldName">Function for getting the key field name for an object dataset</param>
        /// <param name="areaOfInterest">The test run perimeter (optional).</param>
        /// <param name="trackCancel">The cancel tracker.</param>
        /// <param name="errorCount">The number of (hard) errors.</param>
        /// <param name="warningCount">The number of warnings.</param>
        /// <param name="rowCountWithStopConditions">The number of rows for which a stop condition was violated - those rows may not be completely tested.</param>
        /// <returns></returns>
        public bool Verify([NotNull] QualitySpecification qualitySpecification,
                           [NotNull] IDatasetContext datasetContext,
                           [NotNull] IQualityConditionObjectDatasetResolver datasetResolver,
                           [CanBeNull] IIssueRepository issueRepository,
                           [CanBeNull] IExceptionObjectRepository exceptionObjectRepository,
                           double tileSize,
                           [CanBeNull] Func <IObjectDataset, string> getKeyFieldName,
                           [CanBeNull] AreaOfInterest areaOfInterest,
                           [CanBeNull] ITrackCancel trackCancel,
                           out int errorCount,
                           out int warningCount,
                           out int rowCountWithStopConditions)
        {
            Assert.ArgumentNotNull(qualitySpecification, nameof(qualitySpecification));
            Assert.ArgumentNotNull(datasetContext, nameof(datasetContext));
            Assert.ArgumentNotNull(datasetResolver, nameof(datasetResolver));
            Assert.ArgumentCondition(tileSize > 0, "Invalid tile size: {0}", tileSize);

            _verificationReportBuilder.BeginVerification(areaOfInterest);

            IEnumerable <QualitySpecificationElement> elements =
                GetOrderedElements(qualitySpecification).ToList();

            IDictionary <ITest, QualitySpecificationElement> elementsByTest;
            IEnumerable <ITest> tests =
                CreateTests(elements, datasetContext, out elementsByTest).ToList();

            var qualityConditionCount = 0;

            foreach (QualitySpecificationElement element in elements)
            {
                qualityConditionCount++;
                _verificationReportBuilder.AddVerifiedQualityCondition(element);
            }

            var datasetCount = 0;

            foreach (Dataset dataset in
                     GetVerifiedDatasets(qualitySpecification, datasetContext))
            {
                datasetCount++;
                _verificationReportBuilder.AddVerifiedDataset(dataset);
            }

            Stopwatch watch = _msg.DebugStartTiming();

            LogTests(tests, elementsByTest);

            TestContainer testContainer = CreateTestContainer(tests, tileSize);

            LogBeginVerification(qualitySpecification, tileSize, areaOfInterest);

            IssueProcessor    issueProcessor;
            ProgressProcessor progressProcessor;

            using (var issueWriter = new BufferedIssueWriter(_verificationReportBuilder,
                                                             datasetContext, datasetResolver,
                                                             issueRepository,
                                                             getKeyFieldName))
            {
                issueProcessor = CreateIssueProcessor(testContainer, issueWriter,
                                                      areaOfInterest, exceptionObjectRepository,
                                                      elementsByTest);

                progressProcessor = new ProgressProcessor(testContainer, elementsByTest,
                                                          trackCancel);

                testContainer.QaError += (sender, args) => issueProcessor.Process(args);

                testContainer.TestingRow +=
                    delegate(object o, RowEventArgs args)
                {
                    if (issueProcessor.HasStopCondition(args.Row))
                    {
                        args.Cancel = true;
                    }
                };

                testContainer.ProgressChanged +=
                    (sender, args) => progressProcessor.Process(args);

                // run the tests
                TestExecutionUtils.Execute(testContainer, areaOfInterest);
            }

            _verificationReportBuilder.AddRowsWithStopConditions(
                issueProcessor.GetRowsWithStopConditions());

            if (exceptionObjectRepository != null)
            {
                _verificationReportBuilder.AddExceptionStatistics(
                    exceptionObjectRepository.ExceptionStatistics);
            }

            _verificationReportBuilder.EndVerification(progressProcessor.Cancelled);

            _msg.DebugStopTiming(watch, "Verification");

            errorCount   = issueProcessor.ErrorCount;
            warningCount = issueProcessor.WarningCount;
            rowCountWithStopConditions = issueProcessor.RowsWithStopConditionsCount;

            bool fulfilled = errorCount == 0 && !progressProcessor.Cancelled;

            LogResults(elements, issueProcessor,
                       qualityConditionCount, datasetCount,
                       fulfilled, progressProcessor.Cancelled,
                       exceptionObjectRepository?.ExceptionStatistics);

            return(fulfilled);
        }