@Suppress("FunctionName")
private object Native {
    init {
        val preferredLibrary = "{{ lib_name }}_jni"
        val fallbackLibrary = "{{ lib_name }}"
        val vmName = System.getProperty("java.vm.name").orEmpty()
        val isAndroidRuntime =
            vmName.contains("dalvik", ignoreCase = true) ||
            vmName.contains("art", ignoreCase = true)
        if (isAndroidRuntime) {
            System.loadLibrary(fallbackLibrary)
        } else {
            System.loadLibrary(preferredLibrary)
        }
    }

    @JvmStatic external fun {{ prefix }}_free_string(ptr: Long)
    @JvmStatic external fun {{ prefix }}_last_error_message(): String
{%- for function in functions %}
{%- if function.is_async() %}
    @JvmStatic external fun {{ function.ffi_name }}({% for param in function.params %}{{ param.name }}: {{ param.jni_type }}{% if !loop.last %}, {% endif %}{% endfor %}): Long
    @JvmStatic external fun {{ function.ffi_poll() }}(future: Long, contHandle: Long)
    @JvmStatic external fun {{ function.ffi_complete() }}(future: Long): {{ function.complete_return_jni_type() }}
    @JvmStatic external fun {{ function.ffi_cancel() }}(future: Long)
    @JvmStatic external fun {{ function.ffi_free() }}(future: Long)
{%- else %}
    @JvmStatic external fun {{ function.ffi_name }}({% for param in function.params %}{{ param.name }}: {{ param.jni_type }}{% if !loop.last %}, {% endif %}{% endfor %}): {{ function.return_jni_type }}
{%- endif %}
{%- endfor %}
{%- for function in wire_functions %}
    @JvmStatic external fun {{ function.ffi_name }}({% for param in function.params %}{{ param.name }}: {{ param.jni_type }}{% if !loop.last %}, {% endif %}{% endfor %}): {{ function.return_jni_type }}
{%- endfor %}
{%- for class in classes %}
{%- for ctor in class.ctors %}
    @JvmStatic external fun {{ ctor.ffi_name }}({% for param in ctor.params %}{{ param.name }}: {{ param.jni_type }}{% if !loop.last %}, {% endif %}{% endfor %}): Long
{%- endfor %}
    @JvmStatic external fun {{ class.ffi_free }}(handle: Long)
{%- for method in class.async_methods %}
    @JvmStatic external fun {{ method.ffi_name }}({% if method.include_handle %}handle: Long{% if !method.params.is_empty() %}, {% endif %}{% endif %}{% for param in method.params %}{{ param.name }}: {{ param.jni_type }}{% if !loop.last %}, {% endif %}{% endfor %}): Long
    @JvmStatic external fun {{ method.ffi_poll }}({% if method.include_handle %}handle: Long, {% endif %}future: Long, contHandle: Long)
    @JvmStatic external fun {{ method.ffi_complete }}({% if method.include_handle %}handle: Long, {% endif %}future: Long): {{ method.return_jni_type }}
    @JvmStatic external fun {{ method.ffi_cancel }}({% if method.include_handle %}handle: Long, {% endif %}future: Long)
    @JvmStatic external fun {{ method.ffi_free }}({% if method.include_handle %}handle: Long, {% endif %}future: Long)
{%- endfor %}
{%- for method in class.sync_methods %}
    @JvmStatic external fun {{ method.ffi_name }}({% if method.include_handle %}handle: Long{% if !method.params.is_empty() %}, {% endif %}{% endif %}{% for param in method.params %}{{ param.name }}: {{ param.jni_type }}{% if !loop.last %}, {% endif %}{% endfor %}): {{ method.return_jni_type }}
{%- endfor %}
{%- for stream in class.streams %}
    @JvmStatic external fun {{ stream.subscribe }}(handle: Long): Long
    @JvmStatic external fun {{ stream.poll }}(subscription: Long, contHandle: Long)
    @JvmStatic external fun {{ stream.pop_batch }}(subscription: Long, maxCount: Long): ByteArray?
    @JvmStatic external fun {{ stream.wait }}(subscription: Long, timeout: Int): Int
    @JvmStatic external fun {{ stream.unsubscribe }}(subscription: Long)
    @JvmStatic external fun {{ stream.free }}(subscription: Long)
{%- endfor %}
{%- endfor %}
{%- for invoker in async_callback_invokers %}
    @JvmStatic external fun {{ invoker.name }}(callbackPtr: Long, callbackData: Long{% if invoker.has_result() %}, result: {{ invoker.jni_type() }}{% endif %})
{%- endfor %}
}
