///<reference path="..\typings\globals\node\index.d.ts" />
"use strict";
var http = require("http");
var https = require("https");
var Logging = require("../Library/Logging");
var Util = require("../Library/Util");
var RequestResponseHeaders = require("../Library/RequestResponseHeaders");
var ServerRequestParser = require("./ServerRequestParser");
var AutoCollectServerRequests = (function () {
    function AutoCollectServerRequests(client) {
        if (!!AutoCollectServerRequests.INSTANCE) {
            throw new Error("Server request tracking should be configured from the applicationInsights object");
        }
        AutoCollectServerRequests.INSTANCE = this;
        this._client = client;
    }
    AutoCollectServerRequests.prototype.enable = function (isEnabled) {
        this._isEnabled = isEnabled;
        if (this._isEnabled && !this._isInitialized) {
            this._initialize();
        }
    };
    AutoCollectServerRequests.prototype.isInitialized = function () {
        return this._isInitialized;
    };
    AutoCollectServerRequests.prototype._initialize = function () {
        var _this = this;
        this._isInitialized = true;
        var originalHttpServer = http.createServer;
        http.createServer = function (onRequest) {
            // todo: get a pointer to the server so the IP address can be read from server.address
            return originalHttpServer(function (request, response) {
                if (_this._isEnabled) {
                    AutoCollectServerRequests.trackRequest(_this._client, request, response);
                }
                if (typeof onRequest === "function") {
                    onRequest(request, response);
                }
            });
        };
        var originalHttpsServer = https.createServer;
        https.createServer = function (options, onRequest) {
            return originalHttpsServer(options, function (request, response) {
                if (_this._isEnabled) {
                    AutoCollectServerRequests.trackRequest(_this._client, request, response);
                }
                if (typeof onRequest === "function") {
                    onRequest(request, response);
                }
            });
        };
    };
    /**
     * Tracks a request synchronously (doesn't wait for response 'finish' event)
     */
    AutoCollectServerRequests.trackRequestSync = function (client, request, response, ellapsedMilliseconds, properties, error) {
        if (!request || !response || !client) {
            Logging.info("AutoCollectServerRequests.trackRequestSync was called with invalid parameters: ", !request, !response, !client);
            return;
        }
        AutoCollectServerRequests.addResponseIKeyHeader(client, response);
        // store data about the request
        var requestParser = new ServerRequestParser(request);
        AutoCollectServerRequests.endRequest(client, requestParser, request, response, ellapsedMilliseconds, properties, error);
    };
    /**
     * Tracks a request by listening to the response 'finish' event
     */
    AutoCollectServerRequests.trackRequest = function (client, request, response, properties) {
        if (!request || !response || !client) {
            Logging.info("AutoCollectServerRequests.trackRequest was called with invalid parameters: ", !request, !response, !client);
            return;
        }
        // store data about the request
        var requestParser = new ServerRequestParser(request);
        if (Util.canIncludeCorrelationHeader(client, requestParser.getUrl())) {
            AutoCollectServerRequests.addResponseIKeyHeader(client, response);
        }
        // response listeners
        if (response.once) {
            response.once("finish", function () {
                AutoCollectServerRequests.endRequest(client, requestParser, request, response, null, properties, null);
            });
        }
        // track a failed request if an error is emitted
        if (request.on) {
            request.on("error", function (error) {
                AutoCollectServerRequests.endRequest(client, requestParser, request, response, null, properties, error);
            });
        }
    };
    /**
     * Add the target ikey hash to the response headers, if not already provided.
     */
    AutoCollectServerRequests.addResponseIKeyHeader = function (client, response) {
        if (client.config && client.config.instrumentationKeyHash &&
            response.getHeader && response.setHeader &&
            !response.getHeader(RequestResponseHeaders.targetInstrumentationKeyHeader) &&
            !response.headersSent) {
            response.setHeader(RequestResponseHeaders.targetInstrumentationKeyHeader, client.config.instrumentationKeyHash);
        }
    };
    AutoCollectServerRequests.endRequest = function (client, requestParser, request, response, ellapsedMilliseconds, properties, error) {
        if (error) {
            requestParser.onError(error, properties, ellapsedMilliseconds);
        }
        else {
            requestParser.onResponse(response, properties, ellapsedMilliseconds);
        }
        var data = requestParser.getRequestData();
        var tags = requestParser.getRequestTags(client.context.tags);
        var context = { "http.ServerRequest": request, "http.ServerResponse": response };
        client.track(data, tags, context);
    };
    AutoCollectServerRequests.prototype.dispose = function () {
        AutoCollectServerRequests.INSTANCE = null;
        this._isInitialized = false;
    };
    return AutoCollectServerRequests;
}());
module.exports = AutoCollectServerRequests;
