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

// 
import { _DYN_CONFIG, _DYN_CREATE_NEW, _DYN_FLUSH, _DYN_IDENTIFIER, _DYN_LENGTH, _DYN_ON_COMPLETE, _DYN_PROCESS_NEXT, _DYN_PUSH } from "../__DynamicConstants";
import { arrForEach, isArray, objFreeze, throwError } from "./HelperFuncs";
import { STR_PRIORITY } from "./InternalConstants";
import { createProcessTelemetryContext, createTelemetryProxyChain } from "./ProcessTelemetryContext";
import { initializePlugins } from "./TelemetryHelpers";
export var ChannelControllerPriority = 500;
var ChannelValidationMessage = "Channel has invalid priority - ";
function _addChannelQueue(channelQueue, queue, core) {
    if (queue && isArray(queue) && queue[_DYN_LENGTH /* @min:%2elength */] > 0) {
        queue = queue.sort(function (a, b) {
            return a[STR_PRIORITY /* @min:%2epriority */] - b[STR_PRIORITY /* @min:%2epriority */];
        });
        arrForEach(queue, function (queueItem) {
            if (queueItem[STR_PRIORITY /* @min:%2epriority */] < ChannelControllerPriority) {
                throwError(ChannelValidationMessage + queueItem[_DYN_IDENTIFIER /* @min:%2eidentifier */]);
            }
        });
        channelQueue[_DYN_PUSH /* @min:%2epush */]({
            queue: objFreeze(queue),
            chain: createTelemetryProxyChain(queue, core[_DYN_CONFIG /* @min:%2econfig */], core)
        });
    }
}
export function createChannelControllerPlugin(channelQueue, core) {
    function _getTelCtx() {
        return createProcessTelemetryContext(null, core[_DYN_CONFIG /* @min:%2econfig */], core, null);
    }
    function _processChannelQueue(theChannels, itemCtx, processFn, onComplete) {
        var waiting = theChannels ? (theChannels[_DYN_LENGTH /* @min:%2elength */] + 1) : 1;
        function _runChainOnComplete() {
            waiting--;
            if (waiting === 0) {
                onComplete && onComplete();
                onComplete = null;
            }
        }
        if (waiting > 0) {
            arrForEach(theChannels, function (channels) {
                // pass on to first item in queue
                if (channels && channels.queue[_DYN_LENGTH /* @min:%2elength */] > 0) {
                    var channelChain = channels.chain;
                    var chainCtx = itemCtx[_DYN_CREATE_NEW /* @min:%2ecreateNew */](channelChain);
                    chainCtx[_DYN_ON_COMPLETE /* @min:%2eonComplete */](_runChainOnComplete);
                    // Cause this chain to start processing
                    processFn(chainCtx);
                }
                else {
                    waiting--;
                }
            });
        }
        _runChainOnComplete();
    }
    function _doUpdate(updateCtx, updateState) {
        var theUpdateState = updateState || {
            reason: 0 /* TelemetryUpdateReason.Unknown */
        };
        _processChannelQueue(channelQueue, updateCtx, function (chainCtx) {
            chainCtx[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */](theUpdateState);
        }, function () {
            updateCtx[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */](theUpdateState);
        });
        return true;
    }
    function _doTeardown(unloadCtx, unloadState) {
        var theUnloadState = unloadState || {
            reason: 0 /* TelemetryUnloadReason.ManualTeardown */,
            isAsync: false
        };
        _processChannelQueue(channelQueue, unloadCtx, function (chainCtx) {
            chainCtx[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */](theUnloadState);
        }, function () {
            unloadCtx[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */](theUnloadState);
            isInitialized = false;
        });
        return true;
    }
    function _getChannel(pluginIdentifier) {
        var thePlugin = null;
        if (channelQueue && channelQueue[_DYN_LENGTH /* @min:%2elength */] > 0) {
            arrForEach(channelQueue, function (channels) {
                // pass on to first item in queue
                if (channels && channels.queue[_DYN_LENGTH /* @min:%2elength */] > 0) {
                    arrForEach(channels.queue, function (ext) {
                        if (ext[_DYN_IDENTIFIER /* @min:%2eidentifier */] === pluginIdentifier) {
                            thePlugin = ext;
                            // Cause arrForEach to stop iterating
                            return -1;
                        }
                    });
                    if (thePlugin) {
                        // Cause arrForEach to stop iterating
                        return -1;
                    }
                }
            });
        }
        return thePlugin;
    }
    var isInitialized = false;
    var channelController = {
        identifier: "ChannelControllerPlugin",
        priority: ChannelControllerPriority,
        initialize: function (config, core, extensions, pluginChain) {
            isInitialized = true;
            arrForEach(channelQueue, function (channels) {
                if (channels && channels.queue[_DYN_LENGTH /* @min:%2elength */] > 0) {
                    initializePlugins(createProcessTelemetryContext(channels.chain, config, core), extensions);
                }
            });
        },
        isInitialized: function () {
            return isInitialized;
        },
        processTelemetry: function (item, itemCtx) {
            _processChannelQueue(channelQueue, itemCtx || _getTelCtx(), function (chainCtx) {
                chainCtx[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */](item);
            }, function () {
                itemCtx[_DYN_PROCESS_NEXT /* @min:%2eprocessNext */](item);
            });
        },
        update: _doUpdate,
        pause: function () {
            _processChannelQueue(channelQueue, _getTelCtx(), function (chainCtx) {
                chainCtx.iterate(function (plugin) {
                    plugin.pause && plugin.pause();
                });
            }, null);
        },
        resume: function () {
            _processChannelQueue(channelQueue, _getTelCtx(), function (chainCtx) {
                chainCtx.iterate(function (plugin) {
                    plugin.resume && plugin.resume();
                });
            }, null);
        },
        teardown: _doTeardown,
        getChannel: _getChannel,
        flush: function (isAsync, callBack, sendReason, cbTimeout) {
            // Setting waiting to one so that we don't call the callBack until we finish iterating
            var waiting = 1;
            var doneIterating = false;
            var cbTimer = null;
            cbTimeout = cbTimeout || 5000;
            function doCallback() {
                waiting--;
                if (doneIterating && waiting === 0) {
                    if (cbTimer) {
                        clearTimeout(cbTimer);
                        cbTimer = null;
                    }
                    callBack && callBack(doneIterating);
                    callBack = null;
                }
            }
            _processChannelQueue(channelQueue, _getTelCtx(), function (chainCtx) {
                chainCtx.iterate(function (plugin) {
                    if (plugin[_DYN_FLUSH /* @min:%2eflush */]) {
                        waiting++;
                        var handled_1 = false;
                        // Not all channels will call this callback for every scenario
                        if (!plugin[_DYN_FLUSH /* @min:%2eflush */](isAsync, function () {
                            handled_1 = true;
                            doCallback();
                        }, sendReason)) {
                            if (!handled_1) {
                                // If any channel doesn't return true and it didn't call the callback, then we should assume that the callback
                                // will never be called, so use a timeout to allow the channel(s) some time to "finish" before triggering any
                                // followup function (such as unloading)
                                if (isAsync && cbTimer == null) {
                                    cbTimer = setTimeout(function () {
                                        cbTimer = null;
                                        doCallback();
                                    }, cbTimeout);
                                }
                                else {
                                    doCallback();
                                }
                            }
                        }
                    }
                });
            }, function () {
                doneIterating = true;
                doCallback();
            });
            return true;
        },
        _setQueue: function (queue) {
            channelQueue = queue;
        }
    };
    return channelController;
}
export function createChannelQueues(channels, extensions, core) {
    var channelQueue = [];
    if (channels) {
        // Add and sort the configuration channel queues
        arrForEach(channels, function (queue) { return _addChannelQueue(channelQueue, queue, core); });
    }
    if (extensions) {
        // Create a new channel queue for any extensions with a priority > the ChannelControllerPriority
        var extensionQueue_1 = [];
        arrForEach(extensions, function (plugin) {
            if (plugin[STR_PRIORITY /* @min:%2epriority */] > ChannelControllerPriority) {
                extensionQueue_1[_DYN_PUSH /* @min:%2epush */](plugin);
            }
        });
        _addChannelQueue(channelQueue, extensionQueue_1, core);
    }
    return channelQueue;
}
