private static void LogResults(
            [NotNull] IEnumerable <QualitySpecificationElement> qualitySpecificationElements,
            [NotNull] IssueProcessor issueProcessor,
            int qualityConditionCount, int datasetCount,
            bool fulfilled, bool cancelled,
            [CanBeNull] IExceptionStatistics exceptionStatistics)
        {
            using (_msg.IncrementIndentation("Quality verification finished"))
            {
                _msg.InfoFormat("Number of verified datasets: {0:N0}", datasetCount);
                using (_msg.IncrementIndentation("Number of verified quality conditions: {0:N0}",
                                                 qualityConditionCount))
                {
                    LogVerifiedConditions(qualitySpecificationElements,
                                          issueProcessor,
                                          exceptionStatistics);
                }

                _msg.InfoFormat("Warning count: {0:N0}", issueProcessor.WarningCount);
                _msg.InfoFormat("Error count: {0:N0}", issueProcessor.ErrorCount);

                if (issueProcessor.RowsWithStopConditionsCount > 0)
                {
                    _msg.WarnFormat("Number of features with stop errors: {0:N0}",
                                    issueProcessor.RowsWithStopConditionsCount);
                }

                if (exceptionStatistics != null &&
                    exceptionStatistics.TablesWithNonUniqueKeys.Count > 0)
                {
                    _msg.WarnFormat(
                        "Number of tables with non-unique keys referenced by exception objects: {0}",
                        exceptionStatistics.TablesWithNonUniqueKeys.Count);
                }

                if (cancelled)
                {
                    _msg.Warn("The quality verification was cancelled");
                }
                else if (fulfilled)
                {
                    _msg.Info("The quality specification is fulfilled");
                }
                else
                {
                    _msg.Warn("The quality specification is not fulfilled");
                }
            }
        }
        private static void LogVerifiedConditions(
            [NotNull] IEnumerable <QualitySpecificationElement> qualitySpecificationElements,
            [NotNull] IssueProcessor issueProcessor,
            [CanBeNull] IExceptionStatistics exceptionStatistics)
        {
            List <QualitySpecificationElement> elementsWithNoCategory;
            Dictionary <DataQualityCategory, List <QualitySpecificationElement> >
            elementsByCategory =
                GetElementsByCategory(qualitySpecificationElements,
                                      out elementsWithNoCategory);

            var categories = new List <DataQualityCategory>(elementsByCategory.Keys);

            categories.Sort(new DataQualityCategoryComparer());

            foreach (DataQualityCategory category in categories)
            {
                using (_msg.IncrementIndentation("Category '{0}':", category.Name))
                {
                    List <QualitySpecificationElement> elementsForCategory =
                        elementsByCategory[category];

                    elementsForCategory.Sort(CompareElements);

                    LogElements(elementsForCategory, issueProcessor, exceptionStatistics);
                }
            }

            if (elementsWithNoCategory.Count > 0)
            {
                using (_msg.IncrementIndentation("No category:"))
                {
                    elementsWithNoCategory.Sort(CompareElements);

                    LogElements(elementsWithNoCategory, issueProcessor, exceptionStatistics);
                }
            }
        }
        private static void LogElements(
            [NotNull] IEnumerable <QualitySpecificationElement> qualitySpecificationElements,
            [NotNull] IssueProcessor issueProcessor,
            [CanBeNull] IExceptionStatistics exceptionStatistics)
        {
            foreach (QualitySpecificationElement element in qualitySpecificationElements)
            {
                QualityCondition qualityCondition = element.QualityCondition;

                int exceptionCount;
                int issueCount = issueProcessor.GetIssueCount(qualityCondition,
                                                              out exceptionCount);

                var sb = new StringBuilder(qualityCondition.Name);

                if (issueCount > 0)
                {
                    sb.AppendFormat(element.AllowErrors
                                                                ? " - warnings: {0}"
                                                                : " - errors: {0}",
                                    issueCount);
                }

                if (exceptionCount > 0)
                {
                    sb.AppendFormat(" - exceptions: {0}", exceptionCount);
                }

                if (issueCount > 0)
                {
                    _msg.Warn(sb.ToString());
                }
                else
                {
                    _msg.Info(sb.ToString());
                }

                if (exceptionStatistics != null)
                {
                    IQualityConditionExceptionStatistics conditionStatistics =
                        exceptionStatistics.GetQualityConditionStatistics(qualityCondition);

                    if (conditionStatistics != null)
                    {
                        if (conditionStatistics.UnknownTableNames.Count > 0)
                        {
                            using (_msg.IncrementIndentation())
                            {
                                _msg.Warn(
                                    "Exception objects were ignored for this condition due to unknown table names:");
                                foreach (string tableName in conditionStatistics.UnknownTableNames)
                                {
                                    _msg.WarnFormat(
                                        "- {0}: used in {1} exception object(s)",
                                        tableName,
                                        conditionStatistics
                                        .GetExceptionObjectsInvolvingUnknownTableName(
                                            tableName).Count);
                                }
                            }
                        }
                    }
                }
            }
        }