# As Matlab support is highly experimental for now in swig, we split the binding generation in two phases:
#
#  * Generation of the .cxx code, left to the author of the library that needs to have a recent (non-standard) swig.
#  * Compilation of the .cxx, that is left to the user that compiles the library.

# Options related to installation directories
#
# If you want to install bindings for packaging you may need to install
# following several rules (for example placing the .m files in share
# and the compiled libraries in some architecture-specific directory)
# We support this use-cases by exposing this CMake advanced option.
# The default values, however, are choosen to simplify the use of
# the bindings for a developer that compiled the library from source:
# to use the octave bindings just add <prefix>/octave to the octave path,
# to use the matlab bindings just add <prefix>/mex    to the matlab path.
set(IDYNTREE_INSTALL_MATLAB_LIBDIR "mex" CACHE
    STRING "Location (relative to the install prefix) in which the Matlab mex libraries are installed.")
set(IDYNTREE_INSTALL_MATLAB_MFILESDIR "mex" CACHE
    STRING "Location (relative to the install prefix) in which the Matlab .m files are installed.")
set(IDYNTREE_INSTALL_OCTAVE_LIBDIR "octave" CACHE
    STRING "Location (relative to the install prefix) in which the Octave mex libraries are installed.")
set(IDYNTREE_INSTALL_OCTAVE_MFILESDIR "octave" CACHE
    STRING "Location (relative to the install prefix) in which the Octave .m files are installed.")

# Mark the cached options as advanced
mark_as_advanced(IDYNTREE_INSTALL_MATLAB_LIBDIR)
mark_as_advanced(IDYNTREE_INSTALL_MATLAB_MFILESDIR)
mark_as_advanced(IDYNTREE_INSTALL_OCTAVE_LIBDIR)
mark_as_advanced(IDYNTREE_INSTALL_OCTAVE_MFILESDIR)

# The name of the generated source named is
# defined by the variable swig_generated_file_fullname
# in the SWIG_ADD_SOURCE_TO_MODULE macro in UseSWIG.cmake
set(sourcename iDynTreeMATLAB_wrap)

# The name of the generated source should instead match the one
# used by SWIG when generating the .m file.
# See https://github.com/jaeandersson/swig/issues/44 for more details
set(mexname iDynTreeMEX)

# Directory in which the bindings are generated
set(MEX_BINDINGS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/autogenerated)

# Directory containing the high-level-matlab-wrappers and its parent directory
set(HIGH_LEVEL_WRAPPERS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/+iDynTreeWrappers)
set(MATLAB_WRAPPERS_BINDINGS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})

# use previously generated files
set(swig_generated_sources ${MEX_BINDINGS_SOURCE_DIR}/${sourcename}.cxx)
set(swig_other_sources)

# Set the .i files to generate the bindings
set(iDynTree_SWIG_I_FILE ../iDynTree.i)
set(iDynTree_SWIG_I_OTHER
    ../ignore.i
    ../joints.i
    ../sensors.i
    matlab.i
    matlab_mat4x4vec.i
    matlab_matvec.i
    matlab_spatialvec.i)

# Generate SWIG wrapper
macro(GET_LIBRARY_FROM_SWIG_WRAPPER i_main_file i_other_files target_name generate outputdir)

  set_property(SOURCE ${i_main_file} PROPERTY CPLUSPLUS ON)
  set(CMAKE_SWIG_OUTDIR ${outputdir})

  if(${generate} AND NOT bindings_have_been_generated)
    find_package(SWIG)
    set(bindings_have_been_generated TRUE)
    swig_add_library(${target_name} LANGUAGE matlab SOURCES ${i_main_file})
    # Add the dependency to other .i files
    set_property(
        TARGET ${target_name}
        PROPERTY SWIG_DEPENDS ${i_other_files})
  else()
      if(${target_name} STREQUAL "iDynTreeMEX") 
          matlab_add_mex(NAME ${target_name} SRC ${swig_generated_sources})
      else()
          add_library(${target_name} MODULE ${swig_generated_sources})
      endif()
      set_target_properties(${target_name} PROPERTIES DEBUG_POSTFIX "")
      set_source_files_properties(${swig_generated_sources} PROPERTIES GENERATED 1)
  endif()

endmacro()

# ==============
# COMPILE MATLAB
# ==============

if(IDYNTREE_USES_MATLAB)
  find_package(Matlab REQUIRED)

  set(target_name ${mexname})

  get_library_from_swig_wrapper(
          ${iDynTree_SWIG_I_FILE}
          "${iDynTree_SWIG_I_OTHER}"
          ${target_name}
          ${IDYNTREE_GENERATE_MATLAB}
          ${MEX_BINDINGS_SOURCE_DIR})

  set_target_properties(${target_name}
    PROPERTIES OUTPUT_NAME ${mexname}
               PREFIX ""
               SUFFIX .mex)

  target_link_libraries(${target_name} ${IDYNTREE_LIBRARIES} idyntree-core ${Matlab_LIBRARIES})
  target_include_directories(${target_name} PUBLIC ${Matlab_INCLUDE_DIRS})
  set_target_properties(${target_name} PROPERTIES PREFIX "" SUFFIX .${Matlab_MEX_EXTENSION})

  # entry point in the mex file + taking care of visibility and symbol clashes.
  if(WIN32)
    set_target_properties(${target_name}
        PROPERTIES
        DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)")
  endif()

  # Install the generated front-end to ${CMAKE_INSTALL_PREFIX}/mex
  install(
      DIRECTORY ${MEX_BINDINGS_SOURCE_DIR}/+iDynTree
      DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR})
  install(
      FILES
      ${MEX_BINDINGS_SOURCE_DIR}/SwigGet.m
      ${MEX_BINDINGS_SOURCE_DIR}/SwigRef.m
      ${MEX_BINDINGS_SOURCE_DIR}/SwigMem.m
      DESTINATION
      ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR})
  install(
      TARGETS ${target_name}
      DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_LIBDIR})

  # Install the high-level-matlab-wrappers
  install(
      DIRECTORY ${HIGH_LEVEL_WRAPPERS_SOURCE_DIR}
      DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR})

  # Install the matlab-visualization-external-functions
  install(
      FILES ${IDYNTREE_INTERNAL_MESH2TRI_PATH}/mesh2tri.m
      DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR})

endif()

# ==============
# COMPILE OCTAVE
# ==============

if(IDYNTREE_USES_OCTAVE)
  find_package(Octave 4.0 REQUIRED)

  set(target_name idyntreeOctaveMex)

  # Get the target
  get_library_from_swig_wrapper(
          ${iDynTree_SWIG_I_FILE}
          "${iDynTree_SWIG_I_OTHER}"
          ${target_name}
          ${IDYNTREE_GENERATE_MATLAB}
          ${MEX_BINDINGS_SOURCE_DIR})

  target_include_directories(${target_name} PUBLIC ${OCTAVE_INCLUDE_DIRS})

  if(APPLE)
    target_link_libraries(${target_name} ${iDynTree_LIBRARIES})
    set_target_properties(${target_name} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
  else()
    target_link_libraries(${target_name} ${OCTAVE_LIBRARIES} ${iDynTree_LIBRARIES})
  endif()

  set_target_properties(${target_name}
    PROPERTIES OUTPUT_NAME ${mexname}
               PREFIX ""
               SUFFIX .mex)

  # Install the target
  install(
      TARGETS ${target_name}
      DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_LIBDIR})

  # Install the generated front-end to ${CMAKE_INSTALL_PREFIX}/octave
  install(
      DIRECTORY ${MEX_BINDINGS_SOURCE_DIR}/+iDynTree
      DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_MFILESDIR})
  install(
      FILES
      ${MEX_BINDINGS_SOURCE_DIR}/SwigGet.m
      ${MEX_BINDINGS_SOURCE_DIR}/SwigRef.m
      ${MEX_BINDINGS_SOURCE_DIR}/SwigMem.m
      DESTINATION
      ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_MFILESDIR})

  # Install the high-level-matlab-wrappers
  install(
      DIRECTORY ${HIGH_LEVEL_WRAPPERS_SOURCE_DIR}
      DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR})
endif()

# if compile tests compile also matlab/octave tests
if(IDYNTREE_COMPILE_TESTS)
    add_subdirectory(tests)
endif()
