/******************************************************************
 *
 *    THIS FILE HAS BEEN AUTOGENERATED, DO NOT MODIFY
 *
 ******************************************************************/

#ifndef GEN_{{file_id}}_DTO_H_
#define GEN_{{file_id}}_DTO_H_

#include <rockspring/rockspring.h>

namespace {{namespace}} {

namespace _ {

{% for msg in messages %}

struct {{ msg.struct_name }} {
{% for field in msg.fields %}
  {{ field.type_in_struct }} {{ field.name_in_struct }}{};  
{% endfor %}
};

{% endfor %}

}

{% for msg in messages %}

class {{ msg.class_name }} {
 public:
  {{msg.class_name}}() : _base(0), _arena(nullptr) {}
  {{msg.class_name}}(uint64_t base, rs::Arena *arena) : _base(base), _arena(arena) {}
  {{msg.class_name}}(rs::Arena *arena) : _arena(arena) {
    _base = _arena->Request(sizeof({{ msg.struct_ref_name }}));
  }

{% for field in msg.fields %}
{% if field.kind == 'simple' %}
  {{field.getter_type}} {{field.getter}}{{field.property_name}}() {
    return data()->{{field.name_in_struct}};
  }

  void Set{{field.property_name}}({{field.getter_type}} value) {
     data()->{{field.name_in_struct}} = value;
  }
{% elif field.kind == 'string' %}

  std::string Get{{field.property_name}}() {
    return std::string((char *) _arena->Read(data()->{{field.name_in_struct}}.offset));
  }

  void Set{{field.property_name}}(const std::string &value) {
#ifndef NDEBUG
    if (data()->{{field.name_in_struct}}.size != 0) {
      throw rs::RsException("Reassigning is not allowed");
    }
#endif
    uint64_t size = strlen(value.c_str()) + 1;
    uint64_t offset = _arena->Request(size);
    memcpy(_arena->Read(offset), value.c_str(), size);
    {{msg.struct_ref_name}} *ptr = data();
    ptr->{{field.name_in_struct}}.offset = offset;
    ptr->{{field.name_in_struct}}.size = size;
  }
{% elif field.kind == 'list' %}

  void Init{{field.property_name}}(uint64_t count) {
#ifndef NDEBUG
    if (data()->{{field.name_in_struct}}.size != 0) {
      throw rs::RsException("Reitializing collection is not allowed");
    }
#endif
    uint64_t size = count * sizeof({{field.internal_type}});
    uint64_t offset = _arena->Request(size);
    {{msg.struct_ref_name}} *ptr = data();
    ptr->{{field.name_in_struct}}.offset = offset;
    ptr->{{field.name_in_struct}}.size = size;
  }

  {% if field.list_by_value %}
  ::rs::{{field.list_type}}<{{field.getter_type}}> Get{{field.property_name}}() {
    return ::rs::ValueList<{{field.getter_type}}>(data()->{{field.name_in_struct}}, _arena);
  }
  {% else %}
  ::rs::{{field.list_type}}<{{field.getter_type}}> Get{{field.property_name}}() {
    return ::rs::List<{{field.getter_type}}>(
      data()->{{field.name_in_struct}}, _arena, sizeof({{field.internal_type}}));
  }
  {% endif %}

{% elif field.kind == 'reference' %}
  {{field.getter_type}} Get{{field.property_name}}() {
    return {{field.getter_type}}(_base + ((char *)&data()->{{field.name_in_struct}} - (char *)data()), _arena);
  }  
{% endif %}
{% endfor %}

  std::string ToString(int indent = 0) {
    std::string spaces;
    std::string res;

    for (int i = 0; i < indent; i++) {
      spaces += " ";
    }

    res += spaces + "At: " + std::to_string(_base) + "\n";

{% for field in msg.fields %}
{% if field.kind == 'simple' %}
    res += spaces + "{{field.property_name}} " + std::to_string({{field.getter}}{{field.property_name}}()) + "\n";
{% elif field.kind == 'string' %}
    res += spaces + "{{field.property_name}} '" + Get{{field.property_name}}() + "'\n";
{% elif field.kind == 'list' %}
    res += spaces + "{{field.property_name}}\n";
    auto {{field.property_name}}_lst = Get{{field.property_name}}();

    for (int i = 0; i < {{field.property_name}}_lst.count(); i++) {
      {% if field.list_by_value %}
      res += std::to_string({{field.property_name}}_lst.get(i));
      {% else %}
      res += {{field.property_name}}_lst.get(i).ToString(indent + 2);
      {% endif %}
    }
{% elif field.kind == 'reference' %}
  res += spaces + "{{field.property_name}}\n";
  res += Get{{field.property_name}}().ToString(indent + 2);
{% endif %}
{% endfor %}
    return res;
  }
 private:
  {{ msg.struct_ref_name }} *data() const { return ({{ msg.struct_ref_name }} *) _arena->Read(_base); }
  uint64_t _base{};
  rs::Arena *_arena{};

};

{% endfor %}

}


#endif   // GEN_{{file_id}}_DTO_H_