/*
 * Application Insights JavaScript SDK - Properties Plugin, 3.4.3
 * Copyright (c) Microsoft and contributors. All rights reserved.
 */
/**
* TelemetryContext.ts
* @copyright Microsoft 2018
*/
import dynamicProto from "@microsoft/dynamicproto-js";
import { CtxTagKeys, Extensions, PageViewDataType, _InternalLogMessage, dataSanitizeString, getSetValue, hasWindow, isNullOrUndefined, isString, objKeys, setValue } from "@microsoft/applicationinsights-core-js";
import { fnCall, getDeferred, isFunction, isUndefined, objDefine, objDefineProps, strLetterCase } from "@nevware21/ts-utils";
import { Application } from "./Context/Application";
import { Device } from "./Context/Device";
import { Internal } from "./Context/Internal";
import { Location } from "./Context/Location";
import { Session, _SessionManager } from "./Context/Session";
import { User } from "./Context/User";
import { _DYN_ACCOUNT_ID, _DYN_APPLY_APPLICATION_CO1, _DYN_APPLY_INTERNAL_CONTE5, _DYN_APPLY_LOCATION_CONTE4, _DYN_APPLY_OPERATING_SYST3, _DYN_APPLY_OPERATION_CONT2, _DYN_APPLY_SESSION_CONTEX0, _DYN_AUTHENTICATED_ID, _DYN_AUTOMATIC_SESSION, _DYN_GET_SESSION_ID, _DYN_SESSION, _DYN_SESSION_MANAGER } from "./__DynamicConstants";
var strExt = "ext";
var strTags = "tags";
var UNDEF_VALUE;
function _removeEmpty(target, name) {
    if (target && target[name] && objKeys(target[name]).length === 0) {
        delete target[name];
    }
}
function _nullResult() {
    return null;
}
/**
 * Create a telemetryTrace object that will be used to manage the trace context for the current telemetry item.
 * This will create a proxy object that will read the values from the core.getTraceCtx() and provide a way to update the values
 * in the core.getTraceCtx() if they are valid.
 * @param core - The core instance that will be used to get the trace context
 * @returns A telemetryTrace object that will be used to manage the trace context for the current telemetry item.
 */
function _createTelemetryTrace(core) {
    var coreTraceCtx = core ? core.getTraceCtx() : null;
    var trace = {};
    function _getCtx() {
        var ctx = core ? core.getTraceCtx() : null;
        if (coreTraceCtx && ctx !== coreTraceCtx) {
            // It appears that the coreTraceCtx has been updated, so clear the local trace context
            trace = {};
        }
        return ctx;
    }
    function _getTraceCtx(name) {
        var value;
        var ctx = _getCtx();
        if (!isUndefined(trace[name])) {
            // has local value
            value = trace[name];
        }
        else if (ctx) {
            if (name in ctx) {
                // has property
                value = ctx[name];
            }
            else {
                var fnName = "get" + strLetterCase(name);
                if (isFunction(ctx[fnName])) {
                    value = ctx[fnName];
                }
            }
            if (isFunction(value)) {
                // The return values was a function, call it
                value = fnCall(value, ctx);
            }
        }
        return value;
    }
    function _setTraceCtx(name, value, checkFn) {
        var ctx = _getCtx();
        if (ctx) {
            if (name in ctx) {
                if (isFunction(ctx[name])) {
                    // The return values was a function, call it
                    fnCall(ctx[name], ctx, [value]);
                }
                else {
                    ctx[name] = value;
                }
            }
            else {
                var fnName = "set" + strLetterCase(name);
                if (isFunction(ctx[fnName])) {
                    ctx[fnName](value);
                }
            }
            // For backward compatability, we need to support invalid values for historic reasons,
            // moving forward we have marked the usage of the telemetryTrace as deprecated and will be removed in a future version.
            // We will only set the value in the local trace context if it is a valid trace ID or a string, otherwise we will remove it
            trace[name] = UNDEF_VALUE;
            if (value && isString(value)) {
                // If the value is null or undefined, remove it from the local trace context
                if (checkFn && checkFn() !== value) {
                    // If the values doesn't match (most likely because the value is invalid), set the value in the local trace context
                    coreTraceCtx = ctx;
                    trace[name] = value;
                }
            }
        }
    }
    function _getTraceId() {
        return _getTraceCtx("traceId");
    }
    function _getParentId() {
        var ctx = _getCtx();
        var spanId = trace["spanId"];
        if (ctx && isUndefined(spanId)) {
            var parentCtx = ctx.parentCtx;
            if (parentCtx) {
                spanId = parentCtx.spanId;
            }
        }
        return spanId || _getTraceCtx("spanId");
    }
    function _getTraceFlags() {
        return _getTraceCtx("traceFlags");
    }
    function _getName() {
        return dataSanitizeString(core ? core.logger : null, _getTraceCtx("getName") || _getTraceCtx("pageName"));
    }
    function _setValue(name, checkFn) {
        return function (value) {
            _setTraceCtx(name, value, checkFn);
        };
    }
    return objDefineProps({}, {
        traceID: {
            g: _getTraceId,
            s: _setValue("traceId", _getTraceId)
        },
        parentID: {
            g: _getParentId,
            s: _setValue("spanId", _getParentId)
        },
        traceFlags: {
            g: _getTraceFlags,
            s: _setValue("traceFlags", _getTraceFlags)
        },
        name: {
            g: _getName,
            s: _setValue("pageName", _getName)
        }
    });
}
var TelemetryContext = /** @class */ (function () {
    function TelemetryContext(core, defaultConfig, unloadHookContainer) {
        var _this = this;
        var logger = core.logger;
        dynamicProto(TelemetryContext, this, function (_self) {
            _self.appId = _nullResult;
            _self[_DYN_GET_SESSION_ID /* @min:%2egetSessionId */] = _nullResult;
            _self.application = new Application();
            _self.internal = new Internal(defaultConfig, unloadHookContainer);
            if (hasWindow()) {
                _self[_DYN_SESSION_MANAGER /* @min:%2esessionManager */] = new _SessionManager(defaultConfig, core, unloadHookContainer);
                _self.device = new Device();
                _self.location = new Location();
                _self.user = new User(defaultConfig, core, unloadHookContainer);
                _self[_DYN_SESSION /* @min:%2esession */] = new Session();
                objDefine(_self, "telemetryTrace", {
                    l: getDeferred(function () { return _createTelemetryTrace(core); })
                });
            }
            _self[_DYN_GET_SESSION_ID /* @min:%2egetSessionId */] = function () {
                var session = _self[_DYN_SESSION /* @min:%2esession */];
                var sesId = null;
                // If customer set session info, apply their context; otherwise apply context automatically generated
                if (session && isString(session.id)) {
                    sesId = session.id;
                }
                else {
                    // Gets the automatic session if it exists or an empty object
                    var autoSession = (_self[_DYN_SESSION_MANAGER /* @min:%2esessionManager */] || {})[_DYN_AUTOMATIC_SESSION /* @min:%2eautomaticSession */];
                    sesId = autoSession && isString(autoSession.id) ? autoSession.id : null;
                }
                return sesId;
            };
            _self[_DYN_APPLY_SESSION_CONTEX0 /* @min:%2eapplySessionContext */] = function (evt, itemCtx) {
                setValue(getSetValue(evt.ext, Extensions.AppExt), "sesId", _self[_DYN_GET_SESSION_ID /* @min:%2egetSessionId */](), isString);
            };
            _self[_DYN_APPLY_OPERATING_SYST3 /* @min:%2eapplyOperatingSystemContxt */] = function (evt, itemCtx) {
                setValue(evt.ext, Extensions.OSExt, _self.os);
            };
            _self[_DYN_APPLY_APPLICATION_CO1 /* @min:%2eapplyApplicationContext */] = function (evt, itemCtx) {
                var application = _self.application;
                if (application) {
                    // evt.ext.app
                    var tags = getSetValue(evt, strTags);
                    setValue(tags, CtxTagKeys.applicationVersion, application.ver, isString);
                    setValue(tags, CtxTagKeys.applicationBuild, application.build, isString);
                }
            };
            _self.applyDeviceContext = function (evt, itemCtx) {
                var device = _self.device;
                if (device) {
                    // evt.ext.device
                    var extDevice = getSetValue(getSetValue(evt, strExt), Extensions.DeviceExt);
                    setValue(extDevice, "localId", device.id, isString);
                    setValue(extDevice, "ip", device.ip, isString);
                    setValue(extDevice, "model", device.model, isString);
                    setValue(extDevice, "deviceClass", device.deviceClass, isString);
                }
            };
            _self[_DYN_APPLY_INTERNAL_CONTE5 /* @min:%2eapplyInternalContext */] = function (evt, itemCtx) {
                var internal = _self.internal;
                if (internal) {
                    var tags = getSetValue(evt, strTags);
                    setValue(tags, CtxTagKeys.internalAgentVersion, internal.agentVersion, isString); // not mapped in CS 4.0
                    setValue(tags, CtxTagKeys.internalSdkVersion, dataSanitizeString(logger, internal.sdkVersion, 64), isString);
                    if (evt.baseType === _InternalLogMessage.dataType || evt.baseType === PageViewDataType) {
                        setValue(tags, CtxTagKeys.internalSnippet, internal.snippetVer, isString);
                        setValue(tags, CtxTagKeys.internalSdkSrc, internal.sdkSrc, isString);
                    }
                }
            };
            _self[_DYN_APPLY_LOCATION_CONTE4 /* @min:%2eapplyLocationContext */] = function (evt, itemCtx) {
                var location = _this.location;
                if (location) {
                    setValue(getSetValue(evt, strTags, []), CtxTagKeys.locationIp, location.ip, isString);
                }
            };
            _self[_DYN_APPLY_OPERATION_CONT2 /* @min:%2eapplyOperationContext */] = function (evt, itemCtx) {
                var telemetryTrace = _self.telemetryTrace;
                if (telemetryTrace) {
                    var extTrace = getSetValue(getSetValue(evt, strExt), Extensions.TraceExt, { traceID: undefined, parentID: undefined });
                    setValue(extTrace, "traceID", telemetryTrace.traceID, isString, isNullOrUndefined);
                    setValue(extTrace, "name", telemetryTrace.name, isString, isNullOrUndefined);
                    setValue(extTrace, "parentID", telemetryTrace.parentID, isString, isNullOrUndefined);
                }
            };
            _self.applyWebContext = function (evt, itemCtx) {
                var web = _this.web;
                if (web) {
                    setValue(getSetValue(evt, strExt), Extensions.WebExt, web);
                }
            };
            _self.applyUserContext = function (evt, itemCtx) {
                var user = _self.user;
                if (user) {
                    var tags = getSetValue(evt, strTags, []);
                    // stays in tags
                    setValue(tags, CtxTagKeys.userAccountId, user[_DYN_ACCOUNT_ID /* @min:%2eaccountId */], isString);
                    // CS 4.0
                    var extUser = getSetValue(getSetValue(evt, strExt), Extensions.UserExt);
                    setValue(extUser, "id", user.id, isString);
                    setValue(extUser, "authId", user[_DYN_AUTHENTICATED_ID /* @min:%2eauthenticatedId */], isString);
                }
            };
            _self.cleanUp = function (evt, itemCtx) {
                var ext = evt.ext;
                if (ext) {
                    _removeEmpty(ext, Extensions.DeviceExt);
                    _removeEmpty(ext, Extensions.UserExt);
                    _removeEmpty(ext, Extensions.WebExt);
                    _removeEmpty(ext, Extensions.OSExt);
                    _removeEmpty(ext, Extensions.AppExt);
                    _removeEmpty(ext, Extensions.TraceExt);
                }
            };
        });
    }
// Removed Stub for TelemetryContext.prototype.applySessionContext.
// Removed Stub for TelemetryContext.prototype.applyOperatingSystemContxt.
// Removed Stub for TelemetryContext.prototype.applyApplicationContext.
// Removed Stub for TelemetryContext.prototype.applyDeviceContext.
// Removed Stub for TelemetryContext.prototype.applyInternalContext.
// Removed Stub for TelemetryContext.prototype.applyLocationContext.
// Removed Stub for TelemetryContext.prototype.applyOperationContext.
// Removed Stub for TelemetryContext.prototype.applyWebContext.
// Removed Stub for TelemetryContext.prototype.applyUserContext.
// Removed Stub for TelemetryContext.prototype.cleanUp.
    // 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.
    TelemetryContext.__ieDyn=1;

    return TelemetryContext;
}());
export { TelemetryContext };
//# sourceMappingURL=TelemetryContext.js.map