@###############################################
@#
@# ROS message source code generation for C++
@#
@# EmPy template for generating <msg>.h files
@#
@###############################################
@# Start of Template
@#
@# Context:
@#  - file_name_in (String) Source file
@#  - spec (msggen.MsgSpec) Parsed specification of the .msg file
@#  - md5sum (String) MD5Sum of the .msg specification
@###############################################
/* Software License Agreement (BSD License)
 *
 * Copyright (c) 2011, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 *  * Neither the name of Willow Garage, Inc. nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Auto-generated by genmsg_cpp from file @file_name_in
 *
 */

@{
import genmsg.msgs
import gencpp

cpp_namespace = '::%s::'%(spec.package) # TODO handle nested namespace
cpp_class = '%s_'%spec.short_name
cpp_full_name = '%s%s'%(cpp_namespace,cpp_class)
cpp_full_name_with_alloc = '%s<ContainerAllocator>'%(cpp_full_name)
cpp_msg_definition = gencpp.escape_message_definition(msg_definition)
}@

#ifndef @(spec.package.upper())_MESSAGE_@(spec.short_name.upper())_H
#define @(spec.package.upper())_MESSAGE_@(spec.short_name.upper())_H

@##############################
@# Generic Includes
@##############################

#include <string>
#include <vector>
#include <map>

#include <ros/types.h>
#include <ros/serialization.h>
#include <ros/builtin_message_traits.h>
#include <ros/message_operations.h>

@##############################
@# Includes for dependencies
@##############################
@{
for field in spec.parsed_fields():
  if (not field.is_builtin):
    if (field.is_header):
      print('#include <std_msgs/Header.h>')
    else:
      (package, name) = genmsg.names.package_resource_name(field.base_type)
      package = package or spec.package # convert '' to package
      print('#include <%s/%s.h>'%(package, name))
}@

namespace @(spec.package)
{
template <class ContainerAllocator>
struct @(spec.short_name)_
{
  typedef @(spec.short_name)_<ContainerAllocator> Type;

@# constructors (with and without allocator)
@[for (alloc_type,alloc_name) in [['',''],['const ContainerAllocator& ','_alloc']]]@
  @(spec.short_name)_(@(alloc_type+alloc_name))
@# Write initializer list
  @('\n  '.join(gencpp.generate_initializer_list(spec, alloc_name != '' )))@
  {
@# Fixed length arrays
  @('\n  '.join(gencpp.generate_fixed_length_assigns(spec, alloc_name != '', '%s::'%(spec.package))))@
  }
@[end for]

@[for field in spec.parsed_fields()]
 @{cpp_type = gencpp.msg_type_to_cpp(field.type)}@
  typedef @(cpp_type) _@(field.name)_type;
  _@(field.name)_type @(field.name);
@[end for]

@# Constants
@[for constant in spec.constants]@
 @[if (constant.type in ['byte', 'int8', 'int16', 'int32', 'int64', 'char'])]@
   enum { @(constant.name) = @(int(constant.val)) };
 @[elif (constant.type in ['uint8', 'uint16', 'uint32', 'uint64'])]@
   enum { @(constant.name) = @(int(constant.val))u };
 @[else]@
   static const @(gencpp.msg_type_to_cpp(constant.type)) @(constant.name);
 @[end if]@
@[end for]

@# Shared pointer typedefs
  typedef boost::shared_ptr< @(cpp_full_name)<ContainerAllocator> > Ptr;
  typedef boost::shared_ptr< @(cpp_full_name)<ContainerAllocator> const> ConstPtr;

}; // struct @(cpp_class)

@# Typedef of template instance using std::allocator
typedef @(cpp_full_name)<std::allocator<void> > @(spec.short_name);

@# Shared pointer typedefs
typedef boost::shared_ptr< @(cpp_namespace+spec.short_name) > @(spec.short_name)Ptr;
typedef boost::shared_ptr< @(cpp_namespace+spec.short_name) const> @(spec.short_name)ConstPtr;

// constants requiring out of line definition
@[for c in spec.constants]
   @[if c.type not in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64']]
   template<typename ContainerAllocator> const @(gencpp.msg_type_to_cpp(c.type))
      @(spec.short_name)_<ContainerAllocator>::@(c.name) =
        @[if c.type == 'string']
          "@(gencpp.escape_string(c.val))"
        @[elif c.type == 'bool']
           @(int(c.val))
        @[else]
          @c.val
        @[end if]
        ;
   @[end if]
@[end for]


@# Printer
template<typename ContainerAllocator>
std::ostream& operator<<(std::ostream& s, const @(cpp_full_name_with_alloc) & v)
{
ros::message_operations::Printer< @(cpp_full_name_with_alloc) >::stream(s, "", v);
return s;
}

@# End of namespace
} // namespace @(spec.package)

@# Message Traits
namespace ros
{
namespace message_traits
{

@{
bool_traits = dict(IsMessage=True,
                   IsFixedSize=gencpp.is_fixed_length(spec, msg_context, search_path),
                   HasHeader=spec.has_header(),
                   )
def booltotype(b):
   return "TrueType" if b else "FalseType"
}

// BOOLTRAITS @bool_traits
// @search_path

@# TODO
// !!!!!!!!!!! @(dir(spec))
@#if spec.is_fixed_length():
@#    traits = traits.append('IsFixedSize')

@#template <class ContainerAllocator>
@#struct IsFixedSize<@(cpp_full_name_with_alloc) >:: @(dir(spec)) ? "TrueType" ! "FalseType") { };
@#template <class ContainerAllocator>
@#struct IsFixedSize<@(cpp_full_name_with_alloc) const >:: @(dir(spec)) ? "TrueType" ! "FalseType") { };

@# Binary traits

@[for k, v in bool_traits.items()]@

template <class ContainerAllocator>
struct @(k)< @(cpp_full_name_with_alloc) >
  : @(booltotype(v))
  { };

template <class ContainerAllocator>
struct @(k)< @(cpp_full_name_with_alloc) const>
  : @(booltotype(v))
  { };
@[end for]@

@# String traits
@[for trait_class,trait_value in [['MD5Sum', md5sum], ['DataType', spec.full_name], ['Definition', cpp_msg_definition]]]@

template<class ContainerAllocator>
struct @(trait_class)< @(cpp_full_name_with_alloc) >
{
  static const char* value()
  {
    return "@(trait_value)";
  }

  static const char* value(const @(cpp_full_name_with_alloc)&) { return value(); }
@{
if trait_class == 'MD5Sum':
  iter_count = int(len(trait_value) / 16)
  for i in range(0, iter_count):
    start = i*16
    print('  static const uint64_t static_value%s = 0x%sULL;'%((i+1), trait_value[start:start+16]))
}@
};
@[end for]@

@# End of traits
} // namespace message_traits
} // namespace ros

@# Serialization
namespace ros
{
namespace serialization
{

  template<class ContainerAllocator> struct Serializer< @(cpp_full_name_with_alloc) >
  {
@[if spec.parsed_fields()]@
    template<typename Stream, typename T> inline static void allInOne(Stream& stream, T m)
    {
@[for field in spec.parsed_fields()]@
      stream.next(m.@(field.name));
@[end for]@
    }
@[else]@
    template<typename Stream, typename T> inline static void allInOne(Stream&, T)
    {}
@[end if]@

    ROS_DECLARE_ALLINONE_SERIALIZER;
  }; // struct @(cpp_class)

} // namespace serialization
} // namespace ros

@# Message Operations
namespace ros
{
namespace message_operations
{

@# Printer operation
template<class ContainerAllocator>
struct Printer< @(cpp_full_name_with_alloc) >
{
@[if spec.parsed_fields()]@
  template<typename Stream> static void stream(Stream& s, const std::string& indent, const @(cpp_full_name_with_alloc)& v)
  {
@# todo, change this stuff below into proper EmPy syntax
@{
for field in spec.parsed_fields():
  cpp_type = gencpp.msg_type_to_cpp(field.base_type)
  if (field.is_array):
    print('    s << indent << "%s[]" << std::endl;'%(field.name))
    print('    for (size_t i = 0; i < v.%s.size(); ++i)'%(field.name))
    print('    {')
    print('      s << indent << "  %s[" << i << "]: ";'%(field.name))
    indent_increment = '  '
    if (not field.is_builtin):
      print('      s << std::endl;')
      print('      s << indent;')
      indent_increment = '    ';
    print('      Printer<%s>::stream(s, indent + "%s", v.%s[i]);'%(cpp_type, indent_increment, field.name))
    print('    }')
  else:
    print('    s << indent << "%s: ";'%(field.name))
    indent_increment = '  '
    if (not field.is_builtin or field.is_array):
      print('    s << std::endl;')
    print('    Printer<%s>::stream(s, indent + "%s", v.%s);'%(cpp_type, indent_increment, field.name))
}@
  }
@[else]@
  template<typename Stream> static void stream(Stream&, const std::string&, const @(cpp_full_name_with_alloc)&)
  {}
@[end if]@
};

} // namespace message_operations
} // namespace ros

#endif // @(spec.package.upper())_MESSAGE_@(spec.short_name.upper())_H
