#ifndef TLV_H
#define TLV_H

#include <stdint.h>

#define TLV_ARRAY_TYPE  0xAB
#define TLV_OBJECT_TYPE  0xE7
#define TLV_STRING_TYPE  0x3D
#define TLV_INTEGER     0x77
#define TLV_REAL        0xB8

#include <iostream>
#include <fstream>

class Tlv
{
public:
    explicit Tlv()
    {
    }

    ~Tlv() {

    }

    void Save(const std::string &filename)
    {
        auto f = std::ofstream(filename, std::ios::out | std::ios::binary);
        f << m_mem;
        std::flush(f);
        f.close();
    }

    void add_array(uint16_t size)
    {
        m_mem.append(reinterpret_cast<const char*>(&m_arrayType), sizeof(m_arrayType));
        m_mem.append(reinterpret_cast<const char*>(&size), sizeof(size));
    }

    void add_string(const char *s, uint16_t size)
    {
        m_mem.append(reinterpret_cast<const char*>(&m_stringType), sizeof(m_stringType));
        m_mem.append(reinterpret_cast<const char*>(&size), sizeof(size));
        m_mem.append(s, size);
    }

    void add_integer(uint32_t value)
    {
        static const uint16_t size = 4;
        m_mem.append(reinterpret_cast<const char*>(&m_integerType), sizeof(m_integerType));
        m_mem.append(reinterpret_cast<const char*>(&size), sizeof(size));
        m_mem.append(reinterpret_cast<const char*>(&value), size);
    }

    void add_string(const std::string &s)
    {
        add_string(s.c_str(), s.size());
    }

    void add_object(uint16_t entries)
    {
        m_mem.append(reinterpret_cast<const char*>(&m_objectType), sizeof(m_objectType));
        m_mem.append(reinterpret_cast<const char*>(&entries), sizeof(entries));
    }

private:
    std::string m_mem;

    uint8_t m_arrayType = TLV_ARRAY_TYPE;
    uint8_t m_objectType = TLV_OBJECT_TYPE;
    uint8_t m_stringType = TLV_STRING_TYPE;
    uint8_t m_integerType = TLV_INTEGER;

};


#endif // TLV_H
