var Request = require("./Request.js").Request;
var Response = require("./Response.js").Response;
var BinaryData = require("./../data/BinaryData.js").BinaryData;
var RequestProcessor = require("./RequestProcessor.js").RequestProcessor;

var http = require('http');

/**
 * @class Server Main http server class. Wraps native node.js http object. Creates Request processor instance and dispatch processing. 
 * @param {Class} RequestProcessorClass Subclass of RequestProcessor family.
 */
var Server = function (RequestProcessorClass) {
    this.RequestProcessorClass = RequestProcessorClass;
    this._requestCounter = 0;
    var that = this;
    this._server = http.createServer(function (request, response) {
        that._onRequestHandler(request, response);
    });
};

    
        
Server.prototype.listen = function (port, host) {
    this._server._backlog = 4096;
    this._server.listen(port, host);
};

Server.prototype.listenFD = function (fd, protocol) {
    this._server._backlog = 4096;
    this._server.listenFD(fd, protocol);  
};

Server.prototype.close = function () {
    this._server.close();
};

/**
 * Returns native http server instance.
 * @public
 * @returns http.Server
 */
Server.prototype.getClusterNode = function () {
    return this._server;
};
/**
 * @private
 */

Server.prototype._onRequestHandler = function (httpRequest, httpResponse) {
    //czas rozpoczecia przetwarzania requestu
    httpRequest.__timeStart = Date.now();
    //console.log('\n-- request started');

    var that = this;

    var dataLength = 0, buffers = [];
    
    // gathering post data
    httpRequest.on('data', function (data) {
        buffers.push(data);
        dataLength += data.length;
    });
    
    // i'm the master of every buffer @ post data'
    httpRequest.on('end', function () {
        
        var joinedBuffer = new Buffer(dataLength), bufferPosition = 0;
        for(var i = 0, l = buffers.length; i < l; i++){
            buffers[i].copy(joinedBuffer, bufferPosition);
            bufferPosition += buffers[i].length;
        }
        // 2325 - 2336
        
        httpRequest.data = new BinaryData(
            joinedBuffer,
            BinaryData.Encoding.BINARY
        );
        // 2109 - 2283 
        
        var request = new Request(httpRequest);    // 824-831 - return w konstruktorze
        
        // 1381 - 1428
        var response = new Response(httpResponse);
        // 1246 - 1362
        //httpResponse.end('404 not found'); return;
        
        var requestProcessor = that.createRequestProcessor();
        // 1243 - 1275
        
        // 900 - 932 
        requestProcessor.process(request, response); 
        // 897 - 936
    });
    
};

Server.prototype.getServer = function () {
    return this;
};

Server.prototype.createRequestProcessor = function () {
    var requestProcessor = new this.RequestProcessorClass(this.getServer());
    if(!(requestProcessor instanceof  RequestProcessor)){
        throw Server.Exception.WRONG_PROCESSOR_CLASS;
    }
    return requestProcessor;
};

Server.prototype.getStats = function () {
    //Wsteczna kompatybilnosc do wywalenia po aktualizacji node-server
    return {};
};

/**
 * Namespace for exceptions messages.
 * @static
 * @namespace
 */
Server.Exception = {};
/**
 * @static
 * @public
 */
Server.Exception.WRONG_PROCESSOR_CLASS = "Request processor class must be inheriting RequestProcessor";
//

exports.Server = Server;
