"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Debugger = void 0;
const sentio_provider_1 = require("./sentio-provider");
const truffle_debugger = require("@truffle/debugger");
let { data, evm, trace, session, sourcemapping, stacktrace, controller } = truffle_debugger.selectors;
class Debugger {
    constructor() {
        this.sectionPrintouts = new Set(["bui", "glo", "con", "loc"]);
        this.initialized = false;
    }
    static get Instance() {
        return this._instance || (this._instance = new this());
    }
    initialize(init_arguments) {
        return __awaiter(this, void 0, void 0, function* () {
            const provider = new sentio_provider_1.SentioProvider(init_arguments.providerURL, { keepAlive: false });
            yield provider.init(init_arguments.txnHash, init_arguments.chainId);
            this.truffle_debugger = yield truffle_debugger.forTx(init_arguments.txnHash, { provider: provider, compilations: init_arguments.shimmedCompilations, lightMode: true });
            yield this.truffle_debugger.startFullMode();
            this.initialized = true;
        });
    }
    reset() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.truffle_debugger.view(session.status.loaded)) {
                yield this.truffle_debugger.reset();
            }
        });
    }
    stepOver() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.stepOver();
        });
    }
    stepInto() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.stepInto();
        });
    }
    stepOut() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.stepOut();
        });
    }
    stepNext() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.stepNext();
        });
    }
    advance() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.advance();
        });
    }
    continueUntilBreakpoint() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.continueUntilBreakpoint();
        });
    }
    addBreakpoint(breakpoint) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.addBreakpoint(this.determinBreakPoint(breakpoint));
        });
    }
    removeBreakpoint(breakpoint) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.removeBreakpoint(this.determinBreakPoint(breakpoint));
        });
    }
    removeAllBreakpoints() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.truffle_debugger.removeAllBreakpoints();
        });
    }
    variables() {
        return __awaiter(this, void 0, void 0, function* () {
            const values = yield this.truffle_debugger.variables({ indicateUnknown: true });
            const sections = this.truffle_debugger.view(data.current.identifiers.sections);
            const sectionVars = {
                builtin: [],
                global: [],
                contract: [],
                local: []
            };
            for (const [section, variables] of Object.entries(sections)) {
                // only check the first 3 characters of each name given in the input sectionPrintouts
                // since each section name defined in the constructor contains 3 characters
                const includeThisSection = this.sectionPrintouts.has(section.slice(0, 3));
                //@ts-ignore
                if (includeThisSection && variables.length > 0) {
                    //@ts-ignore
                    for (const variable of variables) {
                        const value = values[variable];
                        //@ts-ignore
                        sectionVars[section].push({
                            name: variable,
                            raw: value
                        });
                    }
                }
            }
            return sectionVars;
        });
    }
    stackTrace() {
        let final = false;
        if (this.truffle_debugger.view(session.status.loaded)) {
            //print final report if finished & failed, intermediate if not
            if (this.truffle_debugger.view(trace.finished) &&
                !this.truffle_debugger.view(evm.transaction.status)) {
                final = true; //print final stack trace
            }
            else {
                final = false; //intermediate call stack
            }
        }
        let report = final
            ? this.truffle_debugger.view(stacktrace.current.finalReport)
            : this.truffle_debugger.view(stacktrace.current.report);
        return report;
    }
    currentLocation() {
        if (this.truffle_debugger.view(trace.finishedOrUnloaded)) {
            return undefined;
        }
        const currentLocation = this.truffle_debugger.view(controller.current.location);
        const currentLines = currentLocation.sourceRange
            ? currentLocation.sourceRange.lines
            : null;
        const currentLength = currentLocation.sourceRange
            ? currentLocation.sourceRange.length
            : null;
        const currentSourceId = currentLocation.source
            ? currentLocation.source.id
            : null;
        //search sources for given string
        let sources = Object.values(this.truffle_debugger.view(sourcemapping.views.sources));
        //we will indeed need the sources here, not just IDs
        let matchingSources = sources.filter(source => 
        // @ts-ignore
        source.id === currentSourceId);
        return {
            // @ts-ignore
            compilationId: matchingSources[0].compilationId,
            lines: currentLines,
            length: currentLength,
            // @ts-ignore
            sourcePath: matchingSources[0].sourcePath,
        };
    }
    terminate() {
        return __awaiter(this, void 0, void 0, function* () {
            this.truffle_debugger = null;
            this.initialized = false;
        });
    }
    determinBreakPoint(breakPoint) {
        //search sources for given string
        let sources = Object.values(this.truffle_debugger.view(sourcemapping.views.sources));
        //we will indeed need the sources here, not just IDs
        let matchingSources = sources.filter(source => 
        // @ts-ignore
        source.sourcePath === breakPoint.sourcePath && source.compilationId === breakPoint.compilationId);
        return {
            // @ts-ignore
            sourceId: matchingSources[0].id,
            line: breakPoint.line
        };
    }
}
exports.Debugger = Debugger;
//# sourceMappingURL=debugger.js.map