/*
 * Application Insights JavaScript SDK - Channel, 3.3.10
 * Copyright (c) Microsoft and contributors. All rights reserved.
 */
import { __extendsFn as __extends } from "@microsoft/applicationinsights-shims";
import dynamicProto from "@microsoft/dynamicproto-js";
import { utlGetSessionStorage, utlRemoveSessionStorage, utlSetSessionStorage } from "@microsoft/applicationinsights-common";
import { _throwInternal, arrForEach, arrIndexOf, dumpObj, getExceptionName, getJSON, isArray, isFunction, isNullOrUndefined, isString } from "@microsoft/applicationinsights-core-js";
import { _DYN_BUFFER_OVERRIDE, _DYN_CLEAR, _DYN_CLEAR_SENT, _DYN_CONCAT, _DYN_COUNT, _DYN_EMIT_LINE_DELIMITED_0, _DYN_ENQUEUE, _DYN_LENGTH, _DYN_MARK_AS_SENT, _DYN_PUSH, _DYN_STRINGIFY, _DYN__BUFFER__KEY, _DYN__MAX__BUFFER__SIZE, _DYN__SENT__BUFFER__KEY } from "./__DynamicConstants";
var BaseSendBuffer = /** @class */ (function () {
    function BaseSendBuffer(logger, config) {
        var _buffer = [];
        var _bufferFullMessageSent = false;
        var _maxRetryCnt = config.maxRetryCnt;
        this._get = function () {
            return _buffer;
        };
        this._set = function (buffer) {
            _buffer = buffer;
            return _buffer;
        };
        dynamicProto(BaseSendBuffer, this, function (_self) {
            _self[_DYN_ENQUEUE /* @min:%2eenqueue */] = function (payload) {
                if (_self[_DYN_COUNT /* @min:%2ecount */]() >= config.eventsLimitInMem) {
                    // sent internal log only once per page view
                    if (!_bufferFullMessageSent) {
                        _throwInternal(logger, 2 /* eLoggingSeverity.WARNING */, 105 /* _eInternalMessageId.InMemoryStorageBufferFull */, "Maximum in-memory buffer size reached: " + _self[_DYN_COUNT /* @min:%2ecount */](), true);
                        _bufferFullMessageSent = true;
                    }
                    return;
                }
                payload.cnt = payload.cnt || 0;
                // max retry is defined, and max retry is reached, do not add the payload to buffer
                if (!isNullOrUndefined(_maxRetryCnt)) {
                    if (payload.cnt > _maxRetryCnt) {
                        // TODO: add log here on dropping payloads
                        // will log statsbeat exception later here
                        return;
                    }
                }
                _buffer[_DYN_PUSH /* @min:%2epush */](payload);
                return;
            };
            _self[_DYN_COUNT /* @min:%2ecount */] = function () {
                return _buffer[_DYN_LENGTH /* @min:%2elength */];
            };
            _self.size = function () {
                var size = _buffer[_DYN_LENGTH /* @min:%2elength */];
                for (var lp = 0; lp < _buffer[_DYN_LENGTH /* @min:%2elength */]; lp++) {
                    size += (_buffer[lp].item)[_DYN_LENGTH /* @min:%2elength */];
                }
                if (!config[_DYN_EMIT_LINE_DELIMITED_0 /* @min:%2eemitLineDelimitedJson */]) {
                    size += 2;
                }
                return size;
            };
            _self[_DYN_CLEAR /* @min:%2eclear */] = function () {
                _buffer = [];
                _bufferFullMessageSent = false;
            };
            _self.getItems = function () {
                return _buffer.slice(0);
            };
            _self.batchPayloads = function (payloads) {
                if (payloads && payloads[_DYN_LENGTH /* @min:%2elength */] > 0) {
                    var payloadStr_1 = [];
                    arrForEach(payloads, function (payload) {
                        payloadStr_1[_DYN_PUSH /* @min:%2epush */](payload.item);
                    });
                    var batch = config[_DYN_EMIT_LINE_DELIMITED_0 /* @min:%2eemitLineDelimitedJson */] ?
                        payloadStr_1.join("\n") :
                        "[" + payloadStr_1.join(",") + "]";
                    return batch;
                }
                return null;
            };
            _self.createNew = function (newLogger, newConfig, canUseSessionStorage) {
                var items = _buffer.slice(0);
                newLogger = newLogger || logger;
                newConfig = newConfig || {};
                var newBuffer = !!canUseSessionStorage ? new SessionStorageSendBuffer(newLogger, newConfig) : new ArraySendBuffer(newLogger, newConfig);
                arrForEach(items, function (payload) {
                    newBuffer[_DYN_ENQUEUE /* @min:%2eenqueue */](payload);
                });
                return newBuffer;
            };
        });
    }
// Removed Stub for BaseSendBuffer.prototype.enqueue.
// Removed Stub for BaseSendBuffer.prototype.count.
// Removed Stub for BaseSendBuffer.prototype.size.
// Removed Stub for BaseSendBuffer.prototype.clear.
// Removed Stub for BaseSendBuffer.prototype.getItems.
// Removed Stub for BaseSendBuffer.prototype.batchPayloads.
// Removed Stub for BaseSendBuffer.prototype.createNew.
    // This is a workaround for an IE bug when using dynamicProto() with classes that don't have any
    // non-dynamic functions or static properties/functions when using uglify-js to minify the resulting code.
    BaseSendBuffer.__ieDyn=1;

    return BaseSendBuffer;
}());
/*
 * An array based send buffer.
 */
var ArraySendBuffer = /** @class */ (function (_super) {
    __extends(ArraySendBuffer, _super);
    function ArraySendBuffer(logger, config) {
        var _this = _super.call(this, logger, config) || this;
        dynamicProto(ArraySendBuffer, _this, function (_self, _base) {
            _self[_DYN_MARK_AS_SENT /* @min:%2emarkAsSent */] = function (payload) {
                _base[_DYN_CLEAR /* @min:%2eclear */]();
            };
            _self[_DYN_CLEAR_SENT /* @min:%2eclearSent */] = function (payload) {
                // not supported
            };
        });
        return _this;
    }
// Removed Stub for ArraySendBuffer.prototype.markAsSent.
// Removed Stub for ArraySendBuffer.prototype.clearSent.
    // This is a workaround for an IE bug when using dynamicProto() with classes that don't have any
    // non-dynamic functions or static properties/functions when using uglify-js to minify the resulting code.
    ArraySendBuffer.__ieDyn=1;

    return ArraySendBuffer;
}(BaseSendBuffer));
export { ArraySendBuffer };
var PREVIOUS_KEYS = ["AI_buffer", "AI_sentBuffer"];
/*
 * Session storage buffer holds a copy of all unsent items in the browser session storage.
 */
var SessionStorageSendBuffer = /** @class */ (function (_super) {
    __extends(SessionStorageSendBuffer, _super);
    function SessionStorageSendBuffer(logger, config) {
        var _this = _super.call(this, logger, config) || this;
        var _bufferFullMessageSent = false;
        //Note: should not use config.namePrefix directly, because it will always refers to the latest namePrefix
        var _namePrefix = config === null || config === void 0 ? void 0 : config.namePrefix;
        // TODO: add remove buffer override as well
        var _b = config[_DYN_BUFFER_OVERRIDE /* @min:%2ebufferOverride */] || { getItem: utlGetSessionStorage, setItem: utlSetSessionStorage }, getItem = _b.getItem, setItem = _b.setItem;
        var _maxRetryCnt = config.maxRetryCnt;
        dynamicProto(SessionStorageSendBuffer, _this, function (_self, _base) {
            var bufferItems = _getBuffer(SessionStorageSendBuffer[_DYN__BUFFER__KEY /* @min:%2eBUFFER_KEY */]);
            var itemsInSentBuffer = _getBuffer(SessionStorageSendBuffer[_DYN__SENT__BUFFER__KEY /* @min:%2eSENT_BUFFER_KEY */]);
            var previousItems = _getPreviousEvents();
            var notDeliveredItems = itemsInSentBuffer[_DYN_CONCAT /* @min:%2econcat */](previousItems);
            var buffer = _self._set(bufferItems[_DYN_CONCAT /* @min:%2econcat */](notDeliveredItems));
            // If the buffer has too many items, drop items from the end.
            if (buffer[_DYN_LENGTH /* @min:%2elength */] > SessionStorageSendBuffer[_DYN__MAX__BUFFER__SIZE /* @min:%2eMAX_BUFFER_SIZE */]) {
                buffer[_DYN_LENGTH /* @min:%2elength */] = SessionStorageSendBuffer[_DYN__MAX__BUFFER__SIZE /* @min:%2eMAX_BUFFER_SIZE */];
            }
            _setBuffer(SessionStorageSendBuffer[_DYN__SENT__BUFFER__KEY /* @min:%2eSENT_BUFFER_KEY */], []);
            _setBuffer(SessionStorageSendBuffer[_DYN__BUFFER__KEY /* @min:%2eBUFFER_KEY */], buffer);
            _self[_DYN_ENQUEUE /* @min:%2eenqueue */] = function (payload) {
                if (_self[_DYN_COUNT /* @min:%2ecount */]() >= SessionStorageSendBuffer[_DYN__MAX__BUFFER__SIZE /* @min:%2eMAX_BUFFER_SIZE */]) {
                    // sent internal log only once per page view
                    if (!_bufferFullMessageSent) {
                        _throwInternal(logger, 2 /* eLoggingSeverity.WARNING */, 67 /* _eInternalMessageId.SessionStorageBufferFull */, "Maximum buffer size reached: " + _self[_DYN_COUNT /* @min:%2ecount */](), true);
                        _bufferFullMessageSent = true;
                    }
                    return;
                }
                payload.cnt = payload.cnt || 0;
                // max retry is defined, and max retry is reached, do not add the payload to buffer
                if (!isNullOrUndefined(_maxRetryCnt)) {
                    if (payload.cnt > _maxRetryCnt) {
                        // TODO: add log here on dropping payloads
                        return;
                    }
                }
                _base[_DYN_ENQUEUE /* @min:%2eenqueue */](payload);
                _setBuffer(SessionStorageSendBuffer[_DYN__BUFFER__KEY /* @min:%2eBUFFER_KEY */], _self._get());
            };
            _self[_DYN_CLEAR /* @min:%2eclear */] = function () {
                _base[_DYN_CLEAR /* @min:%2eclear */]();
                _setBuffer(SessionStorageSendBuffer[_DYN__BUFFER__KEY /* @min:%2eBUFFER_KEY */], _self._get());
                _setBuffer(SessionStorageSendBuffer[_DYN__SENT__BUFFER__KEY /* @min:%2eSENT_BUFFER_KEY */], []);
                _bufferFullMessageSent = false;
            };
            _self[_DYN_MARK_AS_SENT /* @min:%2emarkAsSent */] = function (payload) {
                _setBuffer(SessionStorageSendBuffer[_DYN__BUFFER__KEY /* @min:%2eBUFFER_KEY */], _self._set(_removePayloadsFromBuffer(payload, _self._get())));
                var sentElements = _getBuffer(SessionStorageSendBuffer[_DYN__SENT__BUFFER__KEY /* @min:%2eSENT_BUFFER_KEY */]);
                if (sentElements instanceof Array && payload instanceof Array) {
                    sentElements = sentElements[_DYN_CONCAT /* @min:%2econcat */](payload);
                    if (sentElements[_DYN_LENGTH /* @min:%2elength */] > SessionStorageSendBuffer[_DYN__MAX__BUFFER__SIZE /* @min:%2eMAX_BUFFER_SIZE */]) {
                        // We send telemetry normally. If the SENT_BUFFER is too big we don't add new elements
                        // until we receive a response from the backend and the buffer has free space again (see clearSent method)
                        _throwInternal(logger, 1 /* eLoggingSeverity.CRITICAL */, 67 /* _eInternalMessageId.SessionStorageBufferFull */, "Sent buffer reached its maximum size: " + sentElements[_DYN_LENGTH /* @min:%2elength */], true);
                        sentElements[_DYN_LENGTH /* @min:%2elength */] = SessionStorageSendBuffer[_DYN__MAX__BUFFER__SIZE /* @min:%2eMAX_BUFFER_SIZE */];
                    }
                    _setBuffer(SessionStorageSendBuffer[_DYN__SENT__BUFFER__KEY /* @min:%2eSENT_BUFFER_KEY */], sentElements);
                }
            };
            _self[_DYN_CLEAR_SENT /* @min:%2eclearSent */] = function (payload) {
                var sentElements = _getBuffer(SessionStorageSendBuffer[_DYN__SENT__BUFFER__KEY /* @min:%2eSENT_BUFFER_KEY */]);
                sentElements = _removePayloadsFromBuffer(payload, sentElements);
                _setBuffer(SessionStorageSendBuffer[_DYN__SENT__BUFFER__KEY /* @min:%2eSENT_BUFFER_KEY */], sentElements);
            };
            _self.createNew = function (newLogger, newConfig, canUseSessionStorage) {
                canUseSessionStorage = !!canUseSessionStorage;
                var unsentItems = _self._get().slice(0);
                var sentItems = _getBuffer(SessionStorageSendBuffer[_DYN__SENT__BUFFER__KEY /* @min:%2eSENT_BUFFER_KEY */]).slice(0);
                newLogger = newLogger || logger;
                newConfig = newConfig || {};
                // to make sure that we do not send duplicated payloads when it is switched back to previous one
                _self[_DYN_CLEAR /* @min:%2eclear */]();
                var newBuffer = canUseSessionStorage ? new SessionStorageSendBuffer(newLogger, newConfig) : new ArraySendBuffer(newLogger, newConfig);
                arrForEach(unsentItems, function (payload) {
                    newBuffer[_DYN_ENQUEUE /* @min:%2eenqueue */](payload);
                });
                if (canUseSessionStorage) {
                    // arr buffer will clear all payloads if markAsSent() is called
                    newBuffer[_DYN_MARK_AS_SENT /* @min:%2emarkAsSent */](sentItems);
                }
                return newBuffer;
            };
            function _removePayloadsFromBuffer(payloads, buffer) {
                var remaining = [];
                var payloadStr = [];
                arrForEach(payloads, function (payload) {
                    payloadStr[_DYN_PUSH /* @min:%2epush */](payload.item);
                });
                arrForEach(buffer, function (value) {
                    if (!isFunction(value) && arrIndexOf(payloadStr, value.item) === -1) {
                        remaining[_DYN_PUSH /* @min:%2epush */](value);
                    }
                });
                return remaining;
            }
            function _getBuffer(key) {
                var prefixedKey = key;
                prefixedKey = _namePrefix ? _namePrefix + "_" + prefixedKey : prefixedKey;
                return _getBufferBase(prefixedKey);
            }
            function _getBufferBase(key) {
                try {
                    var bufferJson = getItem(logger, key);
                    if (bufferJson) {
                        var buffer_1 = getJSON().parse(bufferJson);
                        if (isString(buffer_1)) {
                            // When using some version prototype.js the stringify / parse cycle does not decode array's correctly
                            buffer_1 = getJSON().parse(buffer_1);
                        }
                        if (buffer_1 && isArray(buffer_1)) {
                            return buffer_1;
                        }
                    }
                }
                catch (e) {
                    _throwInternal(logger, 1 /* eLoggingSeverity.CRITICAL */, 42 /* _eInternalMessageId.FailedToRestoreStorageBuffer */, " storage key: " + key + ", " + getExceptionName(e), { exception: dumpObj(e) });
                }
                return [];
            }
            function _setBuffer(key, buffer) {
                var prefixedKey = key;
                try {
                    prefixedKey = _namePrefix ? _namePrefix + "_" + prefixedKey : prefixedKey;
                    var bufferJson = JSON[_DYN_STRINGIFY /* @min:%2estringify */](buffer);
                    setItem(logger, prefixedKey, bufferJson);
                }
                catch (e) {
                    // if there was an error, clear the buffer
                    // telemetry is stored in the _buffer array so we won't loose any items
                    setItem(logger, prefixedKey, JSON[_DYN_STRINGIFY /* @min:%2estringify */]([]));
                    _throwInternal(logger, 2 /* eLoggingSeverity.WARNING */, 41 /* _eInternalMessageId.FailedToSetStorageBuffer */, " storage key: " + prefixedKey + ", " + getExceptionName(e) + ". Buffer cleared", { exception: dumpObj(e) });
                }
            }
            // this removes buffer with prefix+key
            function _getPreviousEvents() {
                var items = [];
                try {
                    arrForEach(PREVIOUS_KEYS, function (key) {
                        var events = _getItemsFromPreviousKey(key);
                        items = items[_DYN_CONCAT /* @min:%2econcat */](events);
                        // to make sure that we also transfer items from old prefixed + key buffer
                        if (_namePrefix) {
                            var prefixedKey = _namePrefix + "_" + key;
                            var prefixEvents = _getItemsFromPreviousKey(prefixedKey);
                            items = items[_DYN_CONCAT /* @min:%2econcat */](prefixEvents);
                        }
                    });
                    return items;
                }
                catch (e) {
                    _throwInternal(logger, 2 /* eLoggingSeverity.WARNING */, 41 /* _eInternalMessageId.FailedToSetStorageBuffer */, "Transfer events from previous buffers: " + getExceptionName(e) + ". previous Buffer items can not be removed", { exception: dumpObj(e) });
                }
                return [];
            }
            // transform string[] to IInternalStorageItem[]
            function _getItemsFromPreviousKey(key) {
                try {
                    var items = _getBufferBase(key);
                    var transFormedItems_1 = [];
                    arrForEach(items, function (item) {
                        var internalItem = {
                            item: item,
                            cnt: 0 // previous events will be default to 0 count
                        };
                        transFormedItems_1[_DYN_PUSH /* @min:%2epush */](internalItem);
                    });
                    // remove the session storage if we can add events back
                    utlRemoveSessionStorage(logger, key);
                    return transFormedItems_1;
                }
                catch (e) {
                    // eslint-disable-next-line no-empty
                }
                return [];
            }
        });
        return _this;
    }
// Removed Stub for SessionStorageSendBuffer.prototype.enqueue.
// Removed Stub for SessionStorageSendBuffer.prototype.clear.
// Removed Stub for SessionStorageSendBuffer.prototype.markAsSent.
// Removed Stub for SessionStorageSendBuffer.prototype.clearSent.
// Removed Stub for SessionStorageSendBuffer.prototype.createNew.
    var _a;
    _a = SessionStorageSendBuffer;
    SessionStorageSendBuffer.VERSION = "_1";
    SessionStorageSendBuffer.BUFFER_KEY = "AI_buffer" + _a.VERSION;
    SessionStorageSendBuffer.SENT_BUFFER_KEY = "AI_sentBuffer" + _a.VERSION;
    // Maximum number of payloads stored in the buffer. If the buffer is full, new elements will be dropped.
    SessionStorageSendBuffer.MAX_BUFFER_SIZE = 2000;
    return SessionStorageSendBuffer;
}(BaseSendBuffer));
export { SessionStorageSendBuffer };
//# sourceMappingURL=SendBuffer.js.map