#
# Copyright by The HDF Group.
# All rights reserved.
#
# This file is part of HDF5.  The full HDF5 copyright notice, including
# terms governing use, modification, and redistribution, is contained in
# the COPYING file, which can be found at the root of the source code
# distribution tree, or in https://www.hdfgroup.org/licenses.
# If you do not have access to either file, you may request a copy from
# help@hdfgroup.org.
#
#
# This file provides functions for Fortran support.
#
#-------------------------------------------------------------------------------
enable_language (Fortran)
set (HDF_PREFIX "H5")

if (NOT CMAKE_VERSION VERSION_LESS "3.14.0")
  include (CheckFortranSourceRuns)
  include (CheckFortranSourceCompiles)
endif ()

#-------------------------------------------------------------------------------
#  Fix Fortran flags if we are compiling statically on Windows using
#  Windows_MT.cmake from config/cmake/UserMacros
#-------------------------------------------------------------------------------
if (BUILD_STATIC_CRT_LIBS)
  TARGET_STATIC_CRT_FLAGS ()
endif ()

#-----------------------------------------------------------------------------
# Detect name mangling convention used between Fortran and C
#-----------------------------------------------------------------------------
include (FortranCInterface)
FortranCInterface_HEADER (
    ${CMAKE_BINARY_DIR}/FCMangle.h
    MACRO_NAMESPACE "H5_FC_"
    SYMBOL_NAMESPACE "H5_FC_"
)

file (STRINGS ${CMAKE_BINARY_DIR}/FCMangle.h CONTENTS REGEX "H5_FC_GLOBAL\\(.*,.*\\) +(.*)")
string (REGEX MATCH "H5_FC_GLOBAL\\(.*,.*\\) +(.*)" RESULT ${CONTENTS})
set (H5_FC_FUNC "H5_FC_FUNC(name,NAME) ${CMAKE_MATCH_1}")

file (STRINGS ${CMAKE_BINARY_DIR}/FCMangle.h CONTENTS REGEX "H5_FC_GLOBAL_\\(.*,.*\\) +(.*)")
string (REGEX MATCH "H5_FC_GLOBAL_\\(.*,.*\\) +(.*)" RESULT ${CONTENTS})
set (H5_FC_FUNC_ "H5_FC_FUNC_(name,NAME) ${CMAKE_MATCH_1}")

#test code source
set (SIZEOF_CODE
  "
       PROGRAM main
       i = sizeof(x)
       END PROGRAM
  "
)
set (C_SIZEOF_CODE
  "
       PROGRAM main
         USE ISO_C_BINDING
         INTEGER(C_INT) :: a
         INTEGER(C_SIZE_T) :: result
         result = c_sizeof(a)
       END PROGRAM
  "
)
set (STORAGE_SIZE_CODE
  "
       PROGRAM main
         INTEGER :: a
         INTEGER :: result
         result = storage_size(a)
       END PROGRAM
  "
)
set (ISO_FORTRAN_ENV_CODE
  "
       PROGRAM main
         USE, INTRINSIC :: ISO_FORTRAN_ENV
       END PROGRAM
  "
)
set (REALISNOTDOUBLE_CODE
  "
       MODULE type_mod
         INTERFACE h5t
           MODULE PROCEDURE h5t_real
           MODULE PROCEDURE h5t_dble
         END INTERFACE
       CONTAINS
         SUBROUTINE h5t_real(r)
           REAL :: r
         END SUBROUTINE h5t_real
         SUBROUTINE h5t_dble(d)
           DOUBLE PRECISION :: d
         END SUBROUTINE h5t_dble
       END MODULE type_mod
       PROGRAM main
         USE type_mod
         REAL :: r
         DOUBLE PRECISION :: d
         CALL h5t(r)
         CALL h5t(d)
       END PROGRAM main
  "
)
set (ISO_C_BINDING_CODE
  "
       PROGRAM main
            USE iso_c_binding
            IMPLICIT NONE
            TYPE(C_PTR) :: ptr
            TYPE(C_FUNPTR) :: funptr
            INTEGER(C_INT64_T) :: c_int64_type
            CHARACTER(LEN=80, KIND=c_char), TARGET :: ichr
            ptr = C_LOC(ichr(1:1))
       END PROGRAM
  "
)

if (NOT CMAKE_VERSION VERSION_LESS "3.14.0")
  if (HDF5_REQUIRED_LIBRARIES)
    set (CMAKE_REQUIRED_LIBRARIES "${HDF5_REQUIRED_LIBRARIES}")
  endif ()
  check_fortran_source_compiles (${SIZEOF_CODE} ${HDF_PREFIX}_FORTRAN_HAVE_SIZEOF SRC_EXT f90)
  check_fortran_source_compiles (${C_SIZEOF_CODE} ${HDF_PREFIX}_FORTRAN_HAVE_C_SIZEOF SRC_EXT f90)
  check_fortran_source_compiles (${STORAGE_SIZE_CODE} ${HDF_PREFIX}_FORTRAN_HAVE_STORAGE_SIZE SRC_EXT f90)
  check_fortran_source_compiles (${ISO_FORTRAN_ENV_CODE} ${HDF_PREFIX}_HAVE_ISO_FORTRAN_ENV SRC_EXT f90)
  check_fortran_source_compiles (${REALISNOTDOUBLE_CODE} ${HDF_PREFIX}_FORTRAN_DEFAULT_REAL_NOT_DOUBLE SRC_EXT f90)
  check_fortran_source_compiles (${ISO_C_BINDING_CODE} ${HDF_PREFIX}_FORTRAN_HAVE_ISO_C_BINDING SRC_EXT f90)
else ()
  #-----------------------------------------------------------------------------
  # The provided CMake Fortran macros don't provide a general check function
  # so this one is used for a sizeof test.
  #-----------------------------------------------------------------------------
  macro (CHECK_FORTRAN_FEATURE FUNCTION CODE VARIABLE)
      if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.15.0")
        message (VERBOSE "Testing Fortran ${FUNCTION}")
      endif ()
      if (HDF5_REQUIRED_LIBRARIES)
        set (CHECK_FUNCTION_EXISTS_ADD_LIBRARIES
            "-DLINK_LIBRARIES:STRING=${HDF5_REQUIRED_LIBRARIES}")
      else ()
        set (CHECK_FUNCTION_EXISTS_ADD_LIBRARIES)
      endif ()
      file (WRITE
          ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f90
          "${CODE}"
      )
      TRY_COMPILE (RESULT_VAR
          ${CMAKE_BINARY_DIR}
          ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f90
          CMAKE_FLAGS "${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}"
          OUTPUT_VARIABLE OUTPUT
      )

  #    if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.15.0")
  #      message (TRACE "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ")
  #      message (TRACE "Test result ${OUTPUT}")
  #      message (TRACE "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ")
  #    endif ()

      if (${RESULT_VAR})
        set (${VARIABLE} 1 CACHE INTERNAL "Have Fortran function ${FUNCTION}")
        if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.15.0")
          message (VERBOSE "Testing Fortran ${FUNCTION} - OK")
        endif ()
        file (APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
            "Determining if the Fortran ${FUNCTION} exists passed with the following output:\n"
            "${OUTPUT}\n\n"
        )
      else ()
        message (STATUS "Testing Fortran ${FUNCTION} - Fail")
        set (${VARIABLE} 0 CACHE INTERNAL "Have Fortran function ${FUNCTION}")
        file (APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
            "Determining if the Fortran ${FUNCTION} exists failed with the following output:\n"
            "${OUTPUT}\n\n")
      endif ()
  endmacro ()

  #-----------------------------------------------------------------------------
  # Configure Checks which require Fortran compilation must go in here
  # not in the main ConfigureChecks.cmake files, because if the user has
  # no Fortran compiler, problems arise.
  #
  # Be careful with leading spaces here, do not remove them.
  #-----------------------------------------------------------------------------

  # Check for Non-standard extension intrinsic function SIZEOF
  set (${HDF_PREFIX}_FORTRAN_HAVE_SIZEOF FALSE)
  CHECK_FORTRAN_FEATURE(sizeof_code ${SIZEOF_CODE} ${HDF_PREFIX}_FORTRAN_HAVE_SIZEOF)

  # Check for F2008 standard intrinsic function C_SIZEOF
  set (${HDF_PREFIX}_FORTRAN_HAVE_C_SIZEOF FALSE)
  CHECK_FORTRAN_FEATURE(c_sizeof_code ${C_SIZEOF_CODE} ${HDF_PREFIX}_FORTRAN_HAVE_C_SIZEOF)

  # Check for F2008 standard intrinsic function STORAGE_SIZE
  CHECK_FORTRAN_FEATURE(storage_size_code ${STORAGE_SIZE_CODE} ${HDF_PREFIX}_FORTRAN_HAVE_STORAGE_SIZE)

  # Check for F2008 standard intrinsic module "ISO_FORTRAN_ENV"
  set (${HDF_PREFIX}_HAVE_ISO_FORTRAN_ENV FALSE)
  CHECK_FORTRAN_FEATURE(iso_fortran_env_code ${ISO_FORTRAN_ENV_CODE} ${HDF_PREFIX}_HAVE_ISO_FORTRAN_ENV)

  set (${HDF_PREFIX}_FORTRAN_DEFAULT_REAL_NOT_DOUBLE FALSE)
  CHECK_FORTRAN_FEATURE(realisnotdouble_code ${REALISNOTDOUBLE_CODE} ${HDF_PREFIX}_FORTRAN_DEFAULT_REAL_NOT_DOUBLE)

  #-----------------------------------------------------------------------------
  # Checks if the ISO_C_BINDING module meets all the requirements
  #-----------------------------------------------------------------------------
  set (${HDF_PREFIX}_FORTRAN_HAVE_ISO_C_BINDING FALSE)
  CHECK_FORTRAN_FEATURE(iso_c_binding_code ${ISO_C_BINDING_CODE} ${HDF_PREFIX}_FORTRAN_HAVE_ISO_C_BINDING)
endif ()

#-----------------------------------------------------------------------------
# Add debug information (intel Fortran : JB)
#-----------------------------------------------------------------------------
if (CMAKE_Fortran_COMPILER MATCHES ifort)
    if (WIN32 AND NOT MINGW)
        set (CMAKE_Fortran_FLAGS_DEBUG "/debug:full /dbglibs " CACHE STRING "flags" FORCE)
        set (CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "flags" FORCE)
    endif ()
endif ()
