"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const cdk_1 = require("@aws-cdk/cdk");
const cloudwatch_generated_1 = require("./cloudwatch.generated");
const util_statistic_1 = require("./util.statistic");
/**
 * Comparison operator for evaluating alarms
 */
var ComparisonOperator;
(function (ComparisonOperator) {
    ComparisonOperator["GreaterThanOrEqualToThreshold"] = "GreaterThanOrEqualToThreshold";
    ComparisonOperator["GreaterThanThreshold"] = "GreaterThanThreshold";
    ComparisonOperator["LessThanThreshold"] = "LessThanThreshold";
    ComparisonOperator["LessThanOrEqualToThreshold"] = "LessThanOrEqualToThreshold";
})(ComparisonOperator = exports.ComparisonOperator || (exports.ComparisonOperator = {}));
const OPERATOR_SYMBOLS = {
    GreaterThanOrEqualToThreshold: '>=',
    GreaterThanThreshold: '>',
    LessThanThreshold: '<',
    LessThanOrEqualToThreshold: '>=',
};
/**
 * Specify how missing data points are treated during alarm evaluation
 */
var TreatMissingData;
(function (TreatMissingData) {
    /**
     * Missing data points are treated as breaching the threshold
     */
    TreatMissingData["Breaching"] = "breaching";
    /**
     * Missing data points are treated as being within the threshold
     */
    TreatMissingData["NotBreaching"] = "notBreaching";
    /**
     * The current alarm state is maintained
     */
    TreatMissingData["Ignore"] = "ignore";
    /**
     * The alarm does not consider missing data points when evaluating whether to change state
     */
    TreatMissingData["Missing"] = "missing";
})(TreatMissingData = exports.TreatMissingData || (exports.TreatMissingData = {}));
/**
 * An alarm on a CloudWatch metric
 */
class Alarm extends cdk_1.Construct {
    constructor(parent, name, props) {
        super(parent, name);
        const comparisonOperator = props.comparisonOperator || ComparisonOperator.GreaterThanOrEqualToThreshold;
        const alarm = new cloudwatch_generated_1.cloudformation.AlarmResource(this, 'Resource', Object.assign({ 
            // Meta
            alarmDescription: props.alarmDescription, alarmName: props.alarmName, 
            // Evaluation
            comparisonOperator, threshold: props.threshold, evaluateLowSampleCountPercentile: props.evaluateLowSampleCountPercentile, evaluationPeriods: props.evaluationPeriods, treatMissingData: props.treatMissingData, 
            // Actions
            actionsEnabled: props.actionsEnabled, alarmActions: new cdk_1.Token(() => this.alarmActions), insufficientDataActions: new cdk_1.Token(() => this.insufficientDataActions), okActions: new cdk_1.Token(() => this.okActions) }, metricJson(props.metric)));
        this.alarmArn = alarm.alarmArn;
        this.metric = props.metric;
        this.annotation = {
            // tslint:disable-next-line:max-line-length
            label: `${this.metric.label || this.metric.metricName} ${OPERATOR_SYMBOLS[comparisonOperator]} ${props.threshold} for ${props.evaluationPeriods} datapoints within ${describePeriod(props.evaluationPeriods * props.metric.periodSec)}`,
            value: props.threshold,
        };
    }
    /**
     * Trigger this action if the alarm fires
     *
     * Typically the ARN of an SNS topic or ARN of an AutoScaling policy.
     */
    onAlarm(...actions) {
        if (this.alarmActions === undefined) {
            this.alarmActions = [];
        }
        this.alarmActions.push(...actions.map(a => a.alarmActionArn));
    }
    /**
     * Trigger this action if there is insufficient data to evaluate the alarm
     *
     * Typically the ARN of an SNS topic or ARN of an AutoScaling policy.
     */
    onInsufficientData(...actions) {
        if (this.insufficientDataActions === undefined) {
            this.insufficientDataActions = [];
        }
        this.insufficientDataActions.push(...actions.map(a => a.alarmActionArn));
    }
    /**
     * Trigger this action if the alarm returns from breaching state into ok state
     *
     * Typically the ARN of an SNS topic or ARN of an AutoScaling policy.
     */
    onOk(...actions) {
        if (this.okActions === undefined) {
            this.okActions = [];
        }
        this.okActions.push(...actions.map(a => a.alarmActionArn));
    }
    /**
     * Turn this alarm into a horizontal annotation
     *
     * This is useful if you want to represent an Alarm in a non-AlarmWidget.
     * An `AlarmWidget` can directly show an alarm, but it can only show a
     * single alarm and no other metrics. Instead, you can convert the alarm to
     * a HorizontalAnnotation and add it as an annotation to another graph.
     *
     * This might be useful if:
     *
     * - You want to show multiple alarms inside a single graph, for example if
     *   you have both a "small margin/long period" alarm as well as a
     *   "large margin/short period" alarm.
     *
     * - You want to show an Alarm line in a graph with multiple metrics in it.
     */
    toAnnotation() {
        return this.annotation;
    }
}
exports.Alarm = Alarm;
/**
 * Return a human readable string for this period
 *
 * We know the seconds are always one of a handful of allowed values.
 */
function describePeriod(seconds) {
    if (seconds === 60) {
        return '1 minute';
    }
    if (seconds === 1) {
        return '1 second';
    }
    if (seconds > 60) {
        return (seconds / 60) + ' minutes';
    }
    return seconds + ' seconds';
}
/**
 * Return the JSON structure which represents the given metric in an alarm.
 */
function metricJson(metric) {
    const stat = util_statistic_1.parseStatistic(metric.statistic);
    const dims = metric.dimensionsAsList();
    return {
        dimensions: dims.length > 0 ? dims : undefined,
        namespace: metric.namespace,
        metricName: metric.metricName,
        period: metric.periodSec,
        statistic: stat.type === 'simple' ? stat.statistic : undefined,
        extendedStatistic: stat.type === 'percentile' ? 'p' + stat.percentile : undefined,
        unit: metric.unit
    };
}
//# sourceMappingURL=data:application/json;base64, 