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


import { arrForEach, arrIndexOf, dumpObj, newSymbol, scheduleTimeout } from "@nevware21/ts-utils";
import { throwAggregationError } from "../JavaScriptSDK/AggregationError";
import { _DYN_CANCEL, _DYN_LENGTH, _DYN_LOGGER, _DYN_PUSH, _DYN_THROW_INTERNAL } from "../__DynamicConstants";
var symPrefix = "[[ai_";
var symPostfix = "]]";
export function _createState(cfgHandler) {
    var dynamicPropertySymbol = newSymbol(symPrefix + "get" + cfgHandler.uid + symPostfix);
    var dynamicPropertyReadOnly = newSymbol(symPrefix + "ro" + cfgHandler.uid + symPostfix);
    var dynamicPropertyReferenced = newSymbol(symPrefix + "rf" + cfgHandler.uid + symPostfix);
    var dynamicPropertyBlockValue = newSymbol(symPrefix + "blkVal" + cfgHandler.uid + symPostfix);
    var dynamicPropertyDetail = newSymbol(symPrefix + "dtl" + cfgHandler.uid + symPostfix);
    var _waitingHandlers = null;
    var _watcherTimer = null;
    var theState;
    function _useHandler(activeHandler, callback) {
        var prevWatcher = theState.act;
        try {
            theState.act = activeHandler;
            if (activeHandler && activeHandler[dynamicPropertyDetail]) {
                // Clear out the previously tracked details for this handler, so that access are re-evaluated
                arrForEach(activeHandler[dynamicPropertyDetail], function (detail) {
                    detail.clr(activeHandler);
                });
                activeHandler[dynamicPropertyDetail] = [];
            }
            callback({
                cfg: cfgHandler.cfg,
                set: cfgHandler.set.bind(cfgHandler),
                setDf: cfgHandler.setDf.bind(cfgHandler),
                ref: cfgHandler.ref.bind(cfgHandler),
                rdOnly: cfgHandler.rdOnly.bind(cfgHandler)
            });
        }
        catch (e) {
            var logger = cfgHandler[_DYN_LOGGER /* @min:%2elogger */];
            if (logger) {
                // Don't let one individual failure break everyone
                logger[_DYN_THROW_INTERNAL /* @min:%2ethrowInternal */](1 /* eLoggingSeverity.CRITICAL */, 107 /* _eInternalMessageId.ConfigWatcherException */, dumpObj(e));
            }
            // Re-throw the exception so that any true "error" is reported back to the called
            throw e;
        }
        finally {
            theState.act = prevWatcher || null;
        }
    }
    function _notifyWatchers() {
        if (_waitingHandlers) {
            var notifyHandlers = _waitingHandlers;
            _waitingHandlers = null;
            // Stop any timer as we are running them now anyway
            _watcherTimer && _watcherTimer[_DYN_CANCEL /* @min:%2ecancel */]();
            _watcherTimer = null;
            var watcherFailures_1 = [];
            // Now run the handlers
            arrForEach(notifyHandlers, function (handler) {
                if (handler) {
                    if (handler[dynamicPropertyDetail]) {
                        arrForEach(handler[dynamicPropertyDetail], function (detail) {
                            // Clear out this handler from  previously tracked details, so that access are re-evaluated
                            detail.clr(handler);
                        });
                        handler[dynamicPropertyDetail] = null;
                    }
                    // The handler may have self removed as part of another handler so re-check
                    if (handler.fn) {
                        try {
                            _useHandler(handler, handler.fn);
                        }
                        catch (e) {
                            // Don't let a single failing watcher cause other watches to fail
                            watcherFailures_1[_DYN_PUSH /* @min:%2epush */](e);
                        }
                    }
                }
            });
            // During notification we may have had additional updates -- so notify those updates as well
            if (_waitingHandlers) {
                try {
                    _notifyWatchers();
                }
                catch (e) {
                    watcherFailures_1[_DYN_PUSH /* @min:%2epush */](e);
                }
            }
            if (watcherFailures_1[_DYN_LENGTH /* @min:%2elength */] > 0) {
                throwAggregationError("Watcher error(s): ", watcherFailures_1);
            }
        }
    }
    function _addWatcher(detail) {
        if (detail && detail.h[_DYN_LENGTH /* @min:%2elength */] > 0) {
            if (!_waitingHandlers) {
                _waitingHandlers = [];
            }
            if (!_watcherTimer) {
                _watcherTimer = scheduleTimeout(function () {
                    _watcherTimer = null;
                    _notifyWatchers();
                }, 0);
            }
            // Add all of the handlers for this detail (if not already present) - using normal for-loop for performance
            for (var idx = 0; idx < detail.h[_DYN_LENGTH /* @min:%2elength */]; idx++) {
                var handler = detail.h[idx];
                // Add this handler to the collection of handlers to re-execute
                if (handler && arrIndexOf(_waitingHandlers, handler) === -1) {
                    _waitingHandlers[_DYN_PUSH /* @min:%2epush */](handler);
                }
            }
        }
    }
    function _trackHandler(handler, detail) {
        if (handler) {
            var details = handler[dynamicPropertyDetail] = handler[dynamicPropertyDetail] || [];
            if (arrIndexOf(details, detail) === -1) {
                // If this detail is not already listed as tracked then add it so that we re-evaluate it's usage
                details[_DYN_PUSH /* @min:%2epush */](detail);
            }
        }
    }
    theState = {
        prop: dynamicPropertySymbol,
        ro: dynamicPropertyReadOnly,
        rf: dynamicPropertyReferenced,
        blkVal: dynamicPropertyBlockValue,
        hdlr: cfgHandler,
        add: _addWatcher,
        notify: _notifyWatchers,
        use: _useHandler,
        trk: _trackHandler
    };
    return theState;
}
//# sourceMappingURL=DynamicState.js.map