# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.

#.rst:
# FindNetCDF
# ---------
#
# Find the native NetCDF includes and library
#
#  NETCDF_INCLUDE_DIR  - user modifiable choice of where netcdf headers are
#  NETCDF_LIBRARY      - user modifiable choice of where netcdf libraries are
#
# Your package can require certain interfaces to be FOUND by setting these
#
#  NETCDF_CXX         - require the C++ interface and link the C++ library
#  NETCDF_F77         - require the F77 interface and link the fortran library
#  NETCDF_F90         - require the F90 interface and link the fortran library
#
# Or equivalently by calling FindNetCDF with a COMPONENTS argument containing one or
# more of "CXX;F77;F90".
#
# When interfaces are requested the user has access to interface specific hints:
#
#  NETCDF_${LANG}_INCLUDE_DIR - where to search for interface header files
#  NETCDF_${LANG}_LIBRARY     - where to search for interface libraries
#
# This module returns these variables for the rest of the project to use.
#
#  NETCDF_FOUND          - True if NetCDF found including required interfaces (see below)
#  NETCDF_LIBRARIES      - All netcdf related libraries.
#  NETCDF_INCLUDE_DIRS   - All directories to include.
#  NETCDF_HAS_INTERFACES - Whether requested interfaces were found or not.
#  NETCDF_${LANG}_INCLUDE_DIRS/NETCDF_${LANG}_LIBRARIES - C/C++/F70/F90 only interface
#
# Normal usage would be:
#  set (NETCDF_F90 "YES")
#  find_package (NetCDF REQUIRED)
#  target_link_libraries (uses_everthing ${NETCDF_LIBRARIES})
#  target_link_libraries (only_uses_f90 ${NETCDF_F90_LIBRARIES})
#
# It detect NetCDF configurations and set configurations in variable
#
# NETCDF_HAS_NC2
# NETCDF_HAS_NC4
# NETCDF_HAS_HDF4
# NETCDF_HAS_HDF5
# NETCDF_HAS_DAP
# NETCDF_HAS_MEM
#

#search starting from user editable cache var
if (NETCDF_INCLUDE_DIR AND NETCDF_LIBRARY)
    # Already in cache, be silent
    set (NETCDF_FIND_QUIETLY TRUE)
endif ()
find_program(NC_CONFIG NAMES nc-config DOC "NetCDF config command")
mark_as_advanced(NC_CONFIG)

if(NC_CONFIG)
    execute_process(COMMAND ${NC_CONFIG} --includedir
                    RESULT_VARIABLE nc_res
                    OUTPUT_VARIABLE NETCDF_INCLUDE_PATH
                    ERROR_QUIET
                    OUTPUT_STRIP_TRAILING_WHITESPACE)
    execute_process(COMMAND ${NC_CONFIG} --prefix
                    RESULT_VARIABLE nc_res
                    OUTPUT_VARIABLE NETCDF_PREFIX_DIR
                    ERROR_QUIET
                    OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()

find_path(NETCDF_INCLUDE_DIR netcdf.h
          PATHS "${NETCDF_DIR}/include"
          HINTS ${NETCDF_INCLUDE_PATH})

find_library (NETCDF_LIBRARY NAMES netcdf
        PATHS "${NETCDF_DIR}/lib"
              "${NETCDF_INCLUDE_DIR}/../lib"
        HINTS "${NETCDF_PREFIX_DIR}/lib")

if(NETCDF_INCLUDE_DIR AND NETCDF_LIBRARY)
    set (NETCDF_C_INCLUDE_DIRS ${NETCDF_INCLUDE_DIR})
    set (NETCDF_C_LIBRARIES ${NETCDF_LIBRARY})

    find_file(NETCDF_MEM_H
             NAMES "netcdf_mem.h"
             HINTS ${NETCDF_INCLUDE_DIR})
    mark_as_advanced(NETCDF_MEM_H)
    # Ubuntu 16.04 netCDFConfig.cmake declares netCDF_HAS_DISKLESS but doesn't include netcdf_mem.h
    unset(netCDF_HAS_DISKLESS)
    if(NETCDF_MEM_H)
        set(NETCDF_HAS_MEM ON)
    endif()

    function(GET_NC_CONFIG _conf)
        if(_conf STREQUAL "c++")
            set(_key "CXX")
        else()
            string(TOUPPER ${_conf} _key)
        endif()
        execute_process(COMMAND ${NC_CONFIG} --has-${_conf}
                        RESULT_VARIABLE nc_res
                        OUTPUT_VARIABLE nc_has_${_conf}
                        ERROR_QUIET
                        OUTPUT_STRIP_TRAILING_WHITESPACE)
        if(nc_has_${_conf} STREQUAL "yes")
            set(NETCDF_HAS_${_key} ON  PARENT_SCOPE)
        else()
            set(NETCDF_HAS_${_key} OFF PARENT_SCOPE)
        endif()
    endfunction()

    if(NC_CONFIG AND NOT WIN32)
        GET_NC_CONFIG(dap)
        GET_NC_CONFIG(nc2)
        GET_NC_CONFIG(nc4)
        GET_NC_CONFIG(hdf4)
        GET_NC_CONFIG(hdf5)
    else()
        # Detect internal NC4_create symbol as a hint that NC4 support is enabled
        # Fragile...
        function(detect_NC4_create)
            include(CheckCSourceCompiles)
            include(CMakePushCheckState)
            cmake_push_check_state(RESET)
            set(CMAKE_REQUIRED_QUIET "yes")
            set(CMAKE_REQUIRED_LIBRARIES ${NETCDF_LIBRARY})
            check_c_source_compiles("int NC4_create ();int main () {return NC4_create ();}" HAVE_NC4_CREATE)
            cmake_pop_check_state()
        endfunction()

        detect_NC4_create()
        if(HAVE_NC4_CREATE)
            set(NETCDF_HAS_NC4 ON)
        endif()
    endif()

    macro(NetCDF_DETECT_COMPONENT _comp)
        list (FIND NetCDF_FIND_COMPONENTS "${_comp}" _nextcomp)
        if (_nextcomp GREATER -1)
            set (NETCDF_${_comp} 1)
        endif ()
    endmacro()
    NetCDF_DETECT_COMPONENT("CXX")
    NetCDF_DETECT_COMPONENT("F77")
    NetCDF_DETECT_COMPONENT("F90")

    #start finding requested language components
    set (NetCDF_libs "")
    set (NetCDF_includes "${NETCDF_INCLUDE_DIR}")
    get_filename_component (NetCDF_lib_dirs "${NETCDF_LIBRARY}" PATH)
    set (NETCDF_HAS_INTERFACES "YES") # will be set to NO if we're missing any interfaces
    macro (NetCDF_check_interface lang header libs)
        if (NETCDF_${lang})
            #search starting from user modifiable cache var
            find_path (NETCDF_${lang}_INCLUDE_DIR NAMES ${header}
                    HINTS "${NETCDF_INCLUDE_DIR}"
                    HINTS "${NETCDF_${lang}_ROOT}/include"
                    ${USE_DEFAULT_PATHS})

            find_library (NETCDF_${lang}_LIBRARY NAMES ${libs}
                    HINTS "${NetCDF_lib_dirs}"
                    HINTS "${NETCDF_${lang}_ROOT}/lib"
                    ${USE_DEFAULT_PATHS})

            mark_as_advanced (NETCDF_${lang}_INCLUDE_DIR NETCDF_${lang}_LIBRARY)

            #export to internal varS that rest of project can use directly
            set (NETCDF_${lang}_LIBRARIES ${NETCDF_${lang}_LIBRARY})
            set (NETCDF_${lang}_INCLUDE_DIRS ${NETCDF_${lang}_INCLUDE_DIR})

            if (NETCDF_${lang}_INCLUDE_DIR AND NETCDF_${lang}_LIBRARY)
                list (APPEND NetCDF_libs ${NETCDF_${lang}_LIBRARY})
                list (APPEND NetCDF_includes ${NETCDF_${lang}_INCLUDE_DIR})
            else ()
                set (NETCDF_HAS_INTERFACES "NO")
                message (STATUS "Failed to find NetCDF interface for ${lang}")
            endif ()
        endif ()
    endmacro ()

    NetCDF_check_interface (CXX netcdfcpp.h netcdf_c++)
    NetCDF_check_interface (F77 netcdf.inc  netcdff)
    NetCDF_check_interface (F90 netcdf.mod  netcdff)

    #export accumulated results to internal vars that rest of project can depend on
    list (APPEND NetCDF_libs "${NETCDF_C_LIBRARIES}")
    set (NETCDF_LIBRARIES ${NetCDF_libs})
    set (NETCDF_INCLUDE_DIRS ${NetCDF_includes})
endif()
mark_as_advanced(NETCDF_LIBRARY NETCDF_INCLUDE_DIR)

include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (NetCDF
                                   FOUND_VAR NETCDF_FOUND
                                   REQUIRED_VARS NETCDF_LIBRARY NETCDF_INCLUDE_DIR
                                   VERSION_VAR NETCDF_VERSION
                                   )

if(NETCDF_FOUND)
    if(NOT TARGET NETCDF::netCDF)
        add_library(NETCDF::netCDF UNKNOWN IMPORTED)
        set_target_properties(NETCDF::netCDF PROPERTIES
            INTERFACE_INCLUDE_DIRECTORIES "${NETCDF_INCLUDE_DIRS}")
        set_target_properties(NETCDF::netCDF PROPERTIES
            IMPORTED_LINK_INTERFACE_LANGUAGES "C;CXX"
            IMPORTED_LOCATION "${NETCDF_LIBRARIES}")
    endif()
endif()
