#ifndef {{ spec.package|upper }}_MESSAGE_{{ spec.short_name|upper }}
#define {{ spec.package|upper }}_MESSAGE_{{ spec.short_name|upper }}

#include <string>
#include <vector>
#include <memory>

#include <ros/types.h>
#include <ros/serialization.h>
#include <ros/builtin_message_traits.h>
#include <ros/message_operations.h>
{% for field in spec.fields %}
{%- if not is_intrinsic_type(field) %}
#include <{{ field.package }}/{{ field.field_type }}.h>
{%- endif -%}
{%- endfor %}

namespace {{ spec.package }} {

template <class ContainerAllocator>
struct {{ spec.short_name }}_
{
  typedef {{ spec.short_name }}_<ContainerAllocator> Type;

  {#- Constructors and initializer lists #}
  {%- if spec.fields|length > 0 %}
  {{ spec.short_name }}_()
    : {{ spec.fields|map(attribute="name")|join('()\n    , ') }}() {
  }

  {{ spec.short_name }}_(const ContainerAllocator& _alloc)
    : {{ spec.fields|map(attribute="name")|join('(_alloc)\n    , ') }}(_alloc) {
    (void)_alloc;
  }
  {%- else %}
  {{ spec.short_name }}_()
  {
  }

  {{ spec.short_name }}_(const ContainerAllocator& _alloc)
  {
    (void)_alloc;
  }
  {%- endif %}

  {#- Each variable field of the message type is defined here #}
  {%- for field in spec.fields %}
    {# This section is extremely verbose with repeated elements. 
       Trade-off here between repetition and ability to reason about what 
       code should be generated. 
    #}
    {%- if is_vector(field) %}
      {%- if is_intrinsic_type(field) %}
        typedef std::vector<{{ field.field_type|typename_conversion }}, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<{{ field.field_type|typename_conversion }}>> _{{ field.name }}_type;
      {%- else %}
        typedef std::vector<::{{ field.package }}::{{ field.field_type }}_<ContainerAllocator>, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<::{{ field.package }}::{{ field.field_type }}_<ContainerAllocator>>> _{{ field.name }}_type;
      {%- endif %}
    {%- elif is_fixed_array(field) %}
      {%- if is_intrinsic_type(field) %}
        typedef boost::array<{{ field.field_type|typename_conversion }}, {{ field|fixed_size_array_size }}> _{{ field.name }}_type;
      {%- else %}
        typedef boost::array<::{{ field.package }}::{{ field.field_type }}_<ContainerAllocator>, {{ field|fixed_size_array_size }}> _{{ field.name }}_type;
      {%- endif %}
    {%- else %}
      {%- if is_intrinsic_type(field) %}
        typedef {{ field.field_type|typename_conversion }} _{{ field.name }}_type;
      {%- else %}
        typedef ::{{ field.package }}::{{ field.field_type }}_<ContainerAllocator> _{{ field.name }}_type;
      {%- endif %}
    {%- endif %}
    _{{ field.name }}_type {{ field.name }};
  {%- endfor %}

  {# Numeric constant fields (like enums ) are each defined here #}
  {%- if spec.constants|length > 0 %}
    enum {
    {%- for constant in spec.constants %}
      {%- if constant.constant_type in ['byte', 'int8', 'int16', 'int32', 'int64', 'char'] %}
        {{ constant.name }} = {{ constant.constant_value }},
      {%- elif constant.constant_type in ['uint8', 'uint16', 'uint32', 'uint64'] %}
        {{ constant.name }} = {{ constant.constant_value }}u,
      {%- endif -%}
    {%- endfor %}
    };
  {%- endif %}

  {#- Non-numeric constant fields are declared here, but defined below 
     outside of the class definition.
  #}
  {%- for constant in spec.constants %}
    {%- if constant.constant_type not in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64'] %}
      static const {{ constant.constant_type|typename_conversion }} {{ constant.name }};
    {%- endif %}
  {%- endfor %}

  typedef boost::shared_ptr< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>> Ptr;
  typedef boost::shared_ptr< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator> const> ConstPtr;

}; // struct {{ spec.short_name }}_

typedef ::{{ spec.package }}::{{ spec.short_name }}_<std::allocator<void>> {{ spec.short_name }};

typedef boost::shared_ptr< ::{{ spec.package }}::{{ spec.short_name }}> {{ spec.short_name }}Ptr;
typedef boost::shared_ptr< ::{{ spec.package }}::{{ spec.short_name }} const> {{ spec.short_name }}ConstPtr;

// constants requiring out of line definition
{%- for constant in spec.constants %}
  {%- if constant.constant_type not in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64'] %}
    template<typename ContainerAllocator> const {{ constant.constant_type|typename_conversion }}
      {{ spec.short_name }}_<ContainerAllocator>::{{ constant.name }} = 
        {%- if constant.constant_type == 'string' %}
          u8{{ constant.constant_value }}
        {%- elif constant.constant_type == 'bool' %}
          int({{ constant.constant_value|lower }})
        {%- else %}
          {{ constant.constant_value }}
        {% endif -%}
        ;
  {% endif -%}
{%- endfor %}

template<typename ContainerAllocator>
std::ostream& operator<<(std::ostream& s, const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator> & v)
{
ros::message_operations::Printer< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator> >::stream(s, "", v);
return s;
}

template<typename ContainerAllocator1, typename ContainerAllocator2>
bool operator==(const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator1> & lhs, const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator2> & rhs)
{
  return
    {%- for field in spec.fields %}
    lhs.{{ field.name }} == rhs.{{ field.name }} &&
    {%- endfor %}
    true;
}

template<typename ContainerAllocator1, typename ContainerAllocator2>
bool operator!=(const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator1> & lhs, const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator2> & rhs)
{
  return !(lhs == rhs);
}


} // namespace {{ spec.package }}

namespace ros
{
namespace message_traits
{
template <class ContainerAllocator>
struct IsMessage< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>>
  : TrueType
  { };

template <class ContainerAllocator>
struct IsMessage< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator> const>
  : TrueType
  { };

template <class ContainerAllocator>
struct IsFixedSize< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>>
  : {% if is_fixed_length(spec) -%}
    TrueType
    {% else -%}
    FalseType
    {% endif -%}
  { };

template <class ContainerAllocator>
struct IsFixedSize< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator> const>
  : {% if is_fixed_length(spec) -%}
    TrueType
    {% else -%}
    FalseType
    {% endif -%}
  { };

template <class ContainerAllocator>
struct HasHeader< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>>
  : {% if has_header(spec) -%}
    TrueType
    {% else -%}
    FalseType
    {% endif -%}
  { };

template <class ContainerAllocator>
struct HasHeader< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator> const>
  : {% if has_header(spec) -%}
    TrueType
    {% else -%}
    FalseType
    {% endif -%}
  { };

template<class ContainerAllocator>
struct MD5Sum< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>>
{
  static constexpr char const * value()
  {
    return "{{ spec.md5sum_first }}{{ spec.md5sum_second }}";
  }

  static const char* value(const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>&) { return value(); }
  static const uint64_t static_value1 = 0x{{ spec.md5sum_first }}ULL;
  static const uint64_t static_value2 = 0x{{ spec.md5sum_second }}ULL;
};

template<class ContainerAllocator>
struct DataType< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>>
{
  static constexpr char const* value()
  {
    return "{{ spec.package }}/{{ spec.short_name }}";
  }

  static const char* value(const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>&) { return value(); }
};

template<class ContainerAllocator>
struct Definition< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>>
{
  static constexpr char const* value()
  {
    return "{{ spec.description }}";
  }

  static const char* value(const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>&) { return value(); }
};

} // namespace message_traits
} // namespace ros

namespace ros
{
namespace serialization
{

template<class ContainerAllocator>
struct Serializer< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>>
{
  {%- if spec.fields|count > 0 %}
  template<typename Stream, typename T> inline static void allInOne(Stream& stream, T m)
  {
    {%- for field in spec.fields %}
    stream.next(m.{{ field.name }});
    {%- endfor %}
  }
  {%- else %}
  template<typename Stream, typename T> inline static void allInOne(Stream&, T)
  {}
  {%- endif %}

  ROS_DECLARE_ALLINONE_SERIALIZER
}; // struct {{ spec.short_name }}_

} // namespace serialization
} // namespace ros

namespace ros
{
namespace message_operations
{

template<class ContainerAllocator>
struct Printer< ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>>
{
  {%- if spec.fields|count > 0 %}
  template<typename Stream> static void stream(Stream& s, const std::string& indent, const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>& v)
  {
    {%- for field in spec.fields %}
    {%- if is_vector(field) %}
    
    s << indent << "{{ field.name }}[]" << std::endl;
    for (size_t i = 0; i < v.{{ field.name }}.size(); ++i)
    {
      s << indent << "  {{ field.name }}[" << i << "]: ";
      {%- if not is_intrinsic_type(field) %}
      s << std::endl;
      s << indent;
      Printer<::{{ field.package }}::{{ field.field_type}}>::stream(s, indent + "    ", v.{{ field.name }}[i]);
      {%- else %}
      Printer<{{ field.field_type|typename_conversion }}>::stream(s, indent + "  ", v.{{ field.name }}[i]);
      {%- endif %}
    }
    {%- else %}

    s << indent << "{{ field.name }}: ";
    {%- if is_intrinsic_type(field) %}
    Printer< {{ field.field_type|typename_conversion }}>::stream(s, indent + "  ", v.{{ field.name }});
    {%- else %}
    s << std::endl;
    Printer< ::{{ field.package }}::{{ field.field_type }}_<ContainerAllocator>>::stream(s, indent + "  ", v.{{ field.name }});
    {%- endif %}

    {%- endif %}
    {%- endfor %}
  }
  {%- else %}
  template<typename Stream> static void stream(Stream& s, const std::string& indent, const ::{{ spec.package }}::{{ spec.short_name }}_<ContainerAllocator>& v)
  {}
  {%- endif %}
};

} // namespace message_operations
} // namespace ros

#endif // {{ spec.package|upper }}_MESSAGE_{{ spec.short_name|upper }}
