"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubtitleRegionContainer = exports.SubtitleRegionContainerManager = exports.SubtitleLabel = exports.SubtitleOverlay = void 0;
var container_1 = require("./container");
var label_1 = require("./label");
var controlbar_1 = require("./controlbar");
var eventdispatcher_1 = require("../eventdispatcher");
var dom_1 = require("../dom");
var i18n_1 = require("../localization/i18n");
var vttutils_1 = require("../vttutils");
/**
 * Overlays the player to display subtitles.
 *
 * @category Components
 */
var SubtitleOverlay = exports.SubtitleOverlay = /** @class */ (function (_super) {
    __extends(SubtitleOverlay, _super);
    function SubtitleOverlay(config) {
        if (config === void 0) { config = {}; }
        var _this = _super.call(this, config) || this;
        _this.preprocessLabelEventCallback = new eventdispatcher_1.EventDispatcher();
        _this.FONT_SIZE_FACTOR = 1;
        // The number of rows in a cea608 grid
        _this.CEA608_NUM_ROWS = SubtitleOverlay.DEFAULT_CEA608_NUM_ROWS;
        // The number of columns in a cea608 grid
        _this.CEA608_NUM_COLUMNS = SubtitleOverlay.DEFAULT_CEA608_NUM_COLUMNS;
        // The offset in percent for one column (which is also the width of a column)
        _this.CEA608_COLUMN_OFFSET = 100 / _this.CEA608_NUM_COLUMNS;
        _this.cea608Enabled = false;
        _this.filterFontSizeOptions = function (listItem) {
            if (_this.cea608Enabled && listItem.key !== null) {
                var percent = parseInt(listItem.key, 10);
                return !isNaN(percent) && percent <= 200;
            }
            return true;
        };
        _this.recalculateCEAGrid();
        _this.previewSubtitleActive = false;
        _this.previewSubtitle = new SubtitleLabel({ text: i18n_1.i18n.getLocalizer('subtitle.example') });
        _this.config = _this.mergeConfig(config, {
            cssClass: 'ui-subtitle-overlay',
        }, _this.config);
        return _this;
    }
    SubtitleOverlay.prototype.configure = function (player, uimanager) {
        var _this = this;
        _super.prototype.configure.call(this, player, uimanager);
        var subtitleManager = new ActiveSubtitleManager();
        this.subtitleManager = subtitleManager;
        this.subtitleContainerManager = new SubtitleRegionContainerManager(this);
        player.on(player.exports.PlayerEvent.CueEnter, function (event) {
            var label = _this.generateLabel(event);
            subtitleManager.cueEnter(event, label);
            _this.preprocessLabelEventCallback.dispatch(event, label);
            if (_this.previewSubtitleActive) {
                _this.subtitleContainerManager.removeLabel(_this.previewSubtitle);
            }
            _this.show();
            _this.subtitleContainerManager.addLabel(label, _this.getDomElement().size());
            _this.updateComponents();
            if (uimanager.getConfig().forceSubtitlesIntoViewContainer) {
                _this.handleSubtitleCropping(label);
            }
        });
        player.on(player.exports.PlayerEvent.CueUpdate, function (event) {
            var label = _this.generateLabel(event);
            var labelToReplace = subtitleManager.cueUpdate(event, label);
            _this.preprocessLabelEventCallback.dispatch(event, label);
            if (labelToReplace) {
                _this.subtitleContainerManager.replaceLabel(labelToReplace, label);
            }
            if (uimanager.getConfig().forceSubtitlesIntoViewContainer) {
                _this.handleSubtitleCropping(label);
            }
        });
        player.on(player.exports.PlayerEvent.CueExit, function (event) {
            var labelToRemove = subtitleManager.cueExit(event);
            if (labelToRemove) {
                _this.subtitleContainerManager.removeLabel(labelToRemove);
                _this.updateComponents();
            }
            if (!subtitleManager.hasCues) {
                if (!_this.previewSubtitleActive) {
                    _this.hide();
                }
                else {
                    _this.subtitleContainerManager.addLabel(_this.previewSubtitle);
                    _this.updateComponents();
                }
            }
        });
        var subtitleClearHandler = function () {
            _this.hide();
            _this.subtitleContainerManager.clear();
            subtitleManager.clear();
            _this.removeComponents();
            _this.updateComponents();
        };
        var clearInactiveCues = function () {
            var removedActiveCues = subtitleManager.clearInactiveCues(player.getCurrentTime());
            removedActiveCues.forEach(function (toRemove) {
                _this.subtitleContainerManager.removeLabel(toRemove.label);
            });
            _this.updateComponents();
        };
        player.on(player.exports.PlayerEvent.AudioChanged, subtitleClearHandler);
        player.on(player.exports.PlayerEvent.SubtitleDisabled, subtitleClearHandler);
        player.on(player.exports.PlayerEvent.Seeked, clearInactiveCues);
        player.on(player.exports.PlayerEvent.TimeShifted, clearInactiveCues);
        player.on(player.exports.PlayerEvent.PlaybackFinished, subtitleClearHandler);
        player.on(player.exports.PlayerEvent.SourceUnloaded, subtitleClearHandler);
        uimanager.onComponentShow.subscribe(function (component) {
            if (component instanceof controlbar_1.ControlBar) {
                _this.getDomElement().addClass(_this.prefixCss(SubtitleOverlay.CLASS_CONTROLBAR_VISIBLE));
            }
        });
        uimanager.onComponentHide.subscribe(function (component) {
            if (component instanceof controlbar_1.ControlBar) {
                _this.getDomElement().removeClass(_this.prefixCss(SubtitleOverlay.CLASS_CONTROLBAR_VISIBLE));
            }
        });
        this.configureCea608Captions(player, uimanager);
        // Init
        subtitleClearHandler();
    };
    SubtitleOverlay.prototype.setFontSizeFactor = function (factor) {
        // We only allow range from 50% to 200% as suggested by spec
        // https://www.ecfr.gov/current/title-47/part-79/section-79.103#p-79.103(c)(4)
        this.FONT_SIZE_FACTOR = Math.max(0.5, Math.min(2.0, factor));
        this.recalculateCEAGrid();
    };
    SubtitleOverlay.prototype.recalculateCEAGrid = function () {
        // Needs to get recalculated in case the font size will change also we need to floor this
        // to always align to the whole number represented in styles.
        this.CEA608_NUM_ROWS = Math.floor(SubtitleOverlay.DEFAULT_CEA608_NUM_ROWS / Math.max(this.FONT_SIZE_FACTOR, 1));
        this.CEA608_NUM_COLUMNS = Math.floor(SubtitleOverlay.DEFAULT_CEA608_NUM_COLUMNS / this.FONT_SIZE_FACTOR);
        this.CEA608_COLUMN_OFFSET = 100 / this.CEA608_NUM_COLUMNS;
    };
    SubtitleOverlay.prototype.detectCroppedSubtitleLabel = function (labelElement) {
        var parent = this.getDomElement().get(0);
        var childRect = labelElement.getBoundingClientRect();
        var parentRect = parent.getBoundingClientRect();
        return {
            top: childRect.top < parentRect.top,
            right: childRect.right > parentRect.right,
            bottom: childRect.bottom > parentRect.bottom,
            left: childRect.left < parentRect.left,
        };
    };
    SubtitleOverlay.prototype.handleSubtitleCropping = function (label) {
        var labelDomElement = label.getDomElement();
        var cropDetection = this.detectCroppedSubtitleLabel(labelDomElement.get(0));
        if (cropDetection.top) {
            labelDomElement.css('top', '0');
            labelDomElement.removeCss('bottom');
        }
        if (cropDetection.right) {
            labelDomElement.css('right', '0');
            labelDomElement.removeCss('left');
        }
        if (cropDetection.bottom) {
            labelDomElement.css('bottom', '0');
            labelDomElement.removeCss('top');
        }
        if (cropDetection.left) {
            labelDomElement.css('left', '0');
            labelDomElement.removeCss('right');
        }
    };
    SubtitleOverlay.prototype.resolveRowNumber = function (row) {
        // In case there is a font size factor and the row from event would overflow
        // we need to apply an offset so it gets rendered to visible area.
        if (this.FONT_SIZE_FACTOR > 1 && row > this.CEA608_NUM_ROWS) {
            var rowDelta = SubtitleOverlay.DEFAULT_CEA608_NUM_ROWS - this.CEA608_NUM_ROWS;
            return row - rowDelta;
        }
        return row;
    };
    SubtitleOverlay.prototype.generateLabel = function (event) {
        var _a;
        // Sanitize cue data (must be done before the cue ID is generated in subtitleManager.cueEnter / update)
        var region = event.region;
        // Sometimes the positions are undefined, we assume them to be zero.
        // We need to keep track of the original row position in case of recalculation.
        var originalRowNumber = ((_a = event.position) === null || _a === void 0 ? void 0 : _a.row) || 0;
        if (event.position) {
            event.position.row = this.resolveRowNumber(event.position.row) || 0;
            event.position.column = event.position.column || 0;
            region = region || "cea608-row-".concat(event.position.row);
        }
        var label = new SubtitleLabel({
            // Prefer the HTML subtitle text if set, else try generating a image tag as string from the image attribute,
            // else use the plain text
            text: event.html || ActiveSubtitleManager.generateImageTagText(event.image) || event.text,
            vtt: event.vtt,
            region: region,
            regionStyle: event.regionStyle,
            originalRowPosition: originalRowNumber,
        });
        return label;
    };
    SubtitleOverlay.prototype.resolveFontSizeFactor = function (value) {
        return parseInt(value) / 100;
    };
    SubtitleOverlay.prototype.updateRegionRowPosition = function (r) {
        var _a;
        var element = r.getDomElement().get()[0];
        var label = r.getComponents()[0];
        if (!element || !label) {
            return;
        }
        var rowClassList = element.classList;
        var originalRow = (_a = label.getConfig()) === null || _a === void 0 ? void 0 : _a.originalRowPosition;
        var rowClassRegex = /subtitle-position-cea608-row-(\d+)/;
        var currentClass = Array.from(rowClassList).find(function (cls) { return rowClassRegex.test(cls); });
        if (!currentClass) {
            return;
        }
        var match = rowClassRegex.exec(currentClass);
        var rowNumber = match ? parseInt(match[1], 10) : null;
        var newRowNum = this.resolveRowNumber(originalRow !== null && originalRow !== void 0 ? originalRow : rowNumber);
        var newClass = currentClass.replace(rowClassRegex, "subtitle-position-cea608-row-".concat(newRowNum));
        rowClassList.replace(currentClass, newClass);
    };
    SubtitleOverlay.prototype.configureCea608Captions = function (player, uimanager) {
        var _this = this;
        // The calculated font size
        var fontSize = 0;
        // The required letter spacing spread the text characters evenly across the grid
        var fontLetterSpacing = 0;
        // Flag telling if a font size calculation is required of if the current values are valid
        var fontSizeCalculationRequired = true;
        // The ratio of the caption window/row height that is used as padding to make the window enclose the caption
        var windowPaddingRatio = 0.2;
        var windowPadding;
        // Flag telling if the CEA-608 mode is enabled
        this.cea608Enabled = false;
        var settingsManager = uimanager.getSubtitleSettingsManager();
        if (settingsManager.fontSize.value != null) {
            var fontSizeFactorSettings = this.resolveFontSizeFactor(settingsManager.fontSize.value);
            this.setFontSizeFactor(fontSizeFactorSettings);
        }
        settingsManager.fontSize.onChanged.subscribe(function (_sender, property) {
            if (property.isSet()) {
                // We need to convert from percent
                var factorValue = _this.resolveFontSizeFactor(property.value);
                _this.setFontSizeFactor(factorValue);
            }
            else {
                _this.setFontSizeFactor(1);
            }
            updateCEA608FontSize();
        });
        var updateCEA608FontSize = function () {
            var dummyLabel = new SubtitleLabel({ text: 'X' });
            dummyLabel.getDomElement().css({
                // By using a large font size we do not need to use multiple letters and can get still an
                // accurate measurement even though the returned size is an integer value
                'font-size': '200px',
                'line-height': '200px',
                'visibility': 'hidden',
            });
            _this.addComponent(dummyLabel);
            _this.updateComponents();
            _this.show();
            var dummyLabelCharWidth = dummyLabel.getDomElement().width() * _this.FONT_SIZE_FACTOR;
            var dummyLabelCharHeight = dummyLabel.getDomElement().height() * _this.FONT_SIZE_FACTOR;
            var fontSizeRatio = (dummyLabelCharWidth / dummyLabelCharHeight);
            _this.removeComponent(dummyLabel);
            _this.updateComponents();
            if (!_this.subtitleManager.hasCues) {
                _this.hide();
            }
            // We subtract 1px here to avoid line breaks at the right border of the subtitle overlay that can happen
            // when texts contain whitespaces. It's probably some kind of pixel rounding issue in the browser's
            // layouting, but the actual reason could not be determined. Aiming for a target width - 1px would work in
            // most browsers, but Safari has a "quantized" font size rendering with huge steps in between so we need
            // to subtract some more pixels to avoid line breaks there as well.
            var overlayElement = _this.getDomElement();
            var subtitleOverlayWidth = overlayElement.width() - 10;
            var subtitleOverlayHeight = overlayElement.height();
            // The size ratio of the letter grid
            var fontGridSizeRatio = (dummyLabelCharWidth * _this.CEA608_NUM_COLUMNS) /
                (dummyLabelCharHeight * _this.CEA608_NUM_ROWS);
            // The size ratio of the available space for the grid
            var subtitleOverlaySizeRatio = subtitleOverlayWidth / subtitleOverlayHeight;
            var newRowHeight = 0;
            if (subtitleOverlaySizeRatio > fontGridSizeRatio) {
                // When the available space is wider than the text grid, the font size is simply
                // determined by the height of the available space.
                newRowHeight = subtitleOverlayHeight / _this.CEA608_NUM_ROWS;
                fontSize = newRowHeight * (1 - windowPaddingRatio);
                // Calculate the additional letter spacing required to evenly spread the text across the grid's width
                var gridSlotWidth = subtitleOverlayWidth / _this.CEA608_NUM_COLUMNS;
                var fontCharWidth = fontSize * fontSizeRatio;
                fontLetterSpacing = Math.max(gridSlotWidth - fontCharWidth, 0);
            }
            else {
                // When the available space is not wide enough, texts would vertically overlap if we take
                // the height as a base for the font size, so we need to limit the height. We do that
                // by determining the font size by the width of the available space.
                newRowHeight = subtitleOverlayWidth / _this.CEA608_NUM_COLUMNS / fontSizeRatio;
                fontSize = newRowHeight * (1 - windowPaddingRatio);
                fontLetterSpacing = 0;
            }
            windowPadding = newRowHeight * windowPaddingRatio;
            // Update row position of regions
            var regions = _this.getComponents();
            regions.forEach(function (r) {
                if (r instanceof SubtitleRegionContainer) {
                    _this.updateRegionRowPosition(r);
                }
            });
            // Update the CSS custom property on the overlay DOM element
            overlayElement.get().forEach(function (el) {
                el.style.setProperty("--cea608-row-height", "".concat(newRowHeight, "px"));
            });
            // Update font-size of all active subtitle labels
            var updateLabel = function (label) {
                var isLargerFontSize = _this.FONT_SIZE_FACTOR > 1;
                label.getDomElement().css({
                    'font-size': "".concat(fontSize, "px"),
                    'line-height': "".concat(fontSize, "px"),
                    'letter-spacing': "".concat(isLargerFontSize ? 0 : fontLetterSpacing, "px"),
                    'white-space': "".concat(isLargerFontSize ? 'nowrap' : 'normal'),
                    'left': isLargerFontSize && SubtitleOverlay.DEFAULT_CAPTION_LEFT_OFFSET,
                });
                label.regionStyle = "line-height: ".concat(fontSize, "px; padding: ").concat(windowPadding / 2, "px; height: ").concat(fontSize, "px");
            };
            for (var _i = 0, _a = _this.getComponents(); _i < _a.length; _i++) {
                var childComponent = _a[_i];
                if (childComponent instanceof SubtitleRegionContainer) {
                    childComponent.getDomElement().css({
                        'line-height': "".concat(fontSize, "px"),
                        padding: "".concat(windowPadding / 2, "px"),
                        height: "".concat(fontSize, "px")
                    });
                    childComponent.getComponents().forEach(function (l) {
                        updateLabel(l);
                    });
                }
                if (childComponent instanceof SubtitleLabel) {
                    updateLabel(childComponent);
                }
            }
        };
        player.on(player.exports.PlayerEvent.PlayerResized, function () {
            if (_this.cea608Enabled) {
                updateCEA608FontSize();
            }
            else {
                fontSizeCalculationRequired = true;
            }
        });
        this.preprocessLabelEventCallback.subscribe(function (event, label) {
            var isCEA608 = event.position != null;
            if (!isCEA608) {
                // Skip all non-CEA608 cues
                return;
            }
            if (!_this.cea608Enabled) {
                _this.cea608Enabled = true;
                _this.getDomElement().addClass(_this.prefixCss(SubtitleOverlay.CLASS_CEA_608));
                // We conditionally update the font size by this flag here to avoid updating every time a subtitle
                // is added into an empty overlay. Because we reset the overlay when all subtitles are gone, this
                // would trigger an unnecessary update every time, but it's only required under certain conditions,
                // e.g. after the player size has changed.
                if (fontSizeCalculationRequired) {
                    updateCEA608FontSize();
                    fontSizeCalculationRequired = false;
                }
            }
            // We disable the grid and wrapping in case enlarged font size is used to prevent
            // line and characters overflows
            var isLargerFontSize = _this.FONT_SIZE_FACTOR > 1;
            var leftOffset = event.position.column * _this.CEA608_COLUMN_OFFSET + '%';
            if (leftOffset === '0%' || isLargerFontSize) {
                // ensure that a little of the window still shows for better readability
                leftOffset = SubtitleOverlay.DEFAULT_CAPTION_LEFT_OFFSET;
            }
            label.getDomElement().css({
                'left': leftOffset,
                'font-size': "".concat(fontSize, "px"),
                'letter-spacing': "".concat(isLargerFontSize ? 0 : fontLetterSpacing, "px"),
                'white-space': "".concat(isLargerFontSize ? 'nowrap' : 'normal'),
            });
            label.regionStyle = "line-height: ".concat(fontSize, "px; padding: ").concat(windowPadding / 2, "px; height: ").concat(fontSize, "px");
        });
        var reset = function () {
            _this.getDomElement().removeClass(_this.prefixCss(SubtitleOverlay.CLASS_CEA_608));
            _this.cea608Enabled = false;
        };
        player.on(player.exports.PlayerEvent.CueExit, function () {
            if (!_this.subtitleManager.hasCues) {
                // Disable CEA-608 mode when all subtitles are gone (to allow correct formatting and
                // display of other types of subtitles, e.g. the formatting preview subtitle)
                reset();
            }
        });
        player.on(player.exports.PlayerEvent.SourceUnloaded, reset);
        player.on(player.exports.PlayerEvent.SubtitleEnable, reset);
        player.on(player.exports.PlayerEvent.SubtitleDisabled, reset);
    };
    SubtitleOverlay.prototype.enablePreviewSubtitleLabel = function () {
        if (!this.subtitleManager.hasCues) {
            this.previewSubtitleActive = true;
            this.subtitleContainerManager.addLabel(this.previewSubtitle);
            this.updateComponents();
            this.show();
        }
    };
    SubtitleOverlay.prototype.removePreviewSubtitleLabel = function () {
        if (this.previewSubtitleActive) {
            this.previewSubtitleActive = false;
            this.subtitleContainerManager.removeLabel(this.previewSubtitle);
            this.updateComponents();
        }
    };
    SubtitleOverlay.CLASS_CONTROLBAR_VISIBLE = 'controlbar-visible';
    SubtitleOverlay.CLASS_CEA_608 = 'cea608';
    SubtitleOverlay.DEFAULT_CEA608_NUM_ROWS = 15;
    SubtitleOverlay.DEFAULT_CEA608_NUM_COLUMNS = 32;
    SubtitleOverlay.DEFAULT_CAPTION_LEFT_OFFSET = '0.5%';
    return SubtitleOverlay;
}(container_1.Container));
var SubtitleLabel = /** @class */ (function (_super) {
    __extends(SubtitleLabel, _super);
    function SubtitleLabel(config) {
        if (config === void 0) { config = {}; }
        var _this = _super.call(this, config) || this;
        _this.config = _this.mergeConfig(config, {
            cssClass: 'ui-subtitle-label',
        }, _this.config);
        return _this;
    }
    Object.defineProperty(SubtitleLabel.prototype, "vtt", {
        get: function () {
            return this.config.vtt;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SubtitleLabel.prototype, "region", {
        get: function () {
            return this.config.region;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SubtitleLabel.prototype, "regionStyle", {
        get: function () {
            return this.config.regionStyle;
        },
        set: function (style) {
            this.config.regionStyle = style;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SubtitleLabel.prototype, "originalRowPosition", {
        get: function () {
            return this.config.originalRowPosition;
        },
        set: function (row) {
            this.config.originalRowPosition = row;
        },
        enumerable: false,
        configurable: true
    });
    return SubtitleLabel;
}(label_1.Label));
exports.SubtitleLabel = SubtitleLabel;
var ActiveSubtitleManager = /** @class */ (function () {
    function ActiveSubtitleManager() {
        this.activeSubtitleCueMap = {};
        this.activeSubtitleCueCount = 0;
    }
    /**
     * Calculates a unique ID for a subtitle cue, which is needed to associate an CueEnter with its CueExit
     * event so we can remove the correct subtitle in CueExit when multiple subtitles are active at the same time.
     * The start time plus the text should make a unique identifier, and in the only case where a collision
     * can happen, two similar texts will be displayed at a similar time and a similar position (or without position).
     * The start time should always be known, because it is required to schedule the CueEnter event. The end time
     * must not necessarily be known and therefore cannot be used for the ID.
     * @param event
     * @return {string}
     */
    ActiveSubtitleManager.calculateId = function (event) {
        var id = event.start + '-' + event.text;
        if (event.position) {
            id += '-' + event.position.row + '-' + event.position.column;
        }
        return id;
    };
    ActiveSubtitleManager.prototype.cueEnter = function (event, label) {
        this.addCueToMap(event, label);
    };
    ActiveSubtitleManager.prototype.cueUpdate = function (event, label) {
        var labelToReplace = this.popCueFromMap(event);
        if (labelToReplace) {
            this.addCueToMap(event, label);
            return labelToReplace;
        }
        return undefined;
    };
    ActiveSubtitleManager.prototype.addCueToMap = function (event, label) {
        var id = ActiveSubtitleManager.calculateId(event);
        // Create array for id if it does not exist
        this.activeSubtitleCueMap[id] = this.activeSubtitleCueMap[id] || [];
        // Add cue
        this.activeSubtitleCueMap[id].push({ event: event, label: label });
        this.activeSubtitleCueCount++;
    };
    ActiveSubtitleManager.prototype.popCueFromMap = function (event) {
        var id = ActiveSubtitleManager.calculateId(event);
        var activeSubtitleCues = this.activeSubtitleCueMap[id];
        if (activeSubtitleCues && activeSubtitleCues.length > 0) {
            // Remove cue
            /* We apply the FIFO approach here and remove the oldest cue from the associated id. When there are multiple cues
             * with the same id, there is no way to know which one of the cues is to be deleted, so we just hope that FIFO
             * works fine. Theoretically it can happen that two cues with colliding ids are removed at different times, in
             * the wrong order. This rare case has yet to be observed. If it ever gets an issue, we can take the unstable
             * cue end time (which can change between CueEnter and CueExit IN CueUpdate) and use it as an
             * additional hint to try and remove the correct one of the colliding cues.
             */
            var activeSubtitleCue = activeSubtitleCues.shift();
            this.activeSubtitleCueCount--;
            return activeSubtitleCue.label;
        }
    };
    /**
     * Removes all active cues which don't enclose the given time
     * @param time the time for which subtitles should remain
     */
    ActiveSubtitleManager.prototype.clearInactiveCues = function (time) {
        var _this = this;
        var removedCues = [];
        Object.keys(this.activeSubtitleCueMap).forEach(function (key) {
            var activeCues = _this.activeSubtitleCueMap[key];
            activeCues.forEach(function (cue) {
                if (time < cue.event.start || time > cue.event.end) {
                    _this.popCueFromMap(cue.event);
                    removedCues.push(cue);
                }
            });
        });
        return removedCues;
    };
    ActiveSubtitleManager.generateImageTagText = function (imageData) {
        if (!imageData) {
            return;
        }
        var imgTag = new dom_1.DOM('img', {
            src: imageData,
        });
        imgTag.css('width', '100%');
        return imgTag.get(0).outerHTML; // return the html as string
    };
    /**
     * Returns the label associated with an already added cue.
     * @param event
     * @return {SubtitleLabel}
     */
    ActiveSubtitleManager.prototype.getCues = function (event) {
        var id = ActiveSubtitleManager.calculateId(event);
        var activeSubtitleCues = this.activeSubtitleCueMap[id];
        if (activeSubtitleCues && activeSubtitleCues.length > 0) {
            return activeSubtitleCues.map(function (cue) { return cue.label; });
        }
    };
    /**
     * Removes the subtitle cue from the manager and returns the label that should be removed from the subtitle overlay,
     * or null if there is no associated label existing (e.g. because all labels have been {@link #clear cleared}.
     * @param event
     * @return {SubtitleLabel|null}
     */
    ActiveSubtitleManager.prototype.cueExit = function (event) {
        return this.popCueFromMap(event);
    };
    Object.defineProperty(ActiveSubtitleManager.prototype, "cueCount", {
        /**
         * Returns the number of active subtitle cues.
         * @return {number}
         */
        get: function () {
            // We explicitly count the cues to save an Array.reduce on every cueCount call (which can happen frequently)
            return this.activeSubtitleCueCount;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ActiveSubtitleManager.prototype, "hasCues", {
        /**
         * Returns true if there are active subtitle cues, else false.
         * @return {boolean}
         */
        get: function () {
            return this.cueCount > 0;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Removes all subtitle cues from the manager.
     */
    ActiveSubtitleManager.prototype.clear = function () {
        this.activeSubtitleCueMap = {};
        this.activeSubtitleCueCount = 0;
    };
    return ActiveSubtitleManager;
}());
var SubtitleRegionContainerManager = /** @class */ (function () {
    /**
     * @param subtitleOverlay Reference to the subtitle overlay for adding and removing the containers.
     */
    function SubtitleRegionContainerManager(subtitleOverlay) {
        this.subtitleOverlay = subtitleOverlay;
        this.subtitleRegionContainers = {};
        this.subtitleOverlay = subtitleOverlay;
    }
    SubtitleRegionContainerManager.prototype.getRegion = function (label) {
        if (label.vtt) {
            return {
                regionContainerId: label.vtt.region && label.vtt.region.id ? label.vtt.region.id : 'vtt',
                regionName: 'vtt',
            };
        }
        return {
            regionContainerId: label.region || 'default',
            regionName: label.region || 'default',
        };
    };
    /**
     * Creates and wraps a subtitle label into a container div based on the subtitle region.
     * If the subtitle has positioning information it is added to the container.
     * @param label The subtitle label to wrap
     */
    SubtitleRegionContainerManager.prototype.addLabel = function (label, overlaySize) {
        var _a = this.getRegion(label), regionContainerId = _a.regionContainerId, regionName = _a.regionName;
        var cssClasses = ["subtitle-position-".concat(regionName)];
        if (label.vtt && label.vtt.region) {
            cssClasses.push("vtt-region-".concat(label.vtt.region.id));
        }
        if (!this.subtitleRegionContainers[regionContainerId]) {
            var regionContainer = new SubtitleRegionContainer({
                cssClasses: cssClasses,
            });
            this.subtitleRegionContainers[regionContainerId] = regionContainer;
            if (label.regionStyle) {
                regionContainer.getDomElement().attr('style', label.regionStyle);
            }
            if (label.vtt) {
                regionContainer.getDomElement().css('position', 'static');
            }
            // getDomElement needs to be called at least once to ensure the component exists
            regionContainer.getDomElement();
            for (var regionContainerId_1 in this.subtitleRegionContainers) {
                this.subtitleOverlay.addComponent(this.subtitleRegionContainers[regionContainerId_1]);
            }
        }
        this.subtitleRegionContainers[regionContainerId].addLabel(label, overlaySize);
    };
    SubtitleRegionContainerManager.prototype.replaceLabel = function (previousLabel, newLabel) {
        var regionContainerId = this.getRegion(previousLabel).regionContainerId;
        this.subtitleRegionContainers[regionContainerId].removeLabel(previousLabel);
        this.subtitleRegionContainers[regionContainerId].addLabel(newLabel);
    };
    /**
     * Removes a subtitle label from a container.
     */
    SubtitleRegionContainerManager.prototype.removeLabel = function (label) {
        var regionContainerId;
        if (label.vtt) {
            regionContainerId = label.vtt.region && label.vtt.region.id ? label.vtt.region.id : 'vtt';
        }
        else {
            regionContainerId = label.region || 'default';
        }
        this.subtitleRegionContainers[regionContainerId].removeLabel(label);
        // Remove container if no more labels are displayed
        if (this.subtitleRegionContainers[regionContainerId].isEmpty()) {
            this.subtitleOverlay.removeComponent(this.subtitleRegionContainers[regionContainerId]);
            delete this.subtitleRegionContainers[regionContainerId];
        }
    };
    /**
     * Removes all subtitle containers.
     */
    SubtitleRegionContainerManager.prototype.clear = function () {
        for (var regionName in this.subtitleRegionContainers) {
            this.subtitleOverlay.removeComponent(this.subtitleRegionContainers[regionName]);
        }
        this.subtitleRegionContainers = {};
    };
    return SubtitleRegionContainerManager;
}());
exports.SubtitleRegionContainerManager = SubtitleRegionContainerManager;
var SubtitleRegionContainer = /** @class */ (function (_super) {
    __extends(SubtitleRegionContainer, _super);
    function SubtitleRegionContainer(config) {
        if (config === void 0) { config = {}; }
        var _this = _super.call(this, config) || this;
        _this.labelCount = 0;
        _this.config = _this.mergeConfig(config, {
            cssClass: 'subtitle-region-container',
        }, _this.config);
        return _this;
    }
    SubtitleRegionContainer.prototype.addLabel = function (labelToAdd, overlaySize) {
        this.labelCount++;
        if (labelToAdd.vtt) {
            if (labelToAdd.vtt.region && overlaySize) {
                vttutils_1.VttUtils.setVttRegionStyles(this, labelToAdd.vtt.region, overlaySize);
            }
            vttutils_1.VttUtils.setVttCueBoxStyles(labelToAdd, overlaySize);
        }
        this.addComponent(labelToAdd);
        this.updateComponents();
    };
    SubtitleRegionContainer.prototype.removeLabel = function (labelToRemove) {
        this.labelCount--;
        this.removeComponent(labelToRemove);
        this.updateComponents();
    };
    SubtitleRegionContainer.prototype.isEmpty = function () {
        return this.labelCount === 0;
    };
    return SubtitleRegionContainer;
}(container_1.Container));
exports.SubtitleRegionContainer = SubtitleRegionContainer;
