#
# Copyright (C) 2015-2018 Virgil Security 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:
#
#     (1) Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#
#     (2) 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.
#
#     (3) Neither the name of the copyright holder 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 AUTHOR ''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 AUTHOR 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.
#
# Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
#

#
# This module can be used as part of the build process to add support of AOT compilator in PINVOKE.cs file generated by swig.


if (NOT SRC)
    message (FATAL_ERROR "Source file is not defined. Please define variable SRC.")
endif ()

if (NOT EXISTS ${SRC})
    message (FATAL_ERROR "Given source file does not exists: " ${SRC})
endif ()

file (READ ${SRC} content)

set (mono_callback "[global::ObjCRuntime.MonoPInvokeCallback\(typeof\(")
set (new_line "\\n")

set (dll_import_expr "DllImport\\\(\\\"${CSHARP_MODULE_NAME}\\\"")
set (dll_import_replace "DllImport\(\"__Internal\"")

set (delegate_expr "public delegate ")
set (delegate_replace "[global::ObjCRuntime.MonoNativeFunctionWrapper]${new_line}${delegate_expr}")

set (set_pending_expr "static void SetPending")
set (set_pending_replace "${mono_callback}ExceptionDelegate))]${new_line}${set_pending_expr}")

set (set_pending_argument_expr "static void SetPendingArgument")
set (exception_set_pending_argument_expr "ExceptionDelegate\\\)\\\)].?${set_pending_argument_expr}")
set (exception_set_pending_argument_replace "ExceptionArgumentDelegate\)\)]${new_line}${set_pending_argument_expr}")

set (create_string_expr "static string CreateString")
set (create_string_replace "${mono_callback}SWIGStringDelegate\)\)]${new_line}${create_string_expr}")

set (create_managed_array_expr "static System.IntPtr CreateManaged_byte_Array")
set (create_managed_array_replace "${mono_callback}CreateManaged_byte_ArrayDelegate\)\)]${new_line}${create_managed_array_expr}")

set (get_array_size_expr "static int GetManaged_byte_ArraySize")
set (get_array_size_replace "${mono_callback}GetManaged_byte_ArraySizeDelegate\)\)]${new_line}${get_array_size_expr}")

set (copy_to_unmanaged_expr "static void CopyToUnmanaged_byte_Array")
set (copy_to_unmanaged_replace "${mono_callback}CopyToUnmanaged_byte_ArrayDelegate\)\)]${new_line}${copy_to_unmanaged_expr}")

# replace .DllImport("...." to .DllImport("__Internal" 
string (REGEX REPLACE "${dll_import_expr}" "${dll_import_replace}" modified_content "${content}")

# add annotation [global::ObjCRuntime.MonoNativeFunctionWrapper] for "public delegate" functions
string (REGEX REPLACE "${delegate_expr}" "${delegate_replace}" modified_content "${modified_content}")

# add annotation [global::ObjCRuntime.MonoPInvokeCallback(typeof(ExceptionDelegate))] for static void SetPending.. functions 
string (REGEX REPLACE "${set_pending_expr}" "${set_pending_replace}" modified_content "${modified_content}")

# add annotation [global::ObjCRuntime.MonoPInvokeCallback(typeof(ExceptionArgumentDelegate))] for static void SetPendingArgument.. functions
string (REGEX REPLACE "${exception_set_pending_argument_expr}" "${exception_set_pending_argument_replace}" modified_content "${modified_content}")

# add annotation [ObjCRuntime.MonoPInvokeCallback(typeof(SWIGStringDelegate))] for "static string CreateString("
string (REGEX REPLACE "${create_string_expr}" "${create_string_replace}" modified_content "${modified_content}")

# add annotation [ObjCRuntime.MonoPInvokeCallback(typeof(CreateManaged_byte_ArrayDelegate))] for "static System.IntPtr CreateManaged_byte_Array("
string (REGEX REPLACE "${create_managed_array_expr}" "${create_managed_array_replace}" modified_content "${modified_content}")

# add annotation [ObjCRuntime.MonoPInvokeCallback(typeof(GetManaged_byte_ArraySizeDelegate))] for "static int GetManaged_byte_ArraySize"
string (REGEX REPLACE "${get_array_size_expr}" "${get_array_size_replace}" modified_content "${modified_content}")

# add annotation [ObjCRuntime.MonoPInvokeCallback(typeof(CopyToUnmanaged_byte_ArrayDelegate))] for "static void CopyToUnmanaged_byte_Array("
string (REGEX REPLACE "${copy_to_unmanaged_expr}" "${copy_to_unmanaged_replace}" modified_content "${modified_content}")
 
file (WRITE "${SRC}" "${modified_content}")
