/*
 * Application Insights JavaScript SDK - Core, 2.8.15
 * Copyright (c) Microsoft and contributors. All rights reserved.
 */


"use strict";
import dynamicProto from "@microsoft/dynamicproto-js";
import { _DYN_CREATE_NEW, _DYN_DIAG_LOG, _DYN_GET_NEXT, _DYN_GET_PROCESS_TEL_CONT0, _DYN_INITIALIZE, _DYN_IS_ASYNC, _DYN_IS_INITIALIZED, _DYN_PROCESS_NEXT, _DYN_PUSH, _DYN_SET_NEXT_PLUGIN, _DYN_TEARDOWN, _DYN_UPDATE, _DYN__DO_TEARDOWN } from "../__DynamicConstants";
import { arrForEach, isArray, isFunction, isNullOrUndefined, proxyFunctionAs, setValue } from "./HelperFuncs";
import { STR_CORE, STR_EXTENSION_CONFIG, STR_PROCESS_TELEMETRY } from "./InternalConstants";
import { createProcessTelemetryContext, createProcessTelemetryUnloadContext, createProcessTelemetryUpdateContext } from "./ProcessTelemetryContext";
import { createUnloadHandlerContainer } from "./UnloadHandlerContainer";
var strGetPlugin = "getPlugin";
/**
 * BaseTelemetryPlugin provides a basic implementation of the ITelemetryPlugin interface so that plugins
 * can avoid implementation the same set of boiler plate code as well as provide a base
 * implementation so that new default implementations can be added without breaking all plugins.
 */
var BaseTelemetryPlugin = /** @class */ (function () {
    function BaseTelemetryPlugin() {
        var _self = this; // Setting _self here as it's used outside of the dynamicProto as well
        // NOTE!: DON'T set default values here, instead set them in the _initDefaults() function as it is also called during teardown()
        var _isinitialized;
        var _rootCtx; // Used as the root context, holding the current config and initialized core
        var _nextPlugin; // Used for backward compatibility where plugins don't call the main pipeline
        var _unloadHandlerContainer;
        var _hooks;
        _initDefaults();
        dynamicProto(BaseTelemetryPlugin, _self, function (_self) {
            _self[_DYN_INITIALIZE /* @min:%2einitialize */] = function (config, core, extensions, pluginChain) {
                _setDefaults(config, core, pluginChain);
                _isinitialized = true;
            };
            _self[_DYN_TEARDOWN /* @min:%2eteardown */] = function (unloadCtx, unloadState) {
                var _a;
                // If this plugin has already been torn down (not operational) or is not initialized (core is not set)
                // or the core being used for unload was not the same core used for initialization.
                var core = _self[STR_CORE /* @min:%2ecore */];
                if (!core || (unloadCtx && core !== unloadCtx[STR_CORE /* @min:%2ecore */]())) {
                    // Do Nothing as either the plugin is not initialized or was not initialized by the current core
                    return;
                }
                var result;
                var unloadDone = false;
                var theUnloadCtx = unloadCtx || createProcessTelemetryUnloadContext(null, core, _nextPlugin && _nextPlugin[strGetPlugin] ? _nextPlugin[strGetPlugin]() : _nextPlugin);
                var theUnloadState = unloadState || (_a = {
                        reason: 0 /* TelemetryUnloadReason.ManualTeardown */
                    },
                    _a[_DYN_IS_ASYNC /* @min:isAsync */] = false,
                    _a);
                function _unloadCallback() {
                    if (!unloadDone) {
                        unloadDone = true;
                        _unloadHandlerContainer.run(theUnloadCtx, unloadState);
                        var oldHooks = _hooks;
                        _hooks = [];
                        // Remove all instrumentation hooks
                        arrForEach(oldHooks, function (fn) {
                            fn.rm();
                        });
                        if (result === true) {
                            theUnloadCtx[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */](theUnloadState);
                        }
                        _initDefaults();
                    }
                }
                if (!_self[_DYN__DO_TEARDOWN /* @min:%2e_doTeardown */] || _self[_DYN__DO_TEARDOWN /* @min:%2e_doTeardown */](theUnloadCtx, theUnloadState, _unloadCallback) !== true) {
                    _unloadCallback();
                }
                else {
                    // Tell the caller that we will be calling processNext()
                    result = true;
                }
                return result;
            };
            _self[_DYN_UPDATE /* @min:%2eupdate */] = function (updateCtx, updateState) {
                // If this plugin has already been torn down (not operational) or is not initialized (core is not set)
                // or the core being used for unload was not the same core used for initialization.
                var core = _self[STR_CORE /* @min:%2ecore */];
                if (!core || (updateCtx && core !== updateCtx[STR_CORE /* @min:%2ecore */]())) {
                    // Do Nothing
                    return;
                }
                var result;
                var updateDone = false;
                var theUpdateCtx = updateCtx || createProcessTelemetryUpdateContext(null, core, _nextPlugin && _nextPlugin[strGetPlugin] ? _nextPlugin[strGetPlugin]() : _nextPlugin);
                var theUpdateState = updateState || {
                    reason: 0 /* TelemetryUpdateReason.Unknown */
                };
                function _updateCallback() {
                    if (!updateDone) {
                        updateDone = true;
                        _setDefaults(theUpdateCtx.getCfg(), theUpdateCtx.core(), theUpdateCtx[_DYN_GET_NEXT /* @min:%2egetNext */]());
                    }
                }
                if (!_self._doUpdate || _self._doUpdate(theUpdateCtx, theUpdateState, _updateCallback) !== true) {
                    _updateCallback();
                }
                else {
                    result = true;
                }
                return result;
            };
            _self._addHook = function (hooks) {
                if (hooks) {
                    if (isArray(hooks)) {
                        _hooks = _hooks.concat(hooks);
                    }
                    else {
                        _hooks[_DYN_PUSH /* @min:%2epush */](hooks);
                    }
                }
            };
            proxyFunctionAs(_self, "_addUnloadCb", function () { return _unloadHandlerContainer; }, "add");
        });
        // These are added after the dynamicProto so that are not moved to the prototype
        _self[_DYN_DIAG_LOG /* @min:%2ediagLog */] = function (itemCtx) {
            return _getTelCtx(itemCtx)[_DYN_DIAG_LOG /* @min:%2ediagLog */]();
        };
        _self[_DYN_IS_INITIALIZED /* @min:%2eisInitialized */] = function () {
            return _isinitialized;
        };
        _self.setInitialized = function (isInitialized) {
            _isinitialized = isInitialized;
        };
        // _self.getNextPlugin = () => DO NOT IMPLEMENT
        // Sub-classes of this base class *should* not be relying on this value and instead
        // should use processNext() function. If you require access to the plugin use the
        // IProcessTelemetryContext.getNext().getPlugin() while in the pipeline, Note getNext() may return null.
        _self[_DYN_SET_NEXT_PLUGIN /* @min:%2esetNextPlugin */] = function (next) {
            _nextPlugin = next;
        };
        _self[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */] = function (env, itemCtx) {
            if (itemCtx) {
                // Normal core execution sequence
                itemCtx[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */](env);
            }
            else if (_nextPlugin && isFunction(_nextPlugin[STR_PROCESS_TELEMETRY /* @min:%2eprocessTelemetry */])) {
                // Looks like backward compatibility or out of band processing. And as it looks
                // like a ITelemetryPlugin or ITelemetryPluginChain, just call processTelemetry
                _nextPlugin[STR_PROCESS_TELEMETRY /* @min:%2eprocessTelemetry */](env, null);
            }
        };
        _self._getTelCtx = _getTelCtx;
        function _getTelCtx(currentCtx) {
            if (currentCtx === void 0) { currentCtx = null; }
            var itemCtx = currentCtx;
            if (!itemCtx) {
                var rootCtx = _rootCtx || createProcessTelemetryContext(null, {}, _self[STR_CORE /* @min:%2ecore */]);
                // tslint:disable-next-line: prefer-conditional-expression
                if (_nextPlugin && _nextPlugin[strGetPlugin]) {
                    // Looks like a chain object
                    itemCtx = rootCtx[_DYN_CREATE_NEW /* @min:%2ecreateNew */](null, _nextPlugin[strGetPlugin]);
                }
                else {
                    itemCtx = rootCtx[_DYN_CREATE_NEW /* @min:%2ecreateNew */](null, _nextPlugin);
                }
            }
            return itemCtx;
        }
        function _setDefaults(config, core, pluginChain) {
            if (config) {
                // Make sure the extensionConfig exists
                setValue(config, STR_EXTENSION_CONFIG, [], null, isNullOrUndefined);
            }
            if (!pluginChain && core) {
                // Get the first plugin from the core
                pluginChain = core[_DYN_GET_PROCESS_TEL_CONT0 /* @min:%2egetProcessTelContext */]()[_DYN_GET_NEXT /* @min:%2egetNext */]();
            }
            var nextPlugin = _nextPlugin;
            if (_nextPlugin && _nextPlugin[strGetPlugin]) {
                // If it looks like a proxy/chain then get the plugin
                nextPlugin = _nextPlugin[strGetPlugin]();
            }
            // Support legacy plugins where core was defined as a property
            _self[STR_CORE /* @min:%2ecore */] = core;
            _rootCtx = createProcessTelemetryContext(pluginChain, config, core, nextPlugin);
        }
        function _initDefaults() {
            _isinitialized = false;
            _self[STR_CORE /* @min:%2ecore */] = null;
            _rootCtx = null;
            _nextPlugin = null;
            _hooks = [];
            _unloadHandlerContainer = createUnloadHandlerContainer();
        }
    }
// Removed Stub for BaseTelemetryPlugin.prototype.initialize.
// Removed Stub for BaseTelemetryPlugin.prototype.teardown.
// Removed Stub for BaseTelemetryPlugin.prototype.update.
// Removed Stub for BaseTelemetryPlugin.prototype._addUnloadCb.
// Removed Stub for BaseTelemetryPlugin.prototype._addHook.
    // This is a workaround for an IE8 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.
    // this will be removed when ES3 support is dropped.
    BaseTelemetryPlugin.__ieDyn=1;

    return BaseTelemetryPlugin;
}());
export { BaseTelemetryPlugin };
