/**
 * Copyright 2016 the WHATAP project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */

var Long        = require('long'),
    ValueEnum   = require('./valueenum'),
    Value       = require('./value'),
    NumberValue  = require('./number-value'),
    BooleanValue = require('./boolean-value')

function MetricValue() {
    NumberValue.call(this);

    this.count = 0;
    this.sum = 0;
    this.min = 0;
    this.max = 0;
    this.last = 0;
    this.compareTo = function(object) {
        if(object instanceof MetricValue) {
            if(this.value != object.value) {
                return this.value > object.value ? 1 : -1;
            } else {
                return 0;
            }
        }
        return 1;
    };
    this.equals = function(object) {
        if(object instanceof MetricValue) {
            return this.value === object.value;
        }
        return false;
    };
}

MetricValue.prototype = new Value();
MetricValue.prototype.constructor = MetricValue;

MetricValue.prototype.getValueType = function() {
    return ValueEnum.METRIC;
};
MetricValue.prototype.write = function(dout) {
    if (this.count == 0) {
        dout.writeByte(0);
    } else {
        dout.writeByte(1);
        dout.writeDecimal(count);
        dout.writeDouble(sum);
        dout.writeFloat(min);
        dout.writeFloat(max);
        dout.writeFloat(last);
    }
};
MetricValue.prototype.read = function(din) {
    let mode = din.readByte();

    switch (mode) {
        case 0:
            return this;
        case 1:
            this.count = din.readDecimal();
            this.sum = din.readDouble();
            this.min = din.readFloat();
            this.max = din.readFloat();
            this.last = din.readFloat();
    }
    return this;
};

MetricValue.prototype.addcount = () => { this.count++ }

MetricValue.prototype.add = ( value ) => {
    if (value == null) return this;

    if( value instanceof Number) {
        v = value.doubleValue()
    } else if(value instanceof MetricValue) {
        return this.merge(value);
    } else if(value instanceof NumberValue) {
        return this.add(value);
    } else {
        v = value
    }

    if (this.count == 0) {
        this.count = 1;
        this.sum = v;
        this.max = v;
        this.min = v;
    } else {
        this.count++;
        this.sum += v;
        this.max = Math.max(this.max, v);
        this.min = Math.min(this.min, v);
    }
    this.last = v;
    return this;
}

MetricValue.prototype.merge = ( value ) => {
    if (value === null) return this;

    if (this.count == 0) {
        this.count = value.count;
        this.sum = value.sum;
        this.max = value.max;
        this.min = value.min;
    } else {
        this.count += value.count;
        this.sum += value.sum;
        this.max = Math.max(this.max, value.max);
        this.min = Math.min(this.min, value.min);
    }
    this.last = value.last;
    return this;
}

MetricValue.prototype.sum = () => { return this.sum; }

MetricValue.prototype.min = () => { return this.count == 1 ? this.sum : this.min; }

MetricValue.prototype.max = () => { return this.count == 1 ? this.sum : this.max; }

MetricValue.prototype.last = () => { return this.count == 1 ? this.sum : this.last; }

MetricValue.prototype.avg = () => { return (this.count == 0 ? 0 : this.sum / this.count); }

MetricValue.prototype.getCount = () => { return this.count; }

MetricValue.prototype.copy = () => {
    var o = new MetricValue();
    o.count = this.count;
    o.max = this.max;
    o.min = this.min;
    o.sum = this.sum;
    o.last = this.last;
    return o;
}

MetricValue.prototype.doubleValue = function() {
    return this.avg();
};
MetricValue.prototype.floatValue = function() {
    return parseFloat(this.avg());
};
MetricValue.prototype.intValue = function() {
    return parseInt(this.avg());
};
MetricValue.prototype.longValue = function() {
    return Long.fromNumber(this.avg());
};

MetricValue.prototype.isEmpty = () => { return this.count==0 }

module.exports = MetricValue;