/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var protocol_1 = require('./protocol');
var messages_1 = require('./messages');
var Net = require('net');
var Url = require('url');
var Source = (function () {
    function Source(name, path, id, origin, data) {
        if (id === void 0) { id = 0; }
        this.name = name;
        this.path = path;
        this.sourceReference = id;
        if (origin) {
            this.origin = origin;
        }
        if (data) {
            this.adapterData = data;
        }
    }
    return Source;
}());
exports.Source = Source;
var Scope = (function () {
    function Scope(name, reference, expensive) {
        if (expensive === void 0) { expensive = false; }
        this.name = name;
        this.variablesReference = reference;
        this.expensive = expensive;
    }
    return Scope;
}());
exports.Scope = Scope;
var StackFrame = (function () {
    function StackFrame(i, nm, src, ln, col) {
        if (ln === void 0) { ln = 0; }
        if (col === void 0) { col = 0; }
        this.id = i;
        this.source = src;
        this.line = ln;
        this.column = col;
        this.name = nm;
    }
    return StackFrame;
}());
exports.StackFrame = StackFrame;
var Thread = (function () {
    function Thread(id, name) {
        this.id = id;
        if (name) {
            this.name = name;
        }
        else {
            this.name = 'Thread #' + id;
        }
    }
    return Thread;
}());
exports.Thread = Thread;
var Variable = (function () {
    function Variable(name, value, ref, indexedVariables, namedVariables) {
        if (ref === void 0) { ref = 0; }
        this.name = name;
        this.value = value;
        this.variablesReference = ref;
        if (typeof namedVariables === 'number') {
            this.namedVariables = namedVariables;
        }
        if (typeof indexedVariables === 'number') {
            this.indexedVariables = indexedVariables;
        }
    }
    return Variable;
}());
exports.Variable = Variable;
var Breakpoint = (function () {
    function Breakpoint(verified, line, column, source) {
        this.verified = verified;
        var e = this;
        if (typeof line === 'number') {
            e.line = line;
        }
        if (typeof column === 'number') {
            e.column = column;
        }
        if (source) {
            e.source = source;
        }
    }
    return Breakpoint;
}());
exports.Breakpoint = Breakpoint;
var Module = (function () {
    function Module(id, name) {
        this.id = id;
        this.name = name;
    }
    return Module;
}());
exports.Module = Module;
var CompletionItem = (function () {
    function CompletionItem(label, start, length) {
        if (length === void 0) { length = 0; }
        this.label = label;
        this.start = start;
        this.length = length;
    }
    return CompletionItem;
}());
exports.CompletionItem = CompletionItem;
var StoppedEvent = (function (_super) {
    __extends(StoppedEvent, _super);
    function StoppedEvent(reason, threadId, exception_text) {
        if (exception_text === void 0) { exception_text = null; }
        _super.call(this, 'stopped');
        this.body = {
            reason: reason,
            threadId: threadId
        };
        if (exception_text) {
            var e = this;
            e.body.text = exception_text;
        }
    }
    return StoppedEvent;
}(messages_1.Event));
exports.StoppedEvent = StoppedEvent;
var ContinuedEvent = (function (_super) {
    __extends(ContinuedEvent, _super);
    function ContinuedEvent(threadId, allThreadsContinued) {
        _super.call(this, 'continued');
        this.body = {
            threadId: threadId
        };
        if (typeof allThreadsContinued === 'boolean') {
            this.body.allThreadsContinued = allThreadsContinued;
        }
    }
    return ContinuedEvent;
}(messages_1.Event));
exports.ContinuedEvent = ContinuedEvent;
var InitializedEvent = (function (_super) {
    __extends(InitializedEvent, _super);
    function InitializedEvent() {
        _super.call(this, 'initialized');
    }
    return InitializedEvent;
}(messages_1.Event));
exports.InitializedEvent = InitializedEvent;
var TerminatedEvent = (function (_super) {
    __extends(TerminatedEvent, _super);
    function TerminatedEvent(restart) {
        _super.call(this, 'terminated');
        if (typeof restart === 'boolean') {
            var e = this;
            e.body = {
                restart: restart
            };
        }
    }
    return TerminatedEvent;
}(messages_1.Event));
exports.TerminatedEvent = TerminatedEvent;
var OutputEvent = (function (_super) {
    __extends(OutputEvent, _super);
    function OutputEvent(output, category, data) {
        if (category === void 0) { category = 'console'; }
        _super.call(this, 'output');
        this.body = {
            category: category,
            output: output
        };
        if (data !== undefined) {
            this.body.data = data;
        }
    }
    return OutputEvent;
}(messages_1.Event));
exports.OutputEvent = OutputEvent;
var ThreadEvent = (function (_super) {
    __extends(ThreadEvent, _super);
    function ThreadEvent(reason, threadId) {
        _super.call(this, 'thread');
        this.body = {
            reason: reason,
            threadId: threadId
        };
    }
    return ThreadEvent;
}(messages_1.Event));
exports.ThreadEvent = ThreadEvent;
var BreakpointEvent = (function (_super) {
    __extends(BreakpointEvent, _super);
    function BreakpointEvent(reason, breakpoint) {
        _super.call(this, 'breakpoint');
        this.body = {
            reason: reason,
            breakpoint: breakpoint
        };
    }
    return BreakpointEvent;
}(messages_1.Event));
exports.BreakpointEvent = BreakpointEvent;
var ModuleEvent = (function (_super) {
    __extends(ModuleEvent, _super);
    function ModuleEvent(reason, module) {
        _super.call(this, 'module');
        this.body = {
            reason: reason,
            module: module
        };
    }
    return ModuleEvent;
}(messages_1.Event));
exports.ModuleEvent = ModuleEvent;
(function (ErrorDestination) {
    ErrorDestination[ErrorDestination["User"] = 1] = "User";
    ErrorDestination[ErrorDestination["Telemetry"] = 2] = "Telemetry";
})(exports.ErrorDestination || (exports.ErrorDestination = {}));
var ErrorDestination = exports.ErrorDestination;
;
var DebugSession = (function (_super) {
    __extends(DebugSession, _super);
    function DebugSession(obsolete_debuggerLinesAndColumnsStartAt1, obsolete_isServer) {
        var _this = this;
        _super.call(this);
        var linesAndColumnsStartAt1 = typeof obsolete_debuggerLinesAndColumnsStartAt1 === 'boolean' ? obsolete_debuggerLinesAndColumnsStartAt1 : false;
        this._debuggerLinesStartAt1 = linesAndColumnsStartAt1;
        this._debuggerColumnsStartAt1 = linesAndColumnsStartAt1;
        this._debuggerPathsAreURIs = false;
        this._clientLinesStartAt1 = true;
        this._clientColumnsStartAt1 = true;
        this._clientPathsAreURIs = false;
        this._isServer = typeof obsolete_isServer === 'boolean' ? obsolete_isServer : false;
        this.on('close', function () {
            _this.shutdown();
        });
        this.on('error', function (error) {
            _this.shutdown();
        });
    }
    DebugSession.prototype.setDebuggerPathFormat = function (format) {
        this._debuggerPathsAreURIs = format !== 'path';
    };
    DebugSession.prototype.setDebuggerLinesStartAt1 = function (enable) {
        this._debuggerLinesStartAt1 = enable;
    };
    DebugSession.prototype.setDebuggerColumnsStartAt1 = function (enable) {
        this._debuggerColumnsStartAt1 = enable;
    };
    DebugSession.prototype.setRunAsServer = function (enable) {
        this._isServer = enable;
    };
    /**
     * A virtual constructor...
     */
    DebugSession.run = function (debugSession) {
        // parse arguments
        var port = 0;
        var args = process.argv.slice(2);
        args.forEach(function (val, index, array) {
            var portMatch = /^--server=(\d{4,5})$/.exec(val);
            if (portMatch) {
                port = parseInt(portMatch[1], 10);
            }
        });
        if (port > 0) {
            // start as a server
            console.error("waiting for debug protocol on port " + port);
            Net.createServer(function (socket) {
                console.error('>> accepted connection from client');
                socket.on('end', function () {
                    console.error('>> client connection closed\n');
                });
                var session = new debugSession(false, true);
                session.setRunAsServer(true);
                session.start(socket, socket);
            }).listen(port);
        }
        else {
            // start a session
            //console.error('waiting for debug protocol on stdin/stdout');
            var session_1 = new debugSession(false);
            process.on('SIGTERM', function () {
                session_1.shutdown();
            });
            session_1.start(process.stdin, process.stdout);
        }
    };
    DebugSession.prototype.shutdown = function () {
        if (this._isServer) {
            console.error('shutdown ignored in server mode');
        }
        else {
            // wait a bit before shutting down
            setTimeout(function () {
                process.exit(0);
            }, 100);
        }
    };
    DebugSession.prototype.sendErrorResponse = function (response, codeOrMessage, format, variables, dest) {
        if (dest === void 0) { dest = ErrorDestination.User; }
        var msg;
        if (typeof codeOrMessage === 'number') {
            msg = {
                id: codeOrMessage,
                format: format
            };
            if (variables) {
                msg.variables = variables;
            }
            if (dest & ErrorDestination.User) {
                msg.showUser = true;
            }
            if (dest & ErrorDestination.Telemetry) {
                msg.sendTelemetry = true;
            }
        }
        else {
            msg = codeOrMessage;
        }
        response.success = false;
        response.message = DebugSession.formatPII(msg.format, true, msg.variables);
        if (!response.body) {
            response.body = {};
        }
        response.body.error = msg;
        this.sendResponse(response);
    };
    DebugSession.prototype.runInTerminalRequest = function (args, timeout, cb) {
        this.sendRequest('runInTerminal', args, timeout, cb);
    };
    DebugSession.prototype.dispatchRequest = function (request) {
        var response = new messages_1.Response(request);
        try {
            if (request.command === 'initialize') {
                var args = request.arguments;
                if (typeof args.linesStartAt1 === 'boolean') {
                    this._clientLinesStartAt1 = args.linesStartAt1;
                }
                if (typeof args.columnsStartAt1 === 'boolean') {
                    this._clientColumnsStartAt1 = args.columnsStartAt1;
                }
                if (args.pathFormat !== 'path') {
                    this.sendErrorResponse(response, 2018, 'debug adapter only supports native paths', null, ErrorDestination.Telemetry);
                }
                else {
                    var initializeResponse = response;
                    initializeResponse.body = {};
                    this.initializeRequest(initializeResponse, args);
                }
            }
            else if (request.command === 'launch') {
                this.launchRequest(response, request.arguments);
            }
            else if (request.command === 'attach') {
                this.attachRequest(response, request.arguments);
            }
            else if (request.command === 'disconnect') {
                this.disconnectRequest(response, request.arguments);
            }
            else if (request.command === 'restart') {
                this.restartRequest(response, request.arguments);
            }
            else if (request.command === 'setBreakpoints') {
                this.setBreakPointsRequest(response, request.arguments);
            }
            else if (request.command === 'setFunctionBreakpoints') {
                this.setFunctionBreakPointsRequest(response, request.arguments);
            }
            else if (request.command === 'setExceptionBreakpoints') {
                this.setExceptionBreakPointsRequest(response, request.arguments);
            }
            else if (request.command === 'configurationDone') {
                this.configurationDoneRequest(response, request.arguments);
            }
            else if (request.command === 'continue') {
                this.continueRequest(response, request.arguments);
            }
            else if (request.command === 'next') {
                this.nextRequest(response, request.arguments);
            }
            else if (request.command === 'stepIn') {
                this.stepInRequest(response, request.arguments);
            }
            else if (request.command === 'stepOut') {
                this.stepOutRequest(response, request.arguments);
            }
            else if (request.command === 'stepBack') {
                this.stepBackRequest(response, request.arguments);
            }
            else if (request.command === 'reverseContinue') {
                this.reverseContinueRequest(response, request.arguments);
            }
            else if (request.command === 'restartFrame') {
                this.restartFrameRequest(response, request.arguments);
            }
            else if (request.command === 'goto') {
                this.gotoRequest(response, request.arguments);
            }
            else if (request.command === 'pause') {
                this.pauseRequest(response, request.arguments);
            }
            else if (request.command === 'stackTrace') {
                this.stackTraceRequest(response, request.arguments);
            }
            else if (request.command === 'scopes') {
                this.scopesRequest(response, request.arguments);
            }
            else if (request.command === 'variables') {
                this.variablesRequest(response, request.arguments);
            }
            else if (request.command === 'setVariable') {
                this.setVariableRequest(response, request.arguments);
            }
            else if (request.command === 'source') {
                this.sourceRequest(response, request.arguments);
            }
            else if (request.command === 'threads') {
                this.threadsRequest(response);
            }
            else if (request.command === 'evaluate') {
                this.evaluateRequest(response, request.arguments);
            }
            else if (request.command === 'stepInTargets') {
                this.stepInTargetsRequest(response, request.arguments);
            }
            else if (request.command === 'gotoTargets') {
                this.gotoTargetsRequest(response, request.arguments);
            }
            else if (request.command === 'completions') {
                this.completionsRequest(response, request.arguments);
            }
            else if (request.command === 'exceptionInfo') {
                this.exceptionInfoRequest(response, request.arguments);
            }
            else {
                this.customRequest(request.command, response, request.arguments);
            }
        }
        catch (e) {
            this.sendErrorResponse(response, 1104, '{_stack}', { _exception: e.message, _stack: e.stack }, ErrorDestination.Telemetry);
        }
    };
    DebugSession.prototype.initializeRequest = function (response, args) {
        // This default debug adapter does not support conditional breakpoints.
        response.body.supportsConditionalBreakpoints = false;
        // This default debug adapter does not support hit conditional breakpoints.
        response.body.supportsHitConditionalBreakpoints = false;
        // This default debug adapter does not support function breakpoints.
        response.body.supportsFunctionBreakpoints = false;
        // This default debug adapter implements the 'configurationDone' request.
        response.body.supportsConfigurationDoneRequest = true;
        // This default debug adapter does not support hovers based on the 'evaluate' request.
        response.body.supportsEvaluateForHovers = false;
        // This default debug adapter does not support the 'stepBack' request.
        response.body.supportsStepBack = false;
        // This default debug adapter does not support the 'setVariable' request.
        response.body.supportsSetVariable = false;
        // This default debug adapter does not support the 'restartFrame' request.
        response.body.supportsRestartFrame = false;
        // This default debug adapter does not support the 'stepInTargetsRequest' request.
        response.body.supportsStepInTargetsRequest = false;
        // This default debug adapter does not support the 'gotoTargetsRequest' request.
        response.body.supportsGotoTargetsRequest = false;
        // This default debug adapter does not support the 'completionsRequest' request.
        response.body.supportsCompletionsRequest = false;
        // This default debug adapter does not support the 'restart' request.
        response.body.supportsRestartRequest = false;
        // This default debug adapter does not support the 'exceptionOptions' attribute on the 'setExceptionBreakpointsRequest'.
        response.body.supportsExceptionOptions = false;
        // This default debug adapter does not support the 'format' attribute on the 'variablesRequest', 'evaluateRequest', and 'stackTraceRequest'.
        response.body.supportsValueFormattingOptions = false;
        // This debug adapter does not support the 'exceptionInfoRequest' request.
        response.body.supportsExceptionInfoRequest = false;
        this.sendResponse(response);
    };
    DebugSession.prototype.disconnectRequest = function (response, args) {
        this.sendResponse(response);
        this.shutdown();
    };
    DebugSession.prototype.launchRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.attachRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.restartRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.setBreakPointsRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.setFunctionBreakPointsRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.setExceptionBreakPointsRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.configurationDoneRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.continueRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.nextRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.stepInRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.stepOutRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.stepBackRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.reverseContinueRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.restartFrameRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.gotoRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.pauseRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.sourceRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.threadsRequest = function (response) {
        this.sendResponse(response);
    };
    DebugSession.prototype.stackTraceRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.scopesRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.variablesRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.setVariableRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.evaluateRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.stepInTargetsRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.gotoTargetsRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.completionsRequest = function (response, args) {
        this.sendResponse(response);
    };
    DebugSession.prototype.exceptionInfoRequest = function (response, args) {
        this.sendResponse(response);
    };
    /**
     * Override this hook to implement custom requests.
     */
    DebugSession.prototype.customRequest = function (command, response, args) {
        this.sendErrorResponse(response, 1014, 'unrecognized request', null, ErrorDestination.Telemetry);
    };
    //---- protected -------------------------------------------------------------------------------------------------
    DebugSession.prototype.convertClientLineToDebugger = function (line) {
        if (this._debuggerLinesStartAt1) {
            return this._clientLinesStartAt1 ? line : line + 1;
        }
        return this._clientLinesStartAt1 ? line - 1 : line;
    };
    DebugSession.prototype.convertDebuggerLineToClient = function (line) {
        if (this._debuggerLinesStartAt1) {
            return this._clientLinesStartAt1 ? line : line - 1;
        }
        return this._clientLinesStartAt1 ? line + 1 : line;
    };
    DebugSession.prototype.convertClientColumnToDebugger = function (column) {
        if (this._debuggerColumnsStartAt1) {
            return this._clientColumnsStartAt1 ? column : column + 1;
        }
        return this._clientColumnsStartAt1 ? column - 1 : column;
    };
    DebugSession.prototype.convertDebuggerColumnToClient = function (column) {
        if (this._debuggerColumnsStartAt1) {
            return this._clientColumnsStartAt1 ? column : column - 1;
        }
        return this._clientColumnsStartAt1 ? column + 1 : column;
    };
    DebugSession.prototype.convertClientPathToDebugger = function (clientPath) {
        if (this._clientPathsAreURIs != this._debuggerPathsAreURIs) {
            if (this._clientPathsAreURIs) {
                return DebugSession.uri2path(clientPath);
            }
            else {
                return DebugSession.path2uri(clientPath);
            }
        }
        return clientPath;
    };
    DebugSession.prototype.convertDebuggerPathToClient = function (debuggerPath) {
        if (this._debuggerPathsAreURIs != this._clientPathsAreURIs) {
            if (this._debuggerPathsAreURIs) {
                return DebugSession.uri2path(debuggerPath);
            }
            else {
                return DebugSession.path2uri(debuggerPath);
            }
        }
        return debuggerPath;
    };
    //---- private -------------------------------------------------------------------------------
    DebugSession.path2uri = function (str) {
        var pathName = str.replace(/\\/g, '/');
        if (pathName[0] !== '/') {
            pathName = '/' + pathName;
        }
        return encodeURI('file://' + pathName);
    };
    DebugSession.uri2path = function (url) {
        return Url.parse(url).pathname;
    };
    /*
    * If argument starts with '_' it is OK to send its value to telemetry.
    */
    DebugSession.formatPII = function (format, excludePII, args) {
        return format.replace(DebugSession._formatPIIRegexp, function (match, paramName) {
            if (excludePII && paramName.length > 0 && paramName[0] !== '_') {
                return match;
            }
            return args[paramName] && args.hasOwnProperty(paramName) ?
                args[paramName] :
                match;
        });
    };
    DebugSession._formatPIIRegexp = /{([^}]+)}/g;
    return DebugSession;
}(protocol_1.ProtocolServer));
exports.DebugSession = DebugSession;
//# sourceMappingURL=data:application/json;base64,[encoded data, 61788 characters]