# CAPABILITY TESTING MACROS
m4_define(
  [M4_HDF5_LIB],
  [
    cat > nptm_test_hdf5.cpp <<EOF
#include <hdf5.h>
int main(int argc, char **argv) {
  hid_t file_id = 0;
  herr_t status = H5Iis_valid(file_id);
  return (int)status;
}
EOF
    $CXX -o nptm_test_hdf5 nptm_test_hdf5.cpp -I$HDF5_INCLUDE -L$HDF5_LIB -lhdf5 > /dev/null 2>>error.log
    export TEST_HDF5_LIB=$?
    rm nptm_test_hdf5.cpp
    if test "x$TEST_HDF5_LIB" = "x0"; then
      rm nptm_test_hdf5
    fi
  ]
)

m4_define(
  [M4_DETECT_LAPACK],
  [
    export -p | grep MKL
    MKL_DEF=$?
    if test "x$MKL_DEF" = "x0"; then
      export LAPACKFLAGS="-DUSE_LAPACK -DUSE_MKL -DLAPACK_ILP64 -DUSE_ILP64 -I{MKLROOT}/include"
      export LAPACKLDFLAGS="-L${MKLROOT}/lib -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl"
    else
      if test -f /usr/include/lapacke.h; then
        export LAPACKFLAGS="-DUSE_LAPACK -DLAPACK_ILP64 -DUSE_ILP64"
	export LAPACKLDFLAGS="-llapacke64"
      fi
    fi
  ]
)

m4_define(
  [M4_DETECT_MAGMA],
  [
    if test -f /usr/local/cuda/include/cuda.h; then
      CUDAFLAGS="-I/usr/local/cuda/include"
      CUDALDFLAGS="-L/usr/local/cuda/lib64 -lcudart"
    elif test -f /usr/include/cuda.h; then
      CUDAFLAGS="-I/usr/include"
      CUDALDFLAGS="-lcudart"
    elif text "x$CUDA_HOME" != "x"; then
      CUDAFLAGS="-I${CUDA_HOME}/include"
      CUDALDFLAGS="-L${CUDA_HOME}/lib64 -lcudart"
    fi
    if test "x$CUDAFLAGS" != "x"; then
      if test -f /usr/include/magma_v2.h; then
        export MAGMAFLAGS="-DUSE_MAGMA -DMAGMA_ILP64 $CUDAFLAGS -I/usr/include"
	export MAGMALDFLAGS="$CUDALDFLAGS -lmagma"
      elif test -f /usr/local/include/magma_v2.h; then
        export MAGMAFLAGS="-DUSE_MAGMA -DMAGMA_ILP64 $CUDAFLAGS -I/usr/local/include"
	export MAGMALDFLAGS="$CUDALDFLAGS -lmagma"
      elif test "x$MAGMA_HOME" != "x"; then
        export MAGMAFLAGS="-DUSE_MAGMA -DMAGMA_ILP64 $CUDAFLAGS -I${MAGMA_HOME}/include"
	export MAGMALDFLAGS="$CUDALDFLAGS -L${MAGMA_HOME}/lib -lmagma"
      fi
    fi
  ]
)

m4_define(
  [M4_TEST_MPI],
  [
    cat > np_test_mpi.cpp <<EOF
#ifndef MPI_VERSION
#include <mpi.h>
#endif
int main(int argc, char** argv) {
  int ierr = MPI_Init(&argc, &argv);
  MPI_Finalize();
  return ierr;
}
EOF
    $CXX -c np_test_mpi.cpp > /dev/null 2>&1
    export CXX_IS_MPI=$?
    rm np_test_mpi.cpp
    if test "x$CXX_IS_MPI" = "x0"; then
      rm np_test_mpi.o
    fi
  ]
)

m4_define(
  [M4_TEST_OFFLOAD],
  [
    cat > np_test_offload.cpp <<EOF
#include <omp.h>
#pragma omp requires unified_shared_memory

#pragma omp begin declare target device_type(any)
void fill_with_ones(int *array) {
#pragma omp target teams distribute parallel for
  for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
      array[[(1000 * i) + j]] = 1;
    }
  }
}
#pragma omp end declare target
int main(int argc, char** argv) {
  int *numbers = new int[[1000000]]();
  fill_with_ones(numbers);
  delete[[]] numbers;
  return 0;
}
EOF
    $CXX -fcf-protection=check -foffload=default -foffload=nvptx-none="-O3 -ggdb -fopt-info -lm -latomic -mgomp" -fopenmp -c np_test_offload.cpp > /dev/null 2>&1
    export CXX_SUPPORTS_OFFLOAD=$?
    rm np_test_offload.cpp
    if test "x$CXX_SUPPORTS_OFFLOAD" = "x0"; then
      rm np_test_offload.o
    fi
  ]
)
# END CAPABILITY TESTING MACROS

# autoconf setup initialization
AC_INIT([np_tmcode],[8.04],[giovanni.lamura@inaf.it])

# Folder structure safety check
AC_CONFIG_SRCDIR([../src/libnptm/TransitionMatrix.cpp])
AC_CONFIG_FILES([Makefile])

# Auxiliary build folder
AC_CONFIG_AUX_DIR([build_aux])

# automake initialization
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])

# Set the default library policy
AC_DISABLE_SHARED
AC_DISABLE_SHARED([])
AC_ENABLE_STATIC
AC_ENABLE_STATIC([])

# Compiler detection
AM_PROG_AR
AC_ARG_ENABLE(
  [mpi],
  [AS_HELP_STRING([--enable-mpi], [enable MPI compilation [default=auto]])],
  [
    if test "x$enableval" = "xno"; then
      if test "x$CXX" = "x"; then
        AC_PROG_CXX([g++ clang++])
      else
        AC_PROG_CXX([$CXX])
      fi
      AC_MSG_NOTICE([Using $CXX])
      AC_SUBST([MPIFLAGS], [""])
    elif test "x$enableval" = "xauto"; then
      if test "x$CXX" = "x"; then
        AC_PROG_CXX([mpicxx.openmpi mpicxx.mpich mpic++.openmpi mpiCC.openmpi])
        if test "x$CXX" != "x"; then
          AC_SUBST([MPIFLAGS], [-DUSE_MPI])
        else
          AC_PROG_CXX([g++ clang++])
          AC_SUBST([MPIFLAGS], [""])
        fi
      else
        # Test if given CXX defines mpi.h
	M4_TEST_MPI
      fi
    elif test "x$enableval" = "xyes"; then
      if test "x$CXX" = "x"; then
        AC_PROG_CXX([mpicxx.openmpi mpicxx.mpich mpic++.openmpi mpiCC.openmpi])
        if test "x$CXX" != "x"; then
          AC_SUBST([MPIFLAGS], [-DUSE_MPI])
        else
          AC_MSG_ERROR([MPI was requested, but no MPI compiler detected!])
        fi
      else
        # Test if given CXX defines mpi.h
	M4_TEST_MPI
	if test "x$CXX_IS_MPI" != "x0"; then
          AC_MSG_ERROR([MPI was requested, but $CXX is not a MPI compiler!])
	fi
      fi
    fi
  ],
  [
    if test "x$CXX" = "x"; then
      AC_PROG_CXX([mpicxx.openmpi mpicxx.mpich mpic++.openmpi mpiCC.openmpi])
      if test "x$CXX" != "x"; then
        AC_SUBST([MPIFLAGS], [-DUSE_MPI])
      else
        AC_PROG_CXX([g++ clang++])
        AC_SUBST([MPIFLAGS], [""])
        AC_MSG_NOTICE([Using $CXX])
      fi
    else
      AC_PROG_CXX([$CXX])
      M4_TEST_MPI
      if test "x$CXX_IS_MPI" = "x0"; then
        AC_SUBST([MPIFLAGS], [-DUSE_MPI])
        AC_SUBST([MPIFLAGS], [""])
      fi
    fi
  ]
)
AC_PROG_CXX([$CXX])
AC_PROG_F77([$F77 gfortran f77])
# Check whether the compiler is clang++ (needs additional flags)
CXX_IS_CLANG=$($CXX --version | grep clang)
AS_IF(
  [test "x$CXX_IS_CLANG" = "x0"],
  [AC_SUBST([CLANGFLAGS], [-stdlib=libstdc++])],
  [AC_SUBST([CLANGFLAGS], [""])]
)

# Libtool initialization
LT_INIT

# Environment setup
AS_IF(
  [test "x$HDF5_INCLUDE" = "x"],
  [AC_SUBST([HDF5_INCLUDE], ["/usr/include/hdf5/serial"])],
  [AC_MSG_NOTICE([HDF5_INCLUDE=$(HDF5_INCLUDE)])]
)
AS_IF(
  [test "x$HDF5_LIB" = "x"],
  [AC_SUBST([HDF5_LIB], ["/usr/lib/x86_64-linux-gnu/hdf5/serial"])],
  [AC_MSG_NOTICE([HDF5_LIB=$(HDF5_LIB)])]
)

# Check for required headers
AC_CHECK_HEADER(
  [$HDF5_INCLUDE/hdf5.h],
  ,
  AC_MSG_ERROR(["Could not find HDF5 headers!]),
)

# Check for required libraries
M4_HDF5_LIB
AS_IF(
  [test "x$TEST_HDF5_LIB" = "x0"],
  [AC_SUBST([HDF5_LDFLAGS], ["-L${HDF5_LIB} -lhdf5"])],
  [AC_MSG_ERROR(["HDF5 library not found!"])]
)

# Configure the optional features
AC_ARG_ENABLE(
  [fortran],
  [AS_HELP_STRING([--enable-fortran], [enable legacy FORTRAN compilation [default=auto]])],
  [
    if test "x$enableval" = "xno"; then
      export BUILDF="false"
      AC_MSG_NOTICE([Disabling FORTRAN compilation])
    elif test "x$enableval" = "xyes"; then
      if test "x$F77" != "x"; then
        export BUILDF="true"
        AC_MSG_NOTICE([Enabling FORTRAN compilation])
      else
        AC_MSG_ERROR([FORTRAN was requested, but no FORTRAN compiler was found!])
      fi
    elif test "x$enableval" = "xauto"; then
      if test "x$F77" != "x"; then
        export BUILDF="true"
        AC_MSG_NOTICE([Enabling FORTRAN compilation])
      else
        export BUILDF="false"
        AC_MSG_NOTICE([Disabling FORTRAN compilation])
      fi
    fi
  ],
  [
    if test "x$F77" != "x"; then
      export BUILDF="true"
      AC_MSG_NOTICE([Enabling FORTRAN compilation])
    else
      export BUILDF="false"
      AC_MSG_NOTICE([Disabling FORTRAN compilation])
    fi
  ]
)
AM_CONDITIONAL([BUILDFORTRAN], [test "x$BUILDF" = "xtrue"])

AC_ARG_ENABLE(
  [offload],
  [AS_HELP_STRING([--enable-offload], [enable target offloading (requires g++ version >= 13) [default=auto]])],
  [
    if test "x$enableval" != "xno"; then
      M4_TEST_OFFLOAD
      if test "x$CXX_SUPPORTS_OFFLOAD" = "x0"; then
        AC_MSG_NOTICE([Enabling offload.])
        AC_SUBST([OFFLOADFLAGS], ["-fcf-protection=check -foffload=default -foffload=nvptx-none=\"-O3 -ggdb -fopt-info -lm -latomic -mgomp\" -fopenmp -DUSE_TARGET_OFFLOAD "])
      else
        AC_MSG_ERROR([Target offload was requested, but it is not supported!])
      fi
    else
      AC_MSG_NOTICE([Disabling offload.])
      AC_SUBST([OFFLOADFLAGS], [""])
    fi
  ],
  [
    M4_TEST_OFFLOAD
    if test "x$CXX_SUPPORTS_OFFLOAD" = "x0"; then
      AC_MSG_NOTICE([Enabling offload.])
      AC_SUBST([OFFLOADFLAGS], ["-fcf-protection=check -foffload=default -foffload=nvptx-none=\"-O3 -ggdb -fopt-info -lm -latomic -mgomp\" -fopenmp -DUSE_TARGET_OFFLOAD "])
    else
      AC_MSG_NOTICE([Disabling offload.])
      AC_SUBST([OFFLOADFLAGS], [""])
    fi
  ]
)

AC_ARG_ENABLE(
  [openmp],
  [AS_HELP_STRING([--enable-openmp], [enable OpneMP multi-threading [default=yes]])],
  [
    if test "x$enableval" != "xno"; then
      AC_SUBST([OMPFLAGS], ["-fopenmp"])
    fi
  ],
  [
    AC_SUBST([OMPFLAGS], ["-fopenmp"])
  ]
)

AC_ARG_ENABLE(
  [optimize],
  [AS_HELP_STRING([--enable-optimize=LEVEL], [use optimization level LEVEL [default=3]])],
  [
    if test "x$enableval" = "x0"; then
      AC_SUBST([OPTFLAGS], ["-O0"])
    elif test "x$enableval" = "x1"; then
      AC_SUBST([OPTFLAGS], ["-O1"])
    elif test "x$enableval" = "x2"; then
      AC_SUBST([OPTFLAGS], ["-O2"])
    elif test "x$enableval" = "x3"; then
      AC_SUBST([OPTFLAGS], ["-O3"])
    else
      AC_MSG_ERROR([Invalid optimization flag!])
    fi
  ],
  [AC_SUBST([OPTFLAGS], ["-O3"])]
)

AC_ARG_WITH(
  [lapack],
  [AS_HELP_STRING([--with-lapack], [use LAPACK @<:@default=auto@:>@])],
  [
    if test "x$withval" = "xno"; then
      AC_SUBST([LAPACKFLAGS], [""])
      AC_SUBST([LAPACKLDFLAGS], [""])
    else
      M4_DETECT_LAPACK
      AS_IF(
        [test "x$LAPACKLDFLAGS" != "x"],
        [AC_MSG_NOTICE([LAPACK detected.])],
        [AC_MSG_NOTICE([No LAPACK found.])]
      )
      AC_SUBST([LAPACKFLAGS], [${LAPACKFLAGS}])
      AC_SUBST([LAPACKLDFLAGS], [${LAPACKLDFLAGS}])
    fi
  ],
  [
    M4_DETECT_LAPACK
    AS_IF(
      [test "x$LAPACKLDFLAGS" != "x"],
      [AC_MSG_NOTICE([LAPACK detected. Activating by default (use --without-lapack to disble).])],
      [AC_MSG_NOTICE([No LAPACK found.])]
    )
    AC_SUBST([LAPACKFLAGS], [${LAPACKFLAGS}])
    AC_SUBST([LAPACKLDFLAGS], [${LAPACKLDFLAGS}])
  ]
)

AC_ARG_WITH(
  [magma],
  [AS_HELP_STRING([--with-magma], [use MAGMA @<:@default=auto@:>@])],
  [
    if test "x$withval" = "xno"; then
      AC_SUBST([MAGMAFLAGS], [""])
      AC_SUBST([MAGMALDFLAGS], [""])
    else
      if test "x$withval" != "xyes" and "x$withval" != "xauto"; then
        export MAGMA_HOME=$withval
      fi
      M4_DETECT_MAGMA
      AS_IF(
        [test "x$MAGMALDFLAGS" != "x"],
        [AC_MSG_NOTICE([MAGMA detected.])],
        [AC_MSG_NOTICE([MAGMA not found.])]
      )
      AC_SUBST([MAGMAFLAGS], [${MAGMAFLAGS}])
      AC_SUBST([MAGMALDFLAGS], [${MAGMALDFLAGS}])
    fi
  ],
  [
    M4_DETECT_MAGMA
    AS_IF(
      [test "x$MAGMALDFLAGS" != "x"],
      [AC_MSG_NOTICE([MAGMA detected. Activating by default (use --without-magma to disable).])],
      [AC_MSG_NOTICE([MAGMA not found.])]
    )
    AC_SUBST([MAGMAFLAGS], [${MAGMAFLAGS}])
    AC_SUBST([MAGMALDFLAGS], [${MAGMALDFLAGS}])
  ]
)

AC_ARG_ENABLE(
  [nvtx],
  [AS_HELP_STRING([--enable-nvtx], [use NVTX profiling @<:@default=no@:>@])],
  [
    if test "x$enableval" = "xyes"; then
      AC_SUBST([NVTXFLAGS], ["-DUSE_NVTX"])
    fi
  ],
  [
    AC_SUBST([NVTXFLAGS], [""])
  ]
)

# Test for additional user configurations
# Test for specific include folders
AC_ARG_WITH(
  [include],
  [AS_HELP_STRING([--with-include], [additional include folders @<:@default=none@:>@])],
  [
    if test "x$with_val" != "x"; then
      AC_SUBST([USER_INCLUDE], [$with_val])
    fi
  ],
  [AC_SUBST([USER_INCLUDE], [""])]
)

# Test for special FORTRAN compiler flags
AC_ARG_WITH(
  [fflags],
  [AS_HELP_STRING([--with-fflags=flags], [FORTRAN compiler flags @<:@default="-std=legacy -O3"@:>@])],
  [
    if test "x$with_val" != "x"; then
      AC_SUBST([FFLAGS], [$with_val])
    fi
  ],
  [
    AC_SUBST([FFLAGS], ["-std=legacy -O3"])
  ]
)

# Test for special linker flags
AC_ARG_WITH(
  [ldflags],
  [AS_HELP_STRING([--with-ldflags=flags], [custom linker flags @<:@default=none@:>@])],
  [
    if test "x$with_val" != "x"; then
      AC_SUBST([USER_LDFLAGS], [$with_val])
    fi
  ],
  [
    AC_SUBST([USER_LDFLAGS], [""])
  ]
)

AS_IF(
  [test "x$OFFLOADFLAGS" != "x"],
  [AC_SUBST([OMPFLAGS], [""])],
  [AC_SUBST([OMPFLAGS], [$OMPFLAGS])]
)
CXXFLAGS="$CLANGFLAGS $OPTFLAGS -ggdb $OFFLOADFLAGS $USER_INCLUDE -I$HDF5_INCLUDE $OMPFLAGS $MPIFLAGS $LAPACKFLAGS $MAGMAFLAGS $NVTXFLAGS"
SUBDIRS="cluster libnptm sphere testing trapping"

# Generate the output
AC_OUTPUT