class AggregatingToolScanManager implements ToolScanManager {

    public ToolExecutionCheckStatus checkTool(Tool tool, String tag) {
        Optional<ToolVersionScanResult> versionScanOp = toolManager.loadToolVersionScan(tool.getId(), tag);

        int graceHours = preferenceManager.getPreference(SystemPreferences.DOCKER_SECURITY_TOOL_GRACE_HOURS);

        boolean isGracePeriodOrWhiteList = versionScanOp.isPresent() &&
                (gracePeriodIsActive(versionScanOp.get(), graceHours) || versionScanOp.get().isFromWhiteList());

        if (isGracePeriodOrWhiteList) {
            LOGGER.debug("Tool: " + tool.getId() + " version: " + tag +
                    " is from White list or Grace period still active! Proceed with running!");
            return ToolExecutionCheckStatus.success();
        }

        boolean denyNotScanned = preferenceManager.getPreference(
                SystemPreferences.DOCKER_SECURITY_TOOL_POLICY_DENY_NOT_SCANNED);
        if (denyNotScanned && (!versionScanOp.isPresent()
                || versionScanOp.get().getStatus() == ToolScanStatus.NOT_SCANNED
                || versionScanOp.get().getSuccessScanDate() == null)) {
            return ToolExecutionCheckStatus.fail("Tool is not scanned.");
        }

        if (versionScanOp.isPresent()) {
            ToolVersionScanResult toolVersionScanResult = versionScanOp.get();
            Map<VulnerabilitySeverity, Integer> severityCounters = toolVersionScanResult.getVulnerabilities().stream()
                    .collect(
                        HashMap::new,
                        (map, v) -> {
                            if (map.containsKey(v.getSeverity())) {
                                map.put(v.getSeverity(), map.get(v.getSeverity()) + 1);
                            } else {
                                map.put(v.getSeverity(), 1);
                            }
                        },
                        (map1, map2) -> map1.keySet().forEach(k -> map1.merge(k, map2.get(k), (a, b) -> a + b)));
            int maxCriticalVulnerabilities = preferenceManager.getPreference(
                    SystemPreferences.DOCKER_SECURITY_TOOL_POLICY_MAX_CRITICAL_VULNERABILITIES);
            if (maxCriticalVulnerabilities != DISABLED &&
                    maxCriticalVulnerabilities < severityCounters.getOrDefault(VulnerabilitySeverity.Critical, 0)) {
                return ToolExecutionCheckStatus.fail("Max number of CRITICAL vulnerabilities is reached");
            }
            int maxHighVulnerabilities = preferenceManager.getPreference(
                    SystemPreferences.DOCKER_SECURITY_TOOL_POLICY_MAX_HIGH_VULNERABILITIES);
            if (maxHighVulnerabilities != DISABLED &&
                    maxHighVulnerabilities < severityCounters.getOrDefault(VulnerabilitySeverity.High, 0)) {
                return ToolExecutionCheckStatus.fail("Max number of HIGH vulnerabilities is reached");
            }
            int maxMediumVulnerabilities = preferenceManager.getPreference(
                    SystemPreferences.DOCKER_SECURITY_TOOL_POLICY_MAX_MEDIUM_VULNERABILITIES);
            if (maxMediumVulnerabilities != DISABLED &&
                    maxMediumVulnerabilities < severityCounters.getOrDefault(VulnerabilitySeverity.Medium, 0)) {
                return ToolExecutionCheckStatus.fail("Max number of MEDIUM vulnerabilities is reached");
            }

            LOGGER.debug("Tool: {} version: {} Check tool os version.", tool.getId(), tag);
            if (toolVersionScanResult.getToolOSVersion() != null
                    && !toolManager.isToolOSVersionAllowed(toolVersionScanResult.getToolOSVersion())) {
                LOGGER.warn("Tool: {} version: {}. Tool os version isn't allowed, check preference {} ! Cancel run.",
                        tool.getId(), tag, SystemPreferences.DOCKER_SECURITY_TOOL_OS.getKey());
                return ToolExecutionCheckStatus.fail("This type of OS is not supported.");
            }
        }
        return ToolExecutionCheckStatus.success();
    }

}