class DataToTbHandler {

  constructor(index) {
    this.index = index;

    // time, after new value for the given key will be resend to tb (e.g. {status: "OK"})
    this.timeToHoldTbValue = 30 * 60; //30 minutes
    this.previousValues = {};
    this.debug = false;
    this.messageCounter = 0;
    this.itIsNodeReadout = false;
    this.sender = "";

    // if attribute change difference is less than limit value, we do not send to tb.
    this.attributeChangeLimit = {
      temperature: 0.5,
      Phase_1_voltage: 2,
      Phase_2_voltage: 2,
      Phase_3_voltage: 2,
      Phase_1_current: 0.1,
      Phase_2_current: 0.1,
      Phase_3_current: 0.1,
      Phase_1_power: 2,
      Phase_2_power: 2,
      Phase_3_power: 2,
      total_power: 2,
      total_energy: 1,
      Phase_1_pow_factor: 0.1,
      Phase_2_pow_factor: 0.1,
      Phase_3_pow_factor: 0.1,
      power_factor: 0.1,
      lifetime: 2,
      voltage: 2,
      power: 2,
      frequency: 3,
      energy: 0.1,
      current: 2,
      inclination_x: 10,
      inclination_y: 10,
      inclination_z: 10
    };

  }

  dump() {
    console.log("----------------------------");
    console.log("previousValues", this.previousValues);
    console.log("----------------------------");
  }

  setSender(sender) {
    this.sender = sender;
  }

  isEmptyObject(obj) {
    for (var _ in obj) {
      return false;
    }
    return true;
  }


  sendToTb(data, instance) {

    //not to modify data object, we do deep copy:
    let dataCopy = JSON.parse(JSON.stringify(data));

    let keys = Object.keys(dataCopy);

    if (keys.length == 0) {
      if (this.debug) console.log("sendToTb received empty object", dataCopy);
      return;
    }

    let tbname = keys[0];
    let ts;

    let arrayOfValues = dataCopy[tbname];
    let arrayOfValuesToSend = [];

    for (let i = 0; i < arrayOfValues.length; i++) {

      ts = arrayOfValues[i].ts;
      let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);

      if (!this.isEmptyObject(values)) {
        arrayOfValuesToSend.push({ ts: ts, values: values });
      }

    }

    if (arrayOfValuesToSend.length == 0) {
      //if(this.debug) console.log("data not sent - empty array");
      return;
    }

    this.messageCounter++;

    let dataToTbModified = {
      [tbname]: arrayOfValuesToSend
    }

    //console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance);
    //if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend);
    instance.send(this.index, dataToTbModified);
  }


  getDiffTimestamp(key) {
    //TODO set different value for given key!!!
    //if(key == "status") this.timeToHoldTbValue = 2*60*60;//2h
    return this.timeToHoldTbValue * 1000;
  }


  prepareValuesForTb(tbname, timestamp, values) {

    let keys = Object.keys(values);

    if (keys.includes("lifetime")) this.itIsNodeReadout = true;

    if (!this.previousValues.hasOwnProperty(tbname)) {
      this.previousValues[tbname] = {};
    }

    //if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values);

    for (let i = 0; i < keys.length; i++) {

      let key = keys[i];
      let value = values[key];

      if (!this.previousValues[tbname].hasOwnProperty(key)) {
        this.previousValues[tbname][key] = { ts: timestamp, value: value };
        continue;
      }

      // attributeData ==> {voltage: {ts:333333, value:5}}
      let attributeData = this.previousValues[tbname][key];
      let attributeToChange = false;
      if (key in this.attributeChangeLimit) attributeToChange = true;
      let limit = this.attributeChangeLimit[key];
      let timestampDiffToRemoveKey;

      //this will ensure "node statecode" will be sent just once an hour
      if (this.itIsNodeReadout && key === "statecode") {
        attributeData.value = value;
        this.itIsNodeReadout = false;
        timestampDiffToRemoveKey = 1 * 60 * 60 * 1000; // 1 hour
      }

      if (key === "twilight_sensor" && value > 100) {
        attributeData.value = value;
      }

      //if edge, master or node version do not change, send just once a day:
      if (["edge_fw_version", "master_node_version", "fw_version"].includes(key)) {
        timestampDiffToRemoveKey = 24 * 60 * 60 * 1000;
      }

      if (attributeData.value === value || attributeToChange && Math.abs(attributeData.value - value) < limit) {

        let diff = timestamp - attributeData.ts;
        if (!timestampDiffToRemoveKey) timestampDiffToRemoveKey = this.getDiffTimestamp(key);

        if (diff > timestampDiffToRemoveKey) {
          attributeData.ts = Date.now();
          //if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter);
        }
        else {
          delete values[key];
          //if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey);
        }
      }
      else {
        attributeData.value = value;
        attributeData.ts = timestamp;
      }

    }

    return values;
  }
}

module.exports = DataToTbHandler;

