{{comments}}

from rcl_interfaces.msg import ParameterDescriptor
from rcl_interfaces.msg import SetParametersResult
from rcl_interfaces.msg import FloatingPointRange, IntegerRange
from rclpy.clock import Clock
from rclpy.exceptions import InvalidParameterValueException
from rclpy.time import Time
import copy
import rclpy
from generate_parameter_library_py.python_validators import ParameterValidators

{% if user_validation_file|length -%}
import {{user_validation_file}} as custom_validators
{% endif %}

class {{namespace}}:
{%- filter indent(width=4) %}

class Params:
{%- filter indent(width=4) %}
# for detecting if the parameter struct has been updated
stamp_ = Time()

{{field_content-}}
{{sub_struct_content-}}
{% endfilter -%}
{%- endfilter %}


    class ParamListener:
        def __init__(self, node, prefix=""):
            node.declare_parameter('my_parameter', 'world')
            self.prefix_ = prefix
            self.params_ = {{namespace}}.Params()
            self.node_ = node
            self.logger_ = rclpy.logging.get_logger("{{namespace}}." + prefix)

            self.declare_params()

            self.node_.add_on_set_parameters_callback(self.update)
            self.clock_ = Clock()

        def get_params(self):
            tmp = self.params_.stamp_
            self.params_.stamp_ = None
            paramCopy = copy.deepcopy(self.params_)
            paramCopy.stamp_ = tmp
            self.params_.stamp_ = tmp
            return paramCopy

        def is_old(self, other_param):
            return self.params_.stamp_ != other_param.stamp_

        def refresh_dynamic_parameters(self):
            updated_params = self.get_params()
            # TODO remove any destroyed dynamic parameters
{%- filter indent(width=6) %}
{{remove_dynamic_parameters}}
{%- endfilter %}
            # declare any new dynamic parameters
{%- filter indent(width=12) %}
{{update_declare_dynamic_parameters}}
{%- endfilter %}

        def update(self, parameters):
            updated_params = self.get_params()

            for param in parameters:
{%- filter indent(width=16) %}
{{update_params_set}}
{%- endfilter %}
{% if update_dynamic_parameters|length %}
{%- filter indent(width=12) %}
# update dynamic parameters
for param in parameters:
{%- filter indent(width=4) %}
{{update_dynamic_parameters}}
{%- endfilter %}
{%- endfilter %}
{%- endif %}

            updated_params.stamp_ = self.clock_.now()
            self.update_internal_params(updated_params)
            return SetParametersResult(successful=True)

        def update_internal_params(self, updated_params):
            self.params_ = updated_params

        def declare_params(self):
            updated_params = self.get_params()
            # declare all parameters and give default values to non-required ones
{%- filter indent(width=12) %}
{{declare_params}}
{%- endfilter %}
            # TODO: need validation
            # get parameters and fill struct fields

{%- filter indent(width=12) %}
{{declare_params_set}}
{%- endfilter %}
{% if declare_set_dynamic_params|length %}
{% filter indent(width=12) %}
# declare and set all dynamic parameters
{{declare_set_dynamic_params}}
{%- endfilter %}
{%- endif %}

            self.update_internal_params(updated_params)
