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


import { Extensions, arrForEach, dataSanitizeUrl, dateTimeUtilsDuration, isNullOrUndefined, isNumber, isString, msToTimeSpan, normalizeJsName, objForEachKey, objKeys, urlGetAbsoluteUrl, urlGetCompleteUrl } 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_GET_ABSOLUTE_URL, _DYN_HEADER_MAP, _DYN_LENGTH, _DYN_METHOD, _DYN_PERF_TIMING, _DYN_REQUEST_HEADERS, _DYN_REQUEST_SENT_TIME, _DYN_REQUEST_URL, _DYN_RESPONSE_FINISHED_TI12, _DYN_RESPONSE_TEXT, _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.perfMark) {
            propsSet |= _setPerfValue(props, "missing", ajaxData.perfAttempts);
        }
    }
    if (propsSet) {
        dependency[STR_PROPERTIES /* @min:%2eproperties */] = props;
    }
}
/**
 * Factory function to create an XHR monitoring state object
 * @returns An object implementing IXHRMonitoringState interface
 */
export function createXHRMonitoringState() {
    var _a;
    return _a = {
            openDone: false,
            setRequestHeaderDone: false,
            sendDone: false,
            abortDone: false
        },
        _a[_DYN_STATE_CHANGE_ATTACHE11 /* @min:stateChangeAttached */] = false,
        _a;
}
/**
 * Factory function to create an ajax record that implements IAjaxRecordInternal
 * @param traceCtx - The distributed trace context for the ajax request
 * @param logger - The diagnostic logger instance
 * @returns An object implementing IAjaxRecordInternal interface
 */
export function createAjaxRecord(traceCtx, logger) {
    var _a;
    var _logger = logger;
    // Create the ajax record object implementing IAjaxRecordInternal
    var ajaxRecord = (_a = {
            // Initialize all properties with default values
            perfMark: null,
            completed: false,
            requestHeadersSize: null
        },
        _a[_DYN_REQUEST_HEADERS /* @min:requestHeaders */] = null,
        _a.responseReceivingDuration = null,
        _a.callbackDuration = null,
        _a[_DYN_AJAX_TOTAL_DURATION /* @min:ajaxTotalDuration */] = null,
        _a.aborted = 0,
        _a.pageUrl = null,
        _a.requestUrl = null,
        _a.requestSize = 0,
        _a.method = null,
        _a.status = null,
        _a[_DYN_REQUEST_SENT_TIME /* @min:requestSentTime */] = null,
        _a.responseStartedTime = null,
        _a[_DYN_RESPONSE_FINISHED_TI12 /* @min:responseFinishedTime */] = null,
        _a.callbackFinishedTime = null,
        _a.endTime = null,
        _a.xhrMonitoringState = createXHRMonitoringState(),
        _a.clientFailure = 0,
        _a.traceCtx = traceCtx,
        _a.perfTiming = null,
        _a[_DYN_GET_ABSOLUTE_URL /* @min:getAbsoluteUrl */] = function () {
            return ajaxRecord[_DYN_REQUEST_URL /* @min:%2erequestUrl */] ? urlGetAbsoluteUrl(ajaxRecord[_DYN_REQUEST_URL /* @min:%2erequestUrl */]) : null;
        },
        _a.getPathName = function () {
            return ajaxRecord[_DYN_REQUEST_URL /* @min:%2erequestUrl */] ? dataSanitizeUrl(_logger, urlGetCompleteUrl(ajaxRecord[_DYN_METHOD /* @min:%2emethod */], ajaxRecord[_DYN_REQUEST_URL /* @min:%2erequestUrl */])) : null;
        },
        _a[_DYN__CREATE_TRACK_ITEM /* @min:CreateTrackItem */] = function (ajaxType, enableRequestHeaderTracking, getResponse) {
            var _a;
            // round to 3 decimal points
            ajaxRecord.ajaxTotalDuration = mathRound(dateTimeUtilsDuration(ajaxRecord.requestSentTime, ajaxRecord.responseFinishedTime) * 1000) / 1000;
            if (ajaxRecord[_DYN_AJAX_TOTAL_DURATION /* @min:%2eajaxTotalDuration */] < 0) {
                return null;
            }
            var dependency = (_a = {
                    // Always use the traceId and spanId from the traceCtx, this is the same as the
                    // traceId and spanId used to create the ajaxRecord, this is to ensure that
                    // the traceId and spanId are always the same for the ajaxRecord and the dependency
                    // This is important for the distributed tracing to work correctly
                    id: "|" + traceCtx[_DYN_TRACE_ID /* @min:%2etraceId */] + "." + traceCtx[_DYN_SPAN_ID /* @min:%2espanId */],
                    target: ajaxRecord[_DYN_GET_ABSOLUTE_URL /* @min:%2egetAbsoluteUrl */](),
                    name: ajaxRecord.getPathName(),
                    type: ajaxType,
                    startTime: null,
                    duration: ajaxRecord[_DYN_AJAX_TOTAL_DURATION /* @min:%2eajaxTotalDuration */],
                    success: (+(ajaxRecord[_DYN_STATUS /* @min:%2estatus */])) >= 200 && (+(ajaxRecord[_DYN_STATUS /* @min:%2estatus */])) < 400,
                    responseCode: (+(ajaxRecord[_DYN_STATUS /* @min:%2estatus */]))
                },
                _a[STR_PROPERTIES] = { HttpMethod: ajaxRecord[_DYN_METHOD /* @min:%2emethod */] },
                _a);
            var props = dependency[STR_PROPERTIES];
            if (ajaxRecord[_DYN_ABORTED /* @min:%2eaborted */]) {
                props[_DYN_ABORTED /* @min:%2eaborted */] = true;
            }
            if (ajaxRecord[_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(ajaxRecord[_DYN_REQUEST_SENT_TIME /* @min:%2erequestSentTime */]);
            }
            // Add Ajax perf details if available
            _populatePerfData(this, dependency);
            if (enableRequestHeaderTracking) {
                if (objKeys(ajaxRecord.requestHeaders)[_DYN_LENGTH /* @min:%2elength */] > 0) {
                    props[_DYN_REQUEST_HEADERS /* @min:%2erequestHeaders */] = ajaxRecord[_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 (ajaxRecord[_DYN_ERROR_STATUS_TEXT /* @min:%2eerrorStatusText */]) {
                        if ((+(ajaxRecord[_DYN_STATUS /* @min:%2estatus */])) >= 400) {
                            var responseType = response.type;
                            if (responseType === "" || responseType === "text") {
                                props.responseText = response.responseText ? response[_DYN_STATUS_TEXT /* @min:%2estatusText */] + " - " + response[_DYN_RESPONSE_TEXT /* @min:%2eresponseText */] : 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 (ajaxRecord[_DYN_STATUS /* @min:%2estatus */] === 0) {
                            props.responseText = response[_DYN_STATUS_TEXT /* @min:%2estatusText */] || "";
                        }
                    }
                }
            }
            return dependency;
        },
        _a.getPartAProps = function () {
            var partA = null;
            var parentCtx = ajaxRecord.traceCtx.parentCtx;
            if (parentCtx && (parentCtx[_DYN_TRACE_ID /* @min:%2etraceId */] || parentCtx[_DYN_SPAN_ID /* @min:%2espanId */])) {
                partA = {};
                var traceExt = partA[Extensions.TraceExt] = {
                    traceID: parentCtx[_DYN_TRACE_ID /* @min:%2etraceId */],
                    parentID: parentCtx[_DYN_SPAN_ID /* @min:%2espanId */]
                };
                if (!isNullOrUndefined(parentCtx[_DYN_TRACE_FLAGS /* @min:%2etraceFlags */])) {
                    traceExt[_DYN_TRACE_FLAGS /* @min:%2etraceFlags */] = parentCtx[_DYN_TRACE_FLAGS /* @min:%2etraceFlags */];
                }
            }
            return partA;
        },
        _a);
    return ajaxRecord;
}
//# sourceMappingURL=ajaxRecord.js.map