###
#
# PastixFindDependencies: look for libraries Pastix depends on
#
###
include(FortranCInterface)
FortranCInterface_HEADER(common/FCmangle.h
  MACRO_NAMESPACE "FC_"
  SYMBOL_NAMESPACE "FC_")

set(PASTIX_EXTRA_LIBS "")
set(PASTIX_EXTRA_LIBDIRS "")
set(PASTIX_EXTRA_INCDIRS "")

# Check for Thread library
# ------------------------
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
if( THREADS_FOUND )
  list(APPEND PASTIX_EXTRA_LIBS ${CMAKE_THREAD_LIBS_INIT})
endif ()

# Add math library to the list of extra
# it normally exists on all common systems provided with a C compiler
set(M_LIBRARIES "")
if(UNIX OR WIN32)
  find_library(
    M_m_LIBRARY
    NAMES m
    )
  mark_as_advanced(M_m_LIBRARY)
  if (M_m_LIBRARY)
    list(APPEND M_LIBRARIES "${M_m_LIBRARY}")
    list(APPEND PASTIX_EXTRA_LIBS "${M_m_LIBRARY}")
  else()
    message(FATAL_ERROR "Could NOT find libm on your system."
      "Are you sure to have a C compiler installed?")
  endif()
endif()

# Try to find librt (libposix4 - POSIX.1b Realtime Extensions library)
# on Unix systems except Apple ones because it does not exist on it
set(RT_LIBRARIES "")
if(UNIX AND NOT APPLE)
  find_library(
    RT_rt_LIBRARY
    NAMES rt
    )
  mark_as_advanced(RT_rt_LIBRARY)
  if (RT_rt_LIBRARY)
    list(APPEND RT_LIBRARIES "${RT_rt_LIBRARY}")
    list(APPEND PASTIX_EXTRA_LIBS "${RT_rt_LIBRARY}")
  else()
    message(FATAL_ERROR "Could NOT find librt on your system")
  endif()
endif()

# PaStiX depends on BLAS
#-----------------------
find_package(BLASEXT REQUIRED)
if (BLAS_FOUND AND BLAS_LIBRARIES)
  if (PASTIX_BLAS_MT)
    if (BLAS_PAR_LIBRARIES)
      list(APPEND PASTIX_EXTRA_LIBS "${BLAS_PAR_LIBRARIES}")
    else()
      message(FATAL_ERROR "PASTIX_BLAS_MT is set ON but no multithreaded Blas has been found."
      " Consider to turn OFF PASTIX_BLAS_MT or make your multithreaded Blas available in the environment")
    endif()
  else()
    list(APPEND PASTIX_EXTRA_LIBS "${BLAS_LIBRARIES}")
  endif()

  if (BLAS_INCLUDE_DIRS)
    include_directories( ${BLAS_INCLUDE_DIRS} )
    list(APPEND PASTIX_EXTRA_INCDIRS "${BLAS_INCLUDE_DIRS}")
  endif()
  if (BLAS_LIBRARY_DIRS)
    link_directories( ${BLAS_LIBRARY_DIRS} )
    list(APPEND PASTIX_EXTRA_LIBDIRS "${BLAS_LIBRARY_DIRS}")
    list(APPEND CMAKE_INSTALL_RPATH "${BLAS_LIBRARY_DIRS}")
  endif()
  if(BLAS_LINKER_FLAGS AND NOT BLA_STATIC)
    list(APPEND CMAKE_EXE_LINKER_FLAGS "${BLAS_LINKER_FLAGS}")
  endif()
else()
  message(FATAL_ERROR "Blas has not been found.")
endif()

# PaStiX depends on HWLOC
#---------------------------
find_package(HWLOC REQUIRED)
set(HAVE_HWLOC ${HWLOC_FOUND})
if( HWLOC_FOUND )
  # list(APPEND EXTRA_SOURCES src/dague_hwloc.c)
  list(APPEND PASTIX_EXTRA_LIBS ${HWLOC_LIBRARIES})
  if (HWLOC_INCLUDE_DIRS)
    include_directories( ${HWLOC_INCLUDE_DIRS} )
    list(APPEND PASTIX_EXTRA_INCDIRS "${HWLOC_INCLUDE_DIRS}")
  endif()
  if (HWLOC_LIBRARY_DIRS)
    link_directories( ${HWLOC_LIBRARY_DIRS} )
    list(APPEND PASTIX_EXTRA_LIBDIRS "${HWLOC_LIBRARY_DIRS}")
    list(APPEND CMAKE_INSTALL_RPATH "${HWLOC_LIBRARY_DIRS}")
  endif()
  add_definitions("-DWITH_HWLOC")
endif (HWLOC_FOUND)

# PaStiX might depend on MPI
#------------------------------
if (PASTIX_WITH_MPI)
  # Force the detection of the C library
  find_package(MPI REQUIRED)
  set(HAVE_MPI ${MPI_C_FOUND})
  if (MPI_C_FOUND)
    list(APPEND PASTIX_EXTRA_LIBS ${MPI_C_LIBRARIES} )
    if (MPI_C_INCLUDE_PATH)
      include_directories( ${MPI_C_INCLUDE_PATH} )
      list(APPEND PASTIX_EXTRA_INCDIRS "${MPI_C_INCLUDE_PATH}")
    endif()
    if(MPI_C_LINK_FLAGS)
      list(APPEND CMAKE_EXE_LINKER_FLAGS "${MPI_C_LINK_FLAGS}")
    endif()

    # Check to see if support for MPI 2.0 is available
    set(saved_include "${CMAKE_REQUIRED_INCLUDES}" )
    set(saved_libs    "${CMAKE_REQUIRED_LIBRARIES}")
    set(CMAKE_REQUIRED_INCLUDES  "${CMAKE_REQUIRED_INCLUDES};${MPI_C_INCLUDE_PATH}")
    set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};${MPI_C_LIBRARIES}")
    check_function_exists(MPI_Type_create_resized HAVE_MPI_20)
    set(CMAKE_REQUIRED_INCLUDES  "${saved_include}")
    set(CMAKE_REQUIRED_LIBRARIES "${saved_libs}")

  else (MPI_C_FOUND)
    message(FATAL_ERROR "MPI is required but was not found. "
    "Please provide an MPI compiler in your environment or configure with -DPASTIX_WITH_MPI=OFF")
  endif (MPI_C_FOUND)
endif (PASTIX_WITH_MPI)

# PaStiX might depend on CUDA
#----------------------------
if( PASTIX_WITH_STARPU_CUDA )

  find_package(CUDA REQUIRED)

  set(HAVE_CUDA ${CUDA_FOUND})
  if (CUDA_FOUND)
    if(CUDA_VERSION VERSION_LESS "3.0")
      set(CUDA_HOST_COMPILATION_CPP OFF)
    endif(CUDA_VERSION VERSION_LESS "3.0")
    set(CUDA_BUILD_EMULATION OFF)
    include_directories(${CUDA_INCLUDE_DIRS})
    if (CUDA_INCLUDE_DIRS)
      include_directories( ${CUDA_INCLUDE_DIRS} )
      list(APPEND PASTIX_EXTRA_INCDIRS "${CUDA_INCLUDE_DIRS}")
    endif()
    if (CUDA_LIBRARY_DIRS)
      list(APPEND PASTIX_EXTRA_LIBDIRS "${CUDA_LIBRARY_DIRS}")
    endif()
    list(APPEND PASTIX_EXTRA_LIBS ${CUDA_LIBRARIES})
    if (CUDA_CUBLAS_LIBRARIES)
      list(APPEND PASTIX_EXTRA_LIBS ${CUDA_CUBLAS_LIBRARIES})
    endif()
    list(APPEND EXTRA_SOURCES src/gpu_data.c)
    set(saved_include "${CMAKE_REQUIRED_INCLUDES}")
    set(saved_libs "${CMAKE_REQUIRED_LIBRARIES}")
    set(CMAKE_REQUIRED_INCLUDES  "${CMAKE_REQUIRED_INCLUDES};${CUDA_INCLUDE_DIRS}")
    set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};${CUDA_LIBRARIES}")
    if(CUDA_VERSION VERSION_LESS "4.0")
      set(CUDA_HAVE_PEER_DEVICE_MEMORY_ACCESS 0)
    else()
      check_function_exists(cuDeviceCanAccessPeer CUDA_HAVE_PEER_DEVICE_MEMORY_ACCESS)
    endif()
    set(CMAKE_REQUIRED_INCLUDES  "${saved_include}")
    set(CMAKE_REQUIRED_LIBRARIES "${saved_libs}")

    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCUDA_SM_VERSION=20")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCUDA_SM_VERSION=20")
    # nvcc flags
    set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS};-gencode arch=compute_20,code=sm_20;-DCUDA_SM_VERSION=20")

  else(CUDA_FOUND)
    message(FATAL_ERROR "CUDA is required but was not found.\n"
      "Please provide a CUDA library in your environment or configure with -DPASTIX_WITH_STARPU_CUDA=OFF")
  endif (CUDA_FOUND)

endif()

# PaStiX might depend on StarPU
#---------------------------------
if (PASTIX_WITH_STARPU)

  set(PASTIX_STARPU_VERSION "1.1" CACHE STRING "oldest STARPU version desired")

  # Create list of components in order to make a single call to find_package(starpu...)
  set(STARPU_COMPONENT_LIST "HWLOC")
  if(PASTIX_WITH_MPI)
    list(APPEND STARPU_COMPONENT_LIST "MPI")
  endif()
  if(PASTIX_WITH_STARPU_CUDA)
    list(APPEND STARPU_COMPONENT_LIST "CUDA")
  endif()
  if(PASTIX_WITH_FXT)
    list(APPEND STARPU_COMPONENT_LIST "FXT")
  endif()

  find_package(STARPU ${PASTIX_STARPU_VERSION} REQUIRED
    COMPONENTS ${STARPU_COMPONENT_LIST})

  # Add definition and include_dir if found
  if(STARPU_FOUND)
    if (STARPU_INCLUDE_DIRS_DEP)
      include_directories(${STARPU_INCLUDE_DIRS_DEP})
      list(APPEND PASTIX_EXTRA_INCDIRS "${STARPU_INCLUDE_DIRS_DEP}")
    endif()
    if (STARPU_LIBRARY_DIRS_DEP)
      list(APPEND PASTIX_EXTRA_LIBDIRS "${STARPU_LIBRARY_DIRS_DEP}")
    endif()
    list(APPEND PASTIX_EXTRA_LIBS ${STARPU_LIBRARIES_DEP} )
    if(STARPU_LINKER_FLAGS)
      list(APPEND CMAKE_EXE_LINKER_FLAGS "${STARPU_LINKER_FLAGS}")
    endif()
    if(PASTIX_USE_FXT)
      # check if fxt profiling is accessible in starpu and activate it
      set(CMAKE_REQUIRED_INCLUDES "${STARPU_INCLUDE_DIRS}")
      foreach(libdir ${STARPU_LIBRARY_DIRS})
        list(APPEND CMAKE_REQUIRED_FLAGS "-L${libdir}")
      endforeach()
      string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
      set(CMAKE_REQUIRED_LIBRARIES "${STARPU_SHM_LIBRARIES}")
      unset(STARPU_FXT_START_PROFILING_FOUND CACHE)
      check_function_exists(starpu_fxt_start_profiling STARPU_FXT_START_PROFILING_FOUND)
      if ( STARPU_FXT_START_PROFILING_FOUND )
        message(STATUS "Set HAVE_STARPU_FXT_PROFILING - Activate FxT profiling through StarPU")
        add_definitions(-DHAVE_STARPU_FXT_PROFILING)
      endif()
    endif()
    if( STARPU_VERSION_MAJOR EQUAL "1" AND STARPU_VERSION_MINOR GREATER "1")
      add_definitions(-DSTARPU_1_2)
    endif()
  else(STARPU_FOUND)
    message(FATAL_ERROR "StarPU with ${STARPU_COMPONENT_LIST} components is required but was not found.\n"
      "Please provide the StarPU library in your environment or configure with -DPASTIX_WITH_STARPU=OFF")
  endif()

endif (PASTIX_WITH_STARPU)


# Look for ordering/partitioning libraries
set(PASTIX_ORDER_LIBS "")
set(PASTIX_ORDER_LIBDIRS "")

# PaStiX might depend on Scotch/PT-Scotch
#----------------------------------------
if (PASTIX_ORDERING_SCOTCH)
  find_package(SCOTCH REQUIRED)
  if (SCOTCH_FOUND)
    message(STATUS "Scotch include dirs: ${SCOTCH_INCLUDE_DIRS}" )
    include_directories( ${SCOTCH_INCLUDE_DIRS} )
    list(APPEND PASTIX_EXTRA_INCDIRS "${SCOTCH_INCLUDE_DIRS}")
    link_directories( ${SCOTCH_LIBRARY_DIRS} )
    list(APPEND CMAKE_INSTALL_RPATH "${SCOTCH_LIBRARY_DIRS}")
    list(APPEND PASTIX_ORDER_LIBS ${SCOTCH_LIBRARIES} )
    list(APPEND PASTIX_ORDER_LIBDIRS ${SCOTCH_LIBRARY_DIRS} )
  else()
    message(FATAL_ERROR "Scotch is required but was not found.\n"
      "Please provide a Scotch library in your environment or configure with -DPASTIX_ORDERING_SCOTCH=OFF")
  endif()
  if ( (${SCOTCH_INTSIZE} EQUAL "4") AND ${PASTIX_INT64} )
    message(FATAL_ERROR "Scotch was build with 32 bits integer, please deactivate PASTIX_INT64")
  endif()
  if ( (${SCOTCH_INTSIZE} EQUAL "8") AND NOT ${PASTIX_INT64} )
    message(FATAL_ERROR "Scotch was build with 64 bits integer, please activate PASTIX_INT64")
  endif()
endif()

if (PASTIX_ORDERING_PTSCOTCH)
  find_package(PTSCOTCH REQUIRED)
  if (PTSCOTCH_FOUND)
    include_directories( ${PTSCOTCH_INCLUDE_DIRS} )
    list(APPEND PASTIX_EXTRA_INCDIRS "${PTSCOTCH_INCLUDE_DIRS}")
    link_directories( ${PTSCOTCH_LIBRARY_DIRS} )
    list(APPEND CMAKE_INSTALL_RPATH "${PTSCOTCH_LIBRARY_DIRS}")
    list(APPEND PASTIX_ORDER_LIBS ${PTSCOTCH_LIBRARIES_DEP} )
    list(APPEND PASTIX_ORDER_LIBDIRS ${PTSCOTCH_LIBRARY_DIRS_DEP} )
    if (PTSCOTCH_LINKER_FLAGS)
      list(APPEND CMAKE_EXE_LINKER_FLAGS "${PTSCOTCH_LINKER_FLAGS}")
    endif()
  else (PTSCOTCH_FOUND)
    message(FATAL_ERROR "PTSCOTCH is required if PASTIX_ORDERING_PTSCOCTH is on but was not found.\n"
      "Please provide an PtScotch library in your environment or configure with -DPASTIX_ORDERING_PTSCOTCH=OFF")
  endif (PTSCOTCH_FOUND)
  if ( (${PTSCOTCH_INTSIZE} EQUAL "4") AND ${PASTIX_INT64} )
    message(FATAL_ERROR "Scotch was build with 32 bits integer, please deactivate PASTIX_INT64")
  endif()
  if ( (${PTSCOTCH_INTSIZE} EQUAL "8") AND NOT ${PASTIX_INT64} )
    message(FATAL_ERROR "Scotch was build with 64 bits integer, please activate PASTIX_INT64")
  endif()
endif()


# PaStiX might depend on Metis/ParMetis
#--------------------------------------
if (PASTIX_ORDERING_METIS)
  find_package(METIS REQUIRED)
  if (METIS_FOUND)
    include_directories( ${METIS_INCLUDE_DIRS} )
    list(APPEND PASTIX_EXTRA_INCDIRS "${METIS_INCLUDE_DIRS}")
    link_directories( ${METIS_LIBRARY_DIRS} )
    list(APPEND CMAKE_INSTALL_RPATH "${METIS_LIBRARY_DIRS}")
    list(APPEND PASTIX_ORDER_LIBS ${METIS_LIBRARIES} )
    list(APPEND PASTIX_ORDER_LIBDIRS ${METIS_LIBRARY_DIRS} )
  else()
    message(FATAL_ERROR "Metis is required but was not found. "
      "Please provide a Metis library in your environment or configure with -DPASTIX_ORDERING_METIS=OFF")
  endif()
endif()

# prepare linker flags to fill correctly make.inc
list(REMOVE_DUPLICATES CMAKE_EXE_LINKER_FLAGS)
string(REPLACE ";" " " CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
# Fix a problem on Mac OS X when building shared libraries
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
  set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup")
endif()