///<reference path="..\Declarations\node\node.d.ts" />
var url = require("url");
var ContractsModule = require("../Library/Contracts");
var Util = require("../Library/Util");
/**
 * Helper class to read data from the requst/response objects and convert them into the telemetry contract
 */
var RequestDataHelper = (function () {
    function RequestDataHelper(request) {
        if (request) {
            this.method = request.method;
            this.url = request.url;
            this.startTime = +new Date();
            this.rawHeaders = request.headers || request.rawHeaders;
            this.socketRemoteAddress = request.socket && request.socket.remoteAddress;
            this.userAgent = request.headers && request.headers["user-agent"];
            if (request.connection) {
                this.connectionRemoteAddress = request.connection.remoteAddress;
                this.legacySocketRemoteAddress = request.connection["socket"] && request.connection["socket"].remoteAddress;
            }
        }
    }
    RequestDataHelper.prototype.onResponse = function (response, errorProperties) {
        this.endTime = +new Date;
        this.statusCode = response.statusCode;
        this.errorProperties = errorProperties;
    };
    RequestDataHelper.prototype.getRequestData = function () {
        var duration = this.endTime - this.startTime;
        var requestData = new ContractsModule.Contracts.RequestData();
        requestData.httpMethod = this.method;
        requestData.id = Util.newGuid();
        requestData.name = this.method + " " + url.parse(this.url).pathname;
        requestData.startTime = (new Date(this.startTime)).toISOString();
        requestData.url = this.url;
        requestData.duration = Util.msToTimeSpan(duration);
        requestData.responseCode = this.statusCode.toString();
        requestData.success = this._isSuccess(this.statusCode);
        requestData.properties = this.errorProperties;
        var data = new ContractsModule.Contracts.Data();
        data.baseType = "Microsoft.ApplicationInsights.RequestData";
        data.baseData = requestData;
        return data;
    };
    RequestDataHelper.prototype.getRequestTags = function (tags) {
        // create a copy of the context for requests since client info will be used here
        var newTags = {};
        for (var key in tags) {
            newTags[key] = tags[key];
        }
        newTags[RequestDataHelper.keys.locationIp] = this._getIp();
        newTags[RequestDataHelper.keys.sessionId] = this._getSessionId();
        newTags[RequestDataHelper.keys.userAgent] = this.userAgent;
        return newTags;
    };
    RequestDataHelper.prototype._isSuccess = function (statusCode) {
        return (statusCode < 400) && !this.errorProperties; // todo: this could probably be improved
    };
    RequestDataHelper.prototype._getIp = function () {
        // regex to match ipv4 without port
        // Note: including the port would cause the payload to be rejected by the data collector
        var ipMatch = /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/;
        var check = function (str) {
            var results = ipMatch.exec(str);
            if (results) {
                return results[0];
            }
        };
        var ip = check(this.rawHeaders["x-forwarded-for"])
            || check(this.rawHeaders["x-client-ip"])
            || check(this.rawHeaders["x-real-ip"])
            || check(this.connectionRemoteAddress)
            || check(this.socketRemoteAddress)
            || check(this.legacySocketRemoteAddress);
        // node v12 returns this if the address is "localhost"
        if (!ip
            && this.connectionRemoteAddress
            && this.connectionRemoteAddress.substr
            && this.connectionRemoteAddress.substr(0, 2) === "::") {
            ip = "127.0.0.1";
        }
        return ip;
    };
    RequestDataHelper.prototype._getSessionId = function () {
        var name = "ai_session";
        var cookie = (this.rawHeaders && this.rawHeaders["cookie"] &&
            typeof this.rawHeaders["cookie"] === 'string' && this.rawHeaders["cookie"]) || "";
        var value = RequestDataHelper.parseSessionId(Util.getCookie(name, cookie));
        return value;
    };
    RequestDataHelper.parseSessionId = function (cookieValue) {
        return cookieValue.substr(0, cookieValue.indexOf('|'));
    };
    RequestDataHelper.keys = new ContractsModule.Contracts.ContextTagKeys();
    return RequestDataHelper;
})();
module.exports = RequestDataHelper;
