# Definitions used for Jinja template replacement.

# This file is part of Cantera. See License.txt in the top-level directory or
# at https://cantera.org/license.txt for license and copyright information.

clib-param: |-
  @param{{ '[' + par.direction + ']' if par.direction }} {{ par.name }}

clib-comment: |-
  {{ brief }}

  {% if wraps %}
  Wraps C++ {{ what }}: `{{ wraps }}`

  {% endif %}
  {% if uses %}
  Uses:
  {% for uu in uses %}
  - `{{ uu }}`
  {% endfor %}

  {% endif %}
  {% for par in params %}
  {{ par }}
  {% endfor %}
  {% if returns %}
  {{ '@returns' + 12*' ' + returns }}
  {% endif %}
  {% if params or returns %}
  {% endif %}

clib-definition: |-
  {{ annotations }}
  {{ declaration }};

clib-function: |-
  // function: {{ cxx_wraps }}
  try {
      {% for line in lines %}
      {{ line }}
      {% endfor %}
      {% if buffer %}
      {% if buffer[0] %}
      {{ buffer[0] }} = {{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% else %}
      {{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% endif %}
      {% if buffer[1] %}
      {{ buffer[1] }}
      {% endif %}
      return {{ buffer[2] }};
      {% else %}
      return {{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% endif %}
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-variable-getter: |-
  // variable (getter): {{ cxx_wraps }}
  try {
      {% if handle %}
      ## access class member variable
      {% if cxx_base == base %}
      ## object can be accessed directly
      {% if buffer and buffer[0] %}
      {{ buffer[0] }} = {{ base }}Cabinet::at({{ handle }})->{{ cxx_name }};
      ## CLib/C++ variable crosswalk needed
      {% if buffer[1] %}
      {{ buffer[1] }}
      {% endif %}
      return {{ buffer[2] }};
      {% else %}{# not buffer[0] #}
      ## no crosswalk needed
      return {{ base }}Cabinet::at({{ handle }})->{{ cxx_name }};
      {% endif %}{# buffer[0] #}
      {% else %}{# base #}
      ## object needs a cast as method is defined for specialization
      {% if buffer and buffer[0] %}
      {{ buffer[0] }} = {{ base }}Cabinet::as<{{ cxx_base }}>({{ handle }})->{{ cxx_name }};
      ## CLib/C++ variable crosswalk needed
      {% if buffer[1] %}
      {{ buffer[1] }}
      {% endif %}
      return {{ buffer[2] }};
      {% else %}{# not buffer[0] #}
      ## no crosswalk needed
      return {{ base }}Cabinet::as<{{ cxx_base }}>({{ handle }})->{{ cxx_name }};
      {% endif %}{# buffer[0] #}
      {% endif %}{# base #}
      {% else %}{# not handle #}
      ## variable is defined in root namespace
      {% if buffer and buffer[0] %}
      ## CLib/C++ variable crosswalk needed
      {{ buffer[0] }} = {{ cxx_name }};
      {% if buffer[1] %}
      {{ buffer[1] }}
      {% endif %}
      return {{ buffer[2] }};
      {% else %}{# not buffer[0] #}
      ## no crosswalk needed
      return {{ cxx_name }};
      {% endif %}{# buffer[0] #}
      {% endif %}{# handle #}
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-variable-setter: |-
  // variable (setter): {{ cxx_wraps }}
  try {
      {% for line in lines %}
      ## add lines used for CLib/C++ variable crosswalk
      {{ line }}
      {% endfor %}
      {% if handle %}
      ## access class member variable
      {% if cxx_base == base %}
      ## object can be accessed directly
      {{ base }}Cabinet::at({{ handle }})->{{ cxx_name }} = {{ cxx_args[0] }};
      {% else %}{# not base #}
      ## object needs a cast as method is defined for specialization
      {{ base }}Cabinet::as<{{ cxx_base }}>({{ handle }})->{{ cxx_name }} = {{ cxx_args[0] }};
      {% endif %}{# base #}
      {% else %}{# not handle #}
      ## variable is defined in root namespace
      {{ cxx_name }} = {{ cxx_args[0] }};
      {% endif %}{# handle #}
      return 0;
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-constructor: |-
  ## CLib constructor template: instantiates new object
  // constructor: {{ cxx_wraps }}
  try {
      {% for line in lines %}
      ## add lines used for CLib/C++ variable crosswalk
      {{ line }}
      {% endfor %}
      {% if shared %}
      ## instantiated object manages associated objects (see: sol3_newSolution)
      ## storage of associated objects requires id (handle) of new object
      auto obj = {{ cxx_name }}({{ ', '.join(cxx_args) }});
      int id = {{ base }}Cabinet::add(obj);
      {% for typ, getter in shared %}
      ## add associated objects (see: sol3_newSolution, sol3_adjacent)
      if (obj->{{ getter }}()) {
          {{ typ }}Cabinet::add(obj->{{ getter }}(), id);
      }
      {% endfor %}
      return id;
      {% else %}{# not shared #}
      ## instantiated object has no associated objects; no id is needed
      return {{ base }}Cabinet::add({{ cxx_name }}({{ ', '.join(cxx_args) }}));
      {% endif %}{# shared #}
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-accessor: |-
  ## CLib accessor template: exposes existing C++ object to CLib
  // accessor: {{ cxx_wraps }}
  try {
      {% for line in lines %}
      ## add lines used for CLib/C++ variable crosswalk
      {{ line }}
      {% endfor %}
      {% if checks %}
      ## accessor uses index checker (see: sol3_adjacent)
      if ({{ c_args[1] }} < 0 || {{ c_args[1] }} >= {{ base }}Cabinet::at({{ handle }})->{{ checks[0] }}()) {
          throw IndexError("{{ c_func }}", "", {{ c_args[1] }}, {{ base }}Cabinet::at({{ handle }})->{{ checks[0] }}());
      }
      {% endif %}{# checks #}
      {% if shared %}
      ## accessed object manages associated objects (see: sol3_newSolution)
      ## storage of associated objects requires id (handle) of new object
      {% if cxx_rbase %}
      ## returned and accessed C++ objects may have a different bases
      auto obj = {{ cxx_base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
      int id = {{ cxx_rbase }}Cabinet::add(obj);
      ## return handle of newly created / accessed object
      {% for typ, getter in shared %}
      ## add associated objects (see: sol3_newSolution, sol3_adjacent)
      if (obj->{{ getter }}()) {
          {{ typ }}Cabinet::add(obj->{{ getter }}(), id);
      }
      {% endfor %}
      return id;
      {% else %}{# not cxx_rbase #}
      ## method modifies associated objects (see: sol3_setTransportModel)
      auto obj = {{ cxx_base }}Cabinet::at({{ handle }});
      {% for typ, getter in shared %}
      ## remove associated objects
      if (obj->{{ getter }}()) {
          {{ typ }}Cabinet::del(
              {{ typ }}Cabinet::index(*(obj->{{ getter }}()), handle));
      }
      {% endfor %}
      obj->{{ cxx_name }}({{ ', '.join(cxx_args) }});
      ## return handle to modified associated object (see: sol3_setTransportModel)
      {% for typ, getter in shared %}
      ## shared should have single entry
      return {{ typ }}Cabinet::add(obj->{{ getter }}(), handle);
      {% endfor %}
      {% endif %}{# cxx_rbase #}
      {% else %}{# not shared #}
      ## instantiated object has no associated objects; no id is needed
      ## returned and accessed C++ objects may have a different bases
      return {{ cxx_rbase }}Cabinet::add({{ base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }}));
      {% endif %}{# shared #}
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-destructor: |-
  ## CLib destructor template
  // destructor
  try {
      {% if shared %}
      auto obj = {{ base }}Cabinet::at({{ handle }});
      // remove all associated objects in reversed order
      {% for typ, getter in shared[-1::-1] %}
      if (obj->{{ getter }}()) {
          int index = {{ typ }}Cabinet::index(*(obj->{{ getter }}()), {{ handle }});
          if (index >= 0) {
              {{ typ }}Cabinet::del(index);
          }
      }
      {% endfor %}
      {% endif %}
      {{ base }}Cabinet::del({{ handle }});
      return 0;
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-method: |-
  ## CLib method template:
  ## covers methods as well as getters and setters for scalars
  // {{ what }}: {{ cxx_wraps }}
  try {
      {% for line in lines %}
      ## add lines used for CLib/C++ variable crosswalk
      {{ line }}
      {% endfor %}
      {% if buffer %}
      {% if buffer[0] %}
      {% if cxx_base == base %}
      {{ buffer[0] }} = {{ base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% else %}
      {{ buffer[0] }} = {{ base }}Cabinet::as<{{ cxx_base }}>({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% endif %}
      {% else %}
      {% if cxx_base == base %}
      {{ base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% else %}
      {{ base }}Cabinet::as<{{ cxx_base }}>({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% endif %}
      {% endif %}
      {% if buffer[1] %}
      {{ buffer[1] }}
      {% endif %}
      return {{ buffer[2] }};
      {% else %}
      {% if cxx_base == base %}
      return {{ base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% else %}
      return {{ base }}Cabinet::as<{{ cxx_base }}>({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
      {% endif %}
      {% endif %}
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-array-getter: |-
  ## CLib array getter template
  // getter: {{ cxx_wraps }}
  try {
      {% if cxx_base == base %}
      ## object can be accessed directly
      auto& obj = {{ base }}Cabinet::at({{ handle }});
      {% else %}
      ## object needs a cast as method is defined for specialization
      auto obj = {{ base }}Cabinet::as<{{ cxx_base }}>({{ handle }});
      {% endif %}
      {% if checks %}
      if ({{ c_args[1] }} < obj->{{ checks[0] }}()) {
          throw ArraySizeError("{{ c_func }}", {{ c_args[1] }}, obj->{{ checks[0] }}());
      }
      {% else %}
      // no size checking specified
      {% endif %}
      {% if buffer and buffer[0] %}
      {{ buffer[0] }} = obj->{{ cxx_name }}({{ cxx_args[0] }});
      {% if buffer[1] %}
      {{ buffer[1] }}
      {% endif %}
      return {{ buffer[2] }};
      {% else %}
      obj->{{ cxx_name }}({{ cxx_args[0] }});
      return 0;
      {% endif %}
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-array-setter: |-
  ## CLib array setter template
  // setter: {{ cxx_wraps }}
  try {
      {% if cxx_base == base %}
      auto& obj = {{ base }}Cabinet::at({{ handle }});
      {% else %}
      auto obj = {{ base }}Cabinet::as<{{ cxx_base }}>({{ handle }});
      {% endif %}
      {% if checks %}
      if ({{ c_args[1] }} != obj->{{ checks[0] }}()) {
          throw ArraySizeError("{{ c_func }}", {{ c_args[1] }}, obj->{{ checks[0] }}());
      }
      {% else %}
      // no size checking specified
      {% endif %}
      obj->{{ cxx_name }}({{ cxx_args[0] }});
      return 0;
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-noop: |-
  // no-op
  return 0;

clib-custom-code: |-
  // {{ what }}: custom code
  try {
      // *************** begin custom code ***************
      {% for line in lines %}
      {{ line }}
      {% endfor %}
      // **************** end custom code ****************
  } catch (...) {
      return handleAllExceptions({{ error[0] }}, {{ error[1] }});
  }

clib-implementation: |-
  {{ declaration }}
  {
      {{ body | indent(4) }}
  }
