var BinaryData = require("./../data/BinaryData.js").BinaryData;
var Class = require('../class/Class.js').Class;
var Response = require('../net/Response.js').Response;
var Types = require("../common/Types.js");

var Stats = function() {
    this.initialize = function() {
        this.minSize = Number.MAX_VALUE;
        this.maxSize = Number.MIN_VALUE;
        this.avgSize = 0;
        this.minTime = Number.MAX_VALUE;
        this.maxTime = Number.MIN_VALUE;
        this.avgTime = 0;
        this.count = 0;
        this.size = 0;
        this.time = 0;
        this.avgNormalized = 0;
        this.startTime = this.endTime = Date.now();
    };
    this.computeStats = function(size, time) {
        if (size < this.minSize) this.minSize = size;
        if (size > this.maxSize) this.maxSize = size;
        if (time < this.minTime) this.minTime = time;
        if (time > this.maxTime) this.maxTime = time;
        
        if (this.avgSize && this.avgTime && this.avgNormalized) {
            this.avgSize = this.avgSize ? ((this.avgSize + size) / 2) : size;
            this.avgTime = this.avgTime ? ((this.avgTime + time) / 2) : time;
            this.avgNormalized = (this.avgNormalized + (size/time)) / 2;
        }
        else {
            this.avgSize = size;
            this.avgTime = time;
            this.avgNormalized = (size/time);    
        }
        this.count++;
        this.size += size;
        this.time += time;
        
        this.endTime = Date.now();
    };
    this.add = function(stats) {
        if (stats.minSize < this.minSize) this.minSize = stats.minSize;
        if (stats.maxSize > this.maxSize) this.maxSize = stats.maxSize;
        if (stats.minTime < this.minTime) this.minTime = stats.minTime;
        if (stats.maxTime > this.maxTime) this.maxTime = stats.maxTime;
        
        if (this.avgSize && this.avgTime && this.avgNormalized) {
            this.avgSize = (this.avgSize + stats.avgSize) / 2;
            this.avgTime = (this.avgTime + stats.avgTime) / 2;
            this.avgNormalized = (this.avgNormalized + stats.avgNormalized) / 2 ;    
        }
        else {
            this.avgSize = stats.avgSize;
            this.avgTime = stats.avgTime;
            this.avgNormalized = stats.avgNormalized;    
        }
        this.count += stats.count;
        this.size += stats.size;
        this.time += stats.time;
        
        if (this.startTime > stats.startTime) this.startTime = stats.startTime;
        if (this.endTime < stats.endTime) this.endTime = stats.endTime;
    };
    this.getCalculatedStats = function() {
        var testTimeMs = this.endTime - this.startTime,
            testTimeS = testTimeMs / 1000,
            avgRequestPerSecond = this.count / testTimeS,
            avgThroughputBytesPerSecond = this.size / testTimeS;
        return {
            'time'    : testTimeMs,
            'minSize' : this.minSize,
            'maxSize' : this.maxSize,
            'avgSize' : this.avgSize,
            'minTime' : this.minTime,
            'maxTime' : this.maxTime,
            'avgTime' : this.avgTime,
            'requestCount' : this.count,
            'totalSize' : this.size,
            'totalTime' : this.time,
            'avgNormalized' : this.avgNormalized,
            'avgRequestPerSecond' : avgRequestPerSecond,
            'avgThroughputBytesPerSecond' : avgThroughputBytesPerSecond
        }
    };
}
Stats = new Class( new Stats() );

var ServerStats = function() {
    /*
    this.samples = null;
    this.samplesTimes;
    
    this._httpServer = null;
    
    this.totalStats = null;
    
    this.connectionActive = 0;
    this.connectionTotal = 0;    
    this.totalTime = 0,
    this.totalSize = 0;
    */
    
    this.initialize = function(httpServer) {
        
        this.connectionActive = 0;
        this.connectionTotal = 0;    
        this.totalTime = 0,
        this.totalSize = 0;

        this.totalStats = new Stats();
        
        this.sampleTime = 60000;
        this.samplesMaxCount = 15;
        
        this.samples = new Array();
        
        this.samples.push(new Stats);
        
        var that = this;
        //this.resetStats();
        this._httpServer = httpServer;
        this._httpServer.on('connection', function(sock) {
            that.connectionActive++;
            that.connectionTotal++;
            sock.on('close', function() {
                that.connectionActive--;
            });
        });
    };
    
    this.computeStats = function(request, response) {
        var stats = this.samples[0];
        
        var that = this;
                
        response.addEventListener(Response.Event.SEND, function(e) {
            //retrieve data
            var body = response.getBody(),
                size = 0,
                time = request.getProcessingTime();
            
            if (Types.isInstanceOf(body, BinaryData)) {
                size = body.length();
            }
            
            //compute values
            stats.computeStats(size, time);
            
            that.totalStats.computeStats(size, time);
            
            that.totalTime += time;
            that.totalSize += size;
            
            var now = Date.now();
            if (now - stats.startTime > that.sampleTime) {
                var newStats = new Stats();
                that.samples.unshift(newStats);
                if (that.samples.length > that.samplesMaxCount) {
                    that.samples.pop();
                }
            }
        });
    };
    
    this.getStats = function() {
        var //now = Date.now(),
            testTimeMs = this.totalStats.endTime - this.totalStats.startTime,
            testTimeS = testTimeMs / 1000,
            avgConnectionPerSecond = this.connectionTotal / testTimeS,
            period1 = this.samples[0],
            period5 = new Stats(),
            period10 = new Stats(),
            period15 = new Stats();
        
        //period1.endTime = now;
        //this.totalStats.endTime = now;
        
        for (var i = 0; i < this.samples.length; i++) {
            if (i < 5) {
                period5.add(this.samples[i]);
            }
            if (i < 10) {
                period10.add(this.samples[i]);
            }
            if (i < 15) {
                period15.add(this.samples[i]);
            }
        }
        var total = this.totalStats.getCalculatedStats();
        total.avgConnectionPerSecond = avgConnectionPerSecond;
        total.connectionActive = this.connectionActive;
        total.connectionTotal = this.connectionTotal;
        
        return {
            'total' : total,
            '1min'  : period1.getCalculatedStats(),
            '5min'  : period5.getCalculatedStats(),
            '10min': period10.getCalculatedStats(),
            '15min': period15.getCalculatedStats()
        };
    };
    
    /*this.resetStats = function(){
        this.minSize = Number.MAX_VALUE,
        this.maxSize = Number.MIN_VALUE,
        this.avgSize = 0,
        this.minTime = Number.MAX_VALUE,
        this.maxTime = Number.MIN_VALUE,
        this.avgTime = 0,
        this.count = 0,
        this.avgNormalized = 0,
        this.totalTime = 0,
        this.totalSize = 0;

        this._statsStartTime = -1;

        this.connectionActive = 0;
        this.connectionTotal = 0;
    };*/
};

ServerStats = new Class( new ServerStats() );
ServerStats.Stats = Stats;
exports.ServerStats = ServerStats;
