class AlertingService {

    public void checkMetricAlert(String centralDisplay, String agentRollupId,
            String agentRollupDisplay, AlertConfig alertConfig, MetricCondition metricCondition,
            long endTime) throws Exception {
        long startTime = endTime - SECONDS.toMillis(metricCondition.getTimePeriodSeconds());
        Number value =
                metricService.getMetricValue(agentRollupId, metricCondition, startTime, endTime);
        if (value == null) {
            // cannot calculate due to no data, e.g. error rate (but not error count, which can be
            // calculated - zero - when no data)
            return;
        }
        boolean currentlyTriggered;
        if (metricCondition.getLowerBoundThreshold()) {
            currentlyTriggered = value.doubleValue() <= metricCondition.getThreshold();
        } else {
            currentlyTriggered = value.doubleValue() >= metricCondition.getThreshold();
        }
        AlertCondition alertCondition = alertConfig.getCondition();
        OpenIncident openIncident = incidentRepository.readOpenIncident(agentRollupId,
                alertCondition, alertConfig.getSeverity());
        if (openIncident != null && !currentlyTriggered) {
            // TODO don't close if no data and no heartbeat?
            resolveIncident(centralDisplay, agentRollupId, agentRollupDisplay, alertConfig,
                    metricCondition, endTime, alertCondition, openIncident);
        } else if (openIncident == null && currentlyTriggered) {
            // don't open if min transaction count is not met
            if (hasMinTransactionCount(metricCondition.getMetric())) {
                long minTransactionCount = metricCondition.getMinTransactionCount();
                if (minTransactionCount != 0) {
                    long transactionCount = metricService.getTransactionCount(agentRollupId,
                            metricCondition.getTransactionType(),
                            Strings.emptyToNull(metricCondition.getTransactionName()), startTime,
                            endTime);
                    if (transactionCount < minTransactionCount) {
                        return;
                    }
                }
            }
            openIncident(centralDisplay, agentRollupId, agentRollupDisplay, alertConfig,
                    metricCondition, endTime, alertCondition);
        }
    }

    public  AlertingService(ConfigRepository configRepository, IncidentRepository incidentRepository,
            AggregateRepository aggregateRepository, GaugeValueRepository gaugeValueRepository,
            TraceRepository traceRepository, RollupLevelService rollupLevelService,
            MailService mailService, HttpClient httpClient,
            LockSet<IncidentKey> openingIncidentLockSet,
            LockSet<IncidentKey> resolvingIncidentLockSet, Clock clock);

}