/*---------------------------------------------------------------------------------------------
 *  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 ee = require('events');
var messages_1 = require('./messages');
var ProtocolServer = (function (_super) {
    __extends(ProtocolServer, _super);
    function ProtocolServer() {
        _super.call(this);
        this._pendingRequests = new Map();
    }
    ProtocolServer.prototype.start = function (inStream, outStream) {
        var _this = this;
        this._sequence = 1;
        this._writableStream = outStream;
        this._rawData = new Buffer(0);
        inStream.on('data', function (data) { return _this._handleData(data); });
        inStream.on('close', function () {
            _this._emitEvent(new messages_1.Event('close'));
        });
        inStream.on('error', function (error) {
            _this._emitEvent(new messages_1.Event('error'));
        });
        outStream.on('error', function (error) {
            _this._emitEvent(new messages_1.Event('error'));
        });
        inStream.resume();
    };
    ProtocolServer.prototype.stop = function () {
        if (this._writableStream) {
            this._writableStream.end();
        }
    };
    ProtocolServer.prototype.sendEvent = function (event) {
        this._send('event', event);
    };
    ProtocolServer.prototype.sendResponse = function (response) {
        if (response.seq > 0) {
            console.error("attempt to send more than one response for command " + response.command);
        }
        else {
            this._send('response', response);
        }
    };
    ProtocolServer.prototype.sendRequest = function (command, args, timeout, cb) {
        var _this = this;
        var request = {
            command: command
        };
        if (args && Object.keys(args).length > 0) {
            request.arguments = args;
        }
        if (!this._writableStream) {
            this._emitEvent(new messages_1.Event('error'));
            return;
        }
        this._send('request', request);
        if (cb) {
            this._pendingRequests.set(request.seq, cb);
            var timer_1 = setTimeout(function () {
                clearTimeout(timer_1);
                var clb = _this._pendingRequests.get(request.seq);
                if (clb) {
                    _this._pendingRequests.delete(request.seq);
                    clb(new messages_1.Response(request, 'timeout'));
                }
            }, timeout);
        }
    };
    // ---- protected ----------------------------------------------------------
    ProtocolServer.prototype.dispatchRequest = function (request) {
    };
    // ---- private ------------------------------------------------------------
    ProtocolServer.prototype._emitEvent = function (event) {
        this.emit(event.event, event);
    };
    ProtocolServer.prototype._send = function (typ, message) {
        message.type = typ;
        message.seq = this._sequence++;
        if (this._writableStream) {
            var json = JSON.stringify(message);
            this._writableStream.write("Content-Length: " + Buffer.byteLength(json, 'utf8') + "\r\n\r\n" + json, 'utf8');
        }
    };
    ProtocolServer.prototype._handleData = function (data) {
        this._rawData = Buffer.concat([this._rawData, data]);
        while (true) {
            if (this._contentLength >= 0) {
                if (this._rawData.length >= this._contentLength) {
                    var message = this._rawData.toString('utf8', 0, this._contentLength);
                    this._rawData = this._rawData.slice(this._contentLength);
                    this._contentLength = -1;
                    if (message.length > 0) {
                        try {
                            var msg = JSON.parse(message);
                            if (msg.type === 'request') {
                                this.dispatchRequest(msg);
                            }
                            else if (msg.type === 'response') {
                                var response = msg;
                                var clb = this._pendingRequests.get(response.request_seq);
                                if (clb) {
                                    this._pendingRequests.delete(response.request_seq);
                                    clb(response);
                                }
                            }
                        }
                        catch (e) {
                            this._emitEvent(new messages_1.Event('error'));
                        }
                    }
                    continue; // there may be more complete messages to process
                }
            }
            else {
                var idx = this._rawData.indexOf(ProtocolServer.TWO_CRLF);
                if (idx !== -1) {
                    var header = this._rawData.toString('utf8', 0, idx);
                    var lines = header.split('\r\n');
                    for (var i = 0; i < lines.length; i++) {
                        var pair = lines[i].split(/: +/);
                        if (pair[0] == 'Content-Length') {
                            this._contentLength = +pair[1];
                        }
                    }
                    this._rawData = this._rawData.slice(idx + ProtocolServer.TWO_CRLF.length);
                    continue;
                }
            }
            break;
        }
    };
    ProtocolServer.TWO_CRLF = '\r\n\r\n';
    return ProtocolServer;
}(ee.EventEmitter));
exports.ProtocolServer = ProtocolServer;
//# sourceMappingURL=data:application/json;base64,[encoded data, 13852 characters]