/**
 * 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 PackEnum = require('./packenum'),
    Pack = require('./pack'),
    Long = require('long'),
    ValueEnum = require('../value/valueenum'),
    SummaryValue = require('../value/summary-value'),
    DataOutPutX = require('../io/data-outputx'),
    DataInputX = require('../io/data-inputx'),
    HashUtil = require('../util/hashutil'),
    MapValue = require('../value/map-value')

function TagCountPack() {
    Pack.call(this);
    this.category = ''
    this.tagHash = 0
    this.originOid = null;
    this.tags = new MapValue()
    this.fields = new MapValue()
    this.read_size;
    this.fieldPos;
    this.tagPos;
    this.madeByPlugIn;
}

TagCountPack.prototype = new Pack();
TagCountPack.prototype.constructor = TagCountPack;

TagCountPack.prototype.getPackType = function () {
    return PackEnum.TAG_COUNT;
};

TagCountPack.prototype.setOriginOid = function (oid) {
    this.originOid = oid
};

TagCountPack.prototype.resetOid = function () {
    if (this.originOid !== null) {
        this.oid = this.originOid;
        this.originOid = null;
    }
};

TagCountPack.prototype.getTagString = function (name) {
    return this.tags.getText(name);
}

TagCountPack.prototype.getTagNotNull = function (name) {
    var v = this.tags.getText(name);
    return v == null ? "" : v;
}

TagCountPack.prototype.getTag = function (name) {
    return this.tags.get(name);
}

TagCountPack.prototype.getTagInt = function (name) {
    return this.tags.getInt(name);
}

TagCountPack.prototype.getTagLong = function (name) {
    return this.tags.getLong(name);
}

TagCountPack.prototype.putTag = function (name, value) {
    this.tags.put(name, value);
    return this;
}

TagCountPack.prototype.putTagInt = function (name, value) {
    this.tags.putInt(name, value);
    return this;
}

TagCountPack.prototype.putTagString = function (name, value) {
    this.tags.putString(name, value);
    return this;
}

TagCountPack.prototype.putTagLong = function (name, value) {
    this.tags.putLong(name, value);
    return this;
}

TagCountPack.prototype.putTagFloat = function (name, value) {
    this.tags.putFloat(name, value);
    return this;
}

TagCountPack.prototype.putTagDouble = function (name, value) {
    this.tags.putDouble(name, value);
    return this;
}

TagCountPack.prototype.putTagBoolean = function (name, value) {
    this.tags.putBoolean(name, value);
    return this;
}

TagCountPack.prototype.put = function (name, value) {
    this.fields.put(name, value);
}

TagCountPack.prototype.putInt = function (name, value) {
    this.fields.putInt(name, value);
}

TagCountPack.prototype.putLog = function (name, value) {
    this.fields.putLong(name, value);
}

TagCountPack.prototype.putString = function (name, value) {
    this.fields.putString(name, value);
}

TagCountPack.prototype.putFloat = function (name, value) {
    this.fields.putFloat(name, value);
}

TagCountPack.prototype.putDouble = function (name, value) {
    this.fields.putDouble(name, value);
}

TagCountPack.prototype.putBoolean = function (name, value) {
    this.fields.putBoolean(name, value);
}

TagCountPack.prototype.get = function (name) {
    return this.fields.get(name);
}

TagCountPack.prototype.getField = function (key) {
    return get(key);
}

TagCountPack.prototype.getFloat = function (name) {
    var val = this.fields.get(name);
    if (val == null)
        return 0;
    switch (val.getValueType()) {
        case ValueEnum.DOUBLE_SUMMARY:
        case ValueEnum.LONG_SUMMARY:
            return val.avg();
        case ValueEnum.METRIC:
            return val.avg();
        default:
            if (val instanceof Number) {
                return val.doubleValue();
            }
    }
    return 0;
}

TagCountPack.prototype.getLong = function (name) {
    var val = this.fields.get(name);
    if (val == null)
        return 0;
    switch (val.getValueType()) {
        case ValueEnum.DOUBLE_SUMMARY:
        case ValueEnum.LONG_SUMMARY:
            return val.avg().longValue();
        case ValueEnum.METRIC:
            return val.avg();
        default:
            if (val instanceof Number) {
                return val.longValue();
            }
    }
    return 0;
}

TagCountPack.prototype.write = function (dout) {
    Pack.prototype.write.call(this, dout);
    dout.writeByte(1);
    dout.writeText(this.category);
    /*
    if (this.tagHash == 0 && this.tags.size() > 0) {
        var tagBytes = this.resetTagHash();
        dout.writeDecimal(this.tagHash);
        dout.write(tagBytes);
    } else {
        this.tagHash = 0;
        dout.writeDecimal(this.tagHash);
        dout.writeValue(this.tags);
    }
    */
    this.tagHash = 0;
    dout.writeDecimal(this.tagHash);
    dout.writeValue(this.tags);
    dout.writeValue(this.fields);
    if (this.originOid != null) {
        dout.writeBoolean(true);
        dout.writeInt(this.originOid);
    } else {
        dout.writeBoolean(false);
    }
}

TagCountPack.prototype.resetTagHash = function () {
    var tagIO = new DataOutPutX();
    tagIO.writeValue(this.tags);
    var tagBytes = tagIO.toByteArray();
    this.tagHash = HashUtil.hash(tagBytes);
    return tagBytes;
}

TagCountPack.prototype.read = function (din) {
    var offset1 = din.getOffset();
    Pack.prototype.read.call(this, din);
    var ver = din.readByte();
    this.category = din.readText();
    this.tagHash = din.readDecimal();
    this.tags = din.readValue();
    this.fields = din.readValue();
    if (ver == 0) {
        this.read_size = din.getOffset() - offset1;
        return this;
    }
    if (din.readBoolean()) {
        this.originOid = din.readInt();
    }
    this.read_size = din.getOffset() - offset1;
    return this;
}

TagCountPack.prototype.isEmpty = () => {
    return this.fields.isEmpty();
}

TagCountPack.prototype.size = () => {
    return this.fields.size();
}

TagCountPack.prototype.clear = () => {
    this.fields.clear();
}

TagCountPack.prototype.writeHead = () => {
    var dout = new DataOutPutX();

    dout.writeDecimal(this.time);
    dout.writeDecimal(this.oid);
    dout.writeDecimal(this.okind);
    dout.writeDecimal(this.onode);

    dout.writeDecimal(this.tagHash);
    dout.writeDecimal(this.tagPos);
    dout.writeDecimal(this.fieldPos);
    return dout.toByteArray();
}

TagCountPack.prototype.writeField = (info) => {
    var dout = new DataOutPutX();
    _writeMap(this.fields, info.field, dout);
    return dout.toByteArray();
}

TagCountPack.prototype.writeTag = (info) => {
    var dout = new DataOutPutX();
    _writeMap(this.tags, info.tags, dout);
    return dout.toByteArray();
}

TagCountPack.prototype._readMap = (map, info, din) => {
    while (din.readBoolean()) {
        var idx = din.readDecimal();
        var value = din.readValue();
        var key = info.getName(idx);
        map.put(key, value);
    }
}

TagCountPack.prototype._writeMap = (fields, info, dout) => {
    var en = fields.keys();
    while (en.hasMoreElements()) {
        var key = en.nextString();
        var value = fields.get(key);
        var idx = info.intern(key);
        dout.writeBoolean(true);
        dout.writeDecimal(idx);
        dout.writeValue(value);
    }
    dout.writeBoolean(false);
}

TagCountPack.prototype.readHead = (b) => {
    var din = new DataInputX(b);
    this.time = din.readDecimal();
    this.oid = din.readDecimal();
    this.okind = din.readDecimal();
    this.onode = din.readDecimal();

    this.tagHash = din.readDecimal();
    this.tagPos = din.readDecimal();
    this.fieldPos = din.readDecimal();

    this.read_size += b.length;

    return this;
}

TagCountPack.prototype.readTag = (b, info) => {
    var din = new DataInputX(b);
    this._readMap(this.tags, info.tags, din);

    this.read_size += b.length;

    return this;
}

TagCountPack.prototype.readField = (b, info) => {
    var din = new DataInputX(b);
    this._readMap(this.fields, info.field, din);

    this.read_size += b.length;

    return this;
}

TagCountPack.prototype.getCategory = () => {
    return this.category;
}

TagCountPack.prototype.hasAnyField = (fields) => {
    if (fields != null) {
        fields.array.forEach(element => {
            if (this.fields.get(element) != null) {
                return true;
            }
        });
    }
    return false;
}

TagCountPack.prototype.createTagHash = (tags) => {
    if (tags === null || tags.length === 0) return 0;

    var tagIO = new DataOutPutX();
    for (var k in tags) {
        let v = this.tags.get(t);
        if (v != null) {
            tagIO.writeValue(v);
        }
    }
    let tagBytes = tagIO.toByteArray();
    return HashUtil.hash(tagBytes);
}

TagCountPack.prototype.copyCompact = () => {
    var p = new TagCountPack();
    p.time = this.time;
    p.pcode = this.pcode;
    p.oid = this.oid;
    p.okind = this.okind;
    p.onode = this.onode;
    p.category = this.category.intern();
    p.tagHash = this.tagHash;

    var en = this.tags.entries();
    while (en.hasMoreElements()) {
        let ent = en.nextElement();
        let key = ent.getKey().intern();
        let val = ent.getValue();
        if (val.getValueType() == ValueEnum.TEXT) {
            var t = val;
            t.value = t.value.intern();
        }
        p.tags.put(key, val);
    }

    p.fields = this.fields.copy();
    return p;
}

TagCountPack.prototype.isTag = (key, val) => {
    return val.equals(this.getTagString(key));
}

TagCountPack.prototype.flat = () => {
    var out = new MapValue();
    out.put("time", this.time);
    if (this.oid != 0) {
        out.put("oid", this.oid);
    }
    if (this.okind != 0) {
        out.put("okind", this.okind);
    }
    if (this.onode != 0) {
        out.put("onode", this.onode);
    }
    out.putAll(this.tags);
    out.putAll(this.fields);
    return out;
}

module.exports = TagCountPack;