"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.p = exports.CdmProfiler = void 0;
// tslint:disable
// import { performance } from 'perf_hooks';
const internal_1 = require("../internal");
class CdmProfiler {
    constructor() {
        this.calls = new Map();
        this.callStack = [];
        this.on = false;
    }
    static getInternalClassList() {
        return [
            internal_1.CdmArgumentDefinition,
            internal_1.CdmAttributeContext,
            internal_1.CdmAttributeContextReference,
            internal_1.CdmAttributeGroupDefinition,
            internal_1.CdmAttributeGroupReference,
            internal_1.CdmAttribute,
            internal_1.CdmAttributeReference,
            internal_1.CdmObjectDefinitionBase,
            internal_1.CdmObjectReferenceBase,
            internal_1.cdmObjectSimple,
            internal_1.CdmObjectBase,
            internal_1.CdmConstantEntityDefinition,
            internal_1.CdmCorpusDefinition,
            internal_1.CdmDataTypeDefinition,
            internal_1.CdmDataTypeReference,
            internal_1.CdmEntityAttributeDefinition,
            internal_1.CdmEntityDefinition,
            internal_1.CdmEntityReference,
            internal_1.CdmFolderDefinition,
            internal_1.CdmImport,
            internal_1.CdmParameterDefinition,
            internal_1.CdmPurposeDefinition,
            internal_1.CdmPurposeReference,
            internal_1.CdmTraitDefinition,
            internal_1.CdmTraitReference,
            internal_1.CdmTypeAttributeDefinition,
            internal_1.ParameterCollection,
            internal_1.ParameterValueSet,
            internal_1.ParameterValue,
            internal_1.ResolvedAttributeSetBuilder,
            internal_1.ResolvedAttributeSet,
            internal_1.ResolvedAttribute,
            internal_1.ResolvedEntityReferenceSet,
            internal_1.ResolvedEntityReferenceSide,
            internal_1.ResolvedEntityReference,
            internal_1.ResolvedEntity,
            internal_1.ResolvedTraitSetBuilder,
            internal_1.ResolvedTraitSet,
            internal_1.refCounted,
            internal_1.resolveContext,
            internal_1.AttributeResolutionDirectiveSet,
            internal_1.traitToPropertyMap
        ];
    }
    measure(code, funcName) {
        if (this.on) {
            const loc = funcName;
            this.callStack.push(loc);
            let cnt = this.calls.get(loc);
            if (!cnt) {
                cnt = { calls: 0, timeTotal: 0, timeExl: 0 };
                this.calls.set(loc, cnt);
            }
            cnt.calls++;
            const n = 0;
            //const n: number = performance.now();
            const retVal = code();
            let elaspsed = 1;
            //let elaspsed: number = performance.now() - n;
            if (elaspsed < 0) {
                elaspsed = 0.00001;
            }
            cnt.timeTotal += elaspsed;
            this.callStack.pop();
            if (this.callStack.length) {
                const locFrom = this.callStack[this.callStack.length - 1];
                cnt = this.calls.get(locFrom);
                cnt.timeExl += elaspsed;
            }
            return retVal;
        }
        else {
            return code();
        }
    }
    report() {
        const results = [];
        this.calls.forEach((v, k) => {
            results.push(`${v.calls},${v.timeTotal},${v.timeTotal - v.timeExl},${k}`);
        });
        return results;
    }
    getCallData() {
        return this.calls;
    }
    clearData() {
        this.calls = new Map();
    }
    addProfilingCode(classes) {
        const ignoreStaticMembers = [];
        const ignoreMembers = ['constructor'];
        // Capture the profiler variables since the reference to 'this' changes inside the lambda function
        const profiler = this;
        let replaceFunction = (currClass, funcName, displayName) => {
            const descriptor = Object.getOwnPropertyDescriptor(currClass, funcName);
            if (descriptor.get || descriptor.set) {
                return;
            }
            const oldFn = currClass[funcName];
            if (typeof oldFn === 'function') {
                // We need to capture the 'this' variable that is used to make the function call
                currClass[funcName] = function () {
                    return profiler.measure(() => oldFn.apply(this, arguments), `${displayName}`);
                };
            }
        };
        classes.forEach((currClass) => {
            Object.getOwnPropertyNames(currClass.prototype)
                .filter((funcName) => ignoreMembers.indexOf(funcName) === -1)
                .forEach((funcName) => replaceFunction(currClass.prototype, funcName, `${currClass.name}:${funcName}`));
            Object.getOwnPropertyNames(currClass)
                .filter((funcName) => ignoreStaticMembers.indexOf(funcName) === -1)
                .forEach((funcName) => replaceFunction(currClass, funcName, `${currClass.name}:${funcName}`));
        });
    }
}
exports.CdmProfiler = CdmProfiler;
const p = new CdmProfiler();
exports.p = p;
//# sourceMappingURL=profile.js.map