/*
 * Application Insights JavaScript SDK - Dependencies Plugin, 3.3.9-nightly3.2505-37
 * Copyright (c) Microsoft and contributors. All rights reserved.
 */


import dynamicProto from "@microsoft/dynamicproto-js";
import { Extensions, dataSanitizeUrl, dateTimeUtilsDuration, msToTimeSpan, urlGetAbsoluteUrl, urlGetCompleteUrl } from "@microsoft/applicationinsights-common";
import { arrForEach, isNullOrUndefined, isNumber, isString, normalizeJsName, objForEachKey, objKeys } from "@microsoft/applicationinsights-core-js";
import { mathRound } from "@nevware21/ts-utils";
import { STR_DURATION, STR_PROPERTIES } from "./InternalConstants";
import { _DYN_ABORTED, _DYN_AJAX_TOTAL_DURATION, _DYN_CORRELATION_CONTEXT, _DYN_ERROR_STATUS_TEXT, _DYN_EVENT_TRACE_CTX, _DYN_GET_ABSOLUTE_URL, _DYN_GET_PART_APROPS, _DYN_GET_TRACE_FLAGS, _DYN_GET_TRACE_ID, _DYN_HEADER_MAP, _DYN_LENGTH, _DYN_METHOD, _DYN_PERF_MARK, _DYN_PERF_TIMING, _DYN_REQUEST_HEADERS, _DYN_REQUEST_SENT_TIME, _DYN_REQUEST_URL, _DYN_RESPONSE_FINISHED_TI12, _DYN_SPAN_ID, _DYN_START_TIME, _DYN_STATE_CHANGE_ATTACHE11, _DYN_STATUS, _DYN_STATUS_TEXT, _DYN_TRACE_FLAGS, _DYN_TRACE_ID, _DYN__CREATE_TRACK_ITEM } from "./__DynamicConstants";
/** @ignore */
function _calcPerfDuration(resourceEntry, start, end) {
    var result = 0;
    var from = resourceEntry[start];
    var to = resourceEntry[end];
    if (from && to) {
        result = dateTimeUtilsDuration(from, to);
    }
    return result;
}
/** @ignore */
function _setPerfDuration(props, name, resourceEntry, start, end) {
    var result = 0;
    var value = _calcPerfDuration(resourceEntry, start, end);
    if (value) {
        result = _setPerfValue(props, name, msToTimeSpan(value));
    }
    return result;
}
/** @ignore */
function _setPerfValue(props, name, value) {
    var strPerf = "ajaxPerf";
    var result = 0;
    if (props && name && value) {
        var perfData = props[strPerf] = (props[strPerf] || {});
        perfData[name] = value;
        result = 1;
    }
    return result;
}
/** @ignore */
function _populatePerfData(ajaxData, dependency) {
    /*
    * https://developer.mozilla.org/en-US/docs/Web/API/Resource_Timing_API/Using_the_Resource_Timing_API
    *  | -startTime
    *  | -redirectStart
    *  |            | -redirectEnd
    *  |            | | -fetchStart
    *  |            | |   | -domainLookupStart
    *  |            | |   |                |- domainLookupEnd
    *  |            | |   |                | | -connectStart
    *  |            | |   |                | |  | -secureConnectionStart
    *  |            | |   |                | |  |        | -connectEnd
    *  |            | |   |                | |  |        | | -requestStart
    *  |            | |   |                | |  |        | |           | | -responseStart
    *  |            | |   |                | |  |        | |           | |            | | -responseEnd
    *  +------------+-+---+----------------+-+--+--------+-+-----------+-+------------+-+
    *  |--redirect--| |---|--domainLookup--| |--connect--| |--request--| |--response--| |
    *  |-------------------networkConnect----------------|
    *  |                                                   |---------sentRequest--------|
    *  |------------------------------------perfTotal-----------------------------------|
    */
    var resourceEntry = ajaxData[_DYN_PERF_TIMING /* @min:%2eperfTiming */];
    var props = dependency[STR_PROPERTIES /* @min:%2eproperties */] || {};
    var propsSet = 0;
    var strName = "name";
    var strStart = "Start";
    var strEnd = "End";
    var strDomainLookup = "domainLookup";
    var strConnect = "connect";
    var strRedirect = "redirect";
    var strRequest = "request";
    var strResponse = "response";
    var strStartTime = "startTime";
    var strDomainLookupStart = strDomainLookup + strStart;
    var strDomainLookupEnd = strDomainLookup + strEnd;
    var strConnectStart = strConnect + strStart;
    var strConnectEnd = strConnect + strEnd;
    var strRequestStart = strRequest + strStart;
    var strRequestEnd = strRequest + strEnd;
    var strResponseStart = strResponse + strStart;
    var strResponseEnd = strResponse + strEnd;
    var strRedirectStart = strRedirect + strStart;
    var strRedirectEnd = strRedirect = strEnd;
    var strTransferSize = "transferSize";
    var strEncodedBodySize = "encodedBodySize";
    var strDecodedBodySize = "decodedBodySize";
    var strServerTiming = "serverTiming";
    if (resourceEntry) {
        // redirect
        propsSet |= _setPerfDuration(props, strRedirect, resourceEntry, strRedirectStart, strRedirectEnd);
        // domainLookup
        propsSet |= _setPerfDuration(props, strDomainLookup, resourceEntry, strDomainLookupStart, strDomainLookupEnd);
        // connect
        propsSet |= _setPerfDuration(props, strConnect, resourceEntry, strConnectStart, strConnectEnd);
        // request
        propsSet |= _setPerfDuration(props, strRequest, resourceEntry, strRequestStart, strRequestEnd);
        // response
        propsSet |= _setPerfDuration(props, strResponse, resourceEntry, strResponseStart, strResponseEnd);
        // Network connection time
        propsSet |= _setPerfDuration(props, "networkConnect", resourceEntry, strStartTime, strConnectEnd);
        // Sent Request
        propsSet |= _setPerfDuration(props, "sentRequest", resourceEntry, strRequestStart, strResponseEnd);
        // PerfTotal / Duration
        var duration = resourceEntry[STR_DURATION /* @min:%2eduration */];
        if (!duration) {
            duration = _calcPerfDuration(resourceEntry, strStartTime, strResponseEnd) || 0;
        }
        propsSet |= _setPerfValue(props, STR_DURATION, duration);
        propsSet |= _setPerfValue(props, "perfTotal", duration);
        var serverTiming = resourceEntry[strServerTiming];
        if (serverTiming) {
            var server_1 = {};
            arrForEach(serverTiming, function (value, idx) {
                var name = normalizeJsName(value[strName] || "" + idx);
                var newValue = server_1[name] || {};
                objForEachKey(value, function (key, val) {
                    if (key !== strName && isString(val) || isNumber(val)) {
                        if (newValue[key]) {
                            val = newValue[key] + ";" + val;
                        }
                        if (val || !isString(val)) {
                            // Only set the value if it has a value and it's not an empty string
                            newValue[key] = val;
                        }
                    }
                });
                server_1[name] = newValue;
            });
            propsSet |= _setPerfValue(props, strServerTiming, server_1);
        }
        propsSet |= _setPerfValue(props, strTransferSize, resourceEntry[strTransferSize]);
        propsSet |= _setPerfValue(props, strEncodedBodySize, resourceEntry[strEncodedBodySize]);
        propsSet |= _setPerfValue(props, strDecodedBodySize, resourceEntry[strDecodedBodySize]);
    }
    else {
        if (ajaxData[_DYN_PERF_MARK /* @min:%2eperfMark */]) {
            propsSet |= _setPerfValue(props, "missing", ajaxData.perfAttempts);
        }
    }
    if (propsSet) {
        dependency[STR_PROPERTIES /* @min:%2eproperties */] = props;
    }
}
var XHRMonitoringState = /** @class */ (function () {
    function XHRMonitoringState() {
        var self = this;
        self.openDone = false;
        self.setRequestHeaderDone = false;
        self.sendDone = false;
        self.abortDone = false;
        // <summary>True, if onreadyStateChangeCallback function attached to xhr, otherwise false</summary>
        self[_DYN_STATE_CHANGE_ATTACHE11 /* @min:%2estateChangeAttached */] = false;
    }
    return XHRMonitoringState;
}());
export { XHRMonitoringState };
var ajaxRecord = /** @class */ (function () {
    function ajaxRecord(traceId, spanId, logger, traceCtx) {
        var self = this;
        var _logger = logger;
        var strResponseText = "responseText";
        // Assigning the initial/default values within the constructor to avoid typescript from creating a bunch of
        // this.XXXX = null
        self[_DYN_PERF_MARK /* @min:%2eperfMark */] = null;
        self.completed = false;
        self.requestHeadersSize = null;
        self[_DYN_REQUEST_HEADERS /* @min:%2erequestHeaders */] = null;
        self.responseReceivingDuration = null;
        self.callbackDuration = null;
        self[_DYN_AJAX_TOTAL_DURATION /* @min:%2eajaxTotalDuration */] = null;
        self[_DYN_ABORTED /* @min:%2eaborted */] = 0;
        self.pageUrl = null;
        self[_DYN_REQUEST_URL /* @min:%2erequestUrl */] = null;
        self.requestSize = 0;
        self[_DYN_METHOD /* @min:%2emethod */] = null;
        self[_DYN_STATUS /* @min:%2estatus */] = null;
        self[_DYN_REQUEST_SENT_TIME /* @min:%2erequestSentTime */] = null;
        self.responseStartedTime = null;
        self[_DYN_RESPONSE_FINISHED_TI12 /* @min:%2eresponseFinishedTime */] = null;
        self.callbackFinishedTime = null;
        self.endTime = null;
        self.xhrMonitoringState = new XHRMonitoringState();
        self.clientFailure = 0;
        self[_DYN_TRACE_ID /* @min:%2etraceID */] = traceId;
        self[_DYN_SPAN_ID /* @min:%2espanID */] = spanId;
        self[_DYN_TRACE_FLAGS /* @min:%2etraceFlags */] = traceCtx === null || traceCtx === void 0 ? void 0 : traceCtx.getTraceFlags();
        if (traceCtx) {
            self[_DYN_EVENT_TRACE_CTX /* @min:%2eeventTraceCtx */] = {
                traceId: traceCtx[_DYN_GET_TRACE_ID /* @min:%2egetTraceId */](),
                spanId: traceCtx.getSpanId(),
                traceFlags: traceCtx[_DYN_GET_TRACE_FLAGS /* @min:%2egetTraceFlags */]()
            };
        }
        else {
            self[_DYN_EVENT_TRACE_CTX /* @min:%2eeventTraceCtx */] = null;
        }
        dynamicProto(ajaxRecord, self, function (self) {
            self.getAbsoluteUrl = function () {
                return self[_DYN_REQUEST_URL /* @min:%2erequestUrl */] ? urlGetAbsoluteUrl(self[_DYN_REQUEST_URL /* @min:%2erequestUrl */]) : null;
            };
            self.getPathName = function () {
                return self[_DYN_REQUEST_URL /* @min:%2erequestUrl */] ? dataSanitizeUrl(_logger, urlGetCompleteUrl(self[_DYN_METHOD /* @min:%2emethod */], self[_DYN_REQUEST_URL /* @min:%2erequestUrl */])) : null;
            };
            self[_DYN__CREATE_TRACK_ITEM /* @min:%2eCreateTrackItem */] = function (ajaxType, enableRequestHeaderTracking, getResponse) {
                var _a;
                // round to 3 decimal points
                self.ajaxTotalDuration = mathRound(dateTimeUtilsDuration(self.requestSentTime, self.responseFinishedTime) * 1000) / 1000;
                if (self[_DYN_AJAX_TOTAL_DURATION /* @min:%2eajaxTotalDuration */] < 0) {
                    return null;
                }
                var dependency = (_a = {
                        id: "|" + self[_DYN_TRACE_ID /* @min:%2etraceID */] + "." + self[_DYN_SPAN_ID /* @min:%2espanID */],
                        target: self[_DYN_GET_ABSOLUTE_URL /* @min:%2egetAbsoluteUrl */](),
                        name: self.getPathName(),
                        type: ajaxType,
                        startTime: null,
                        duration: self[_DYN_AJAX_TOTAL_DURATION /* @min:%2eajaxTotalDuration */],
                        success: (+(self[_DYN_STATUS /* @min:%2estatus */])) >= 200 && (+(self[_DYN_STATUS /* @min:%2estatus */])) < 400,
                        responseCode: (+(self[_DYN_STATUS /* @min:%2estatus */]))
                    },
                    _a[STR_PROPERTIES] = { HttpMethod: self[_DYN_METHOD /* @min:%2emethod */] },
                    _a);
                var props = dependency[STR_PROPERTIES];
                if (self[_DYN_ABORTED /* @min:%2eaborted */]) {
                    props[_DYN_ABORTED /* @min:%2eaborted */] = true;
                }
                if (self[_DYN_REQUEST_SENT_TIME /* @min:%2erequestSentTime */]) {
                    // Set the correct dependency start time
                    dependency[_DYN_START_TIME /* @min:%2estartTime */] = new Date();
                    dependency[_DYN_START_TIME /* @min:%2estartTime */].setTime(self[_DYN_REQUEST_SENT_TIME /* @min:%2erequestSentTime */]);
                }
                // Add Ajax perf details if available
                _populatePerfData(self, dependency);
                if (enableRequestHeaderTracking) {
                    if (objKeys(self.requestHeaders)[_DYN_LENGTH /* @min:%2elength */] > 0) {
                        props[_DYN_REQUEST_HEADERS /* @min:%2erequestHeaders */] = self[_DYN_REQUEST_HEADERS /* @min:%2erequestHeaders */];
                    }
                }
                if (getResponse) {
                    var response = getResponse();
                    if (response) {
                        // enrich dependency target with correlation context from the server
                        var correlationContext = response[_DYN_CORRELATION_CONTEXT /* @min:%2ecorrelationContext */];
                        if (correlationContext) {
                            dependency.correlationContext = /* dependency.target + " | " + */ correlationContext;
                        }
                        if (response[_DYN_HEADER_MAP /* @min:%2eheaderMap */]) {
                            if (objKeys(response.headerMap)[_DYN_LENGTH /* @min:%2elength */] > 0) {
                                props.responseHeaders = response[_DYN_HEADER_MAP /* @min:%2eheaderMap */];
                            }
                        }
                        if (self[_DYN_ERROR_STATUS_TEXT /* @min:%2eerrorStatusText */]) {
                            if (self[_DYN_STATUS /* @min:%2estatus */] >= 400) {
                                var responseType = response.type;
                                if (responseType === "" || responseType === "text") {
                                    props.responseText = response.responseText ? response[_DYN_STATUS_TEXT /* @min:%2estatusText */] + " - " + response[strResponseText] : response[_DYN_STATUS_TEXT /* @min:%2estatusText */];
                                }
                                if (responseType === "json") {
                                    props.responseText = response.response ? response[_DYN_STATUS_TEXT /* @min:%2estatusText */] + " - " + JSON.stringify(response.response) : response[_DYN_STATUS_TEXT /* @min:%2estatusText */];
                                }
                            }
                            else if (self[_DYN_STATUS /* @min:%2estatus */] === 0) {
                                props.responseText = response[_DYN_STATUS_TEXT /* @min:%2estatusText */] || "";
                            }
                        }
                    }
                }
                return dependency;
            };
            self[_DYN_GET_PART_APROPS /* @min:%2egetPartAProps */] = function () {
                var partA = null;
                var traceCtx = self[_DYN_EVENT_TRACE_CTX /* @min:%2eeventTraceCtx */];
                if (traceCtx && (traceCtx.traceId || traceCtx.spanId)) {
                    partA = {};
                    var traceExt = partA[Extensions.TraceExt] = {
                        traceID: traceCtx.traceId,
                        parentID: traceCtx.spanId
                    };
                    if (!isNullOrUndefined(traceCtx[_DYN_TRACE_FLAGS /* @min:%2etraceFlags */])) {
                        traceExt[_DYN_TRACE_FLAGS /* @min:%2etraceFlags */] = traceCtx[_DYN_TRACE_FLAGS /* @min:%2etraceFlags */];
                    }
                }
                return partA;
            };
        });
    }
// Removed Stub for ajaxRecord.prototype.getAbsoluteUrl.
// Removed Stub for ajaxRecord.prototype.getPathName.
// Removed Stub for ajaxRecord.prototype.CreateTrackItem.
// Removed Stub for ajaxRecord.prototype.getPartAProps.
    // 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.
    ajaxRecord.__ieDyn=1;

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