//
// Created by magino on 20.5.2019.
//

#ifndef MODBUSCLIENT_H
#define MODBUSCLIENT_H

#include <chrono>
#include <memory>
#include <bitset>
#include <mutex>

#include <open62541/types.h>
#include <open62541/types_generated.h>
#include <modbus/modbus.h>

#include "compositeBuilder/S7CsvDataBlock/S7CsvRowModel.h"
#include "configuration/ModbusTcpClientCfg.h"
#include "ICommunication.h"
#include "communication/EEndian.h"


class ModbusTcpClient: public ICommunication {
private:
    modbus_t* _modbus;
    std::mutex _lock;

    bool _isConnected;
    ModbusTcpClientCfg _config;
    uint16_t* _buffer;

    EEndian _endian;
    int _startAddress;
    int _endAddress;

    UA_Boolean GetBoolAt(float offset);
    UA_String GetString(int pos);

    void WriteBoolAt(UA_Boolean val, float offset);
    void WriteByteAt(UA_Byte val, int offset);
    void WriteSByteAt(UA_SByte val, int offset);
    void WriteInt16At(UA_Int16 val, int pos);
    void WriteUInt16At(UA_UInt16 val, int pos);
    void WriteInt32At(UA_Int32 val, int pos);
    void WriteUInt32At(UA_UInt32 val, int pos);
    void WriteInt64At(UA_Int64 val, int pos);
    void WriteUInt64At(UA_UInt64 val, int pos);
    void WriteFloatAt(UA_Float val, int pos);
    void WriteDoubleAt(UA_Double val, int pos);
    void WriteStringAt(UA_String val, int pos);

    int GetAddressDiff() { return _endAddress - _startAddress; }
    /***
     * Calculate modbus register number from byte position in data block
     * @param pos of variable in data block
     * @return position in modbus register
     */
    int GetModbusRegisterPos(int pos);

    virtual void Reconnect(volatile bool* running);
    virtual int GetCycleTime();

public:
    ModbusTcpClient(ModbusTcpClientCfg cfg);
    ~ModbusTcpClient() {
        StopComm();
        delete[] _buffer;
    }

    virtual void GetData();
    virtual void StopComm();

    virtual UA_Variant ReadValue(void* params);
    virtual void WriteValue(UA_Variant data, void* params);
};

#endif //MODBUSCLIENT_H