# -*- mode: cmake -*-

set(LIBINT "" CACHE STRING "Libint on/off/prefix")
set_property(CACHE LIBINT PROPERTY STRINGS "" "on" "off") 

# default libint action:
# optional, if new features not needed
# mandatory, if new features are requested
if ("${LIBINT}" STREQUAL "")
  if (NOT MPQC_NEW_FEATURES)
    set(LIBINT "optional")
  else (NOT MPQC_NEW_FEATURES)
    set(LIBINT TRUE)
  endif (NOT MPQC_NEW_FEATURES)
endif("${LIBINT}" STREQUAL "")

# LIBINT == "check0" means LIBINT=TRUE, but use small library for testing
if ("${LIBINT}" STREQUAL "check0")
  set(LIBINT TRUE)
  set(LIBINT_USE_CHECK0 TRUE)
endif ("${LIBINT}" STREQUAL "check0")

if (LIBINT)

  if ("${LIBINT}" OR "${LIBINT}" STREQUAL "optional")
    find_library(LIBINT2_LIBRARY int2)
    find_path(LIBINT2_INCLUDE_DIR libint2.h)
  else()
    find_library(LIBINT2_LIBRARY int2
                 PATHS ${LIBINT}/lib NO_DEFAULT_PATH)
    find_path(LIBINT2_INCLUDE_DIR libint2.h
              PATHS ${LIBINT}/include NO_DEFAULT_PATH)
    if (NOT LIBINT2_LIBRARY)
      message(FATAL_ERROR "Could not find libint library in ${LIBINT}")
    endif()
  endif()

  if (LIBINT2_LIBRARY)
  
    if (NOT LIBINT2_INCLUDE_DIR)
      message(FATAL_ERROR "Could not find libint2.h")
    endif()

    list(APPEND CMAKE_REQUIRED_INCLUDES ${LIBINT2_INCLUDE_DIR})
    list(APPEND CMAKE_REQUIRED_INCLUDES ${EIGEN_INCLUDE_DIR})
    list(APPEND CMAKE_REQUIRED_INCLUDES ${LIBINT2_INCLUDE_DIR}/libint2)
    list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBINT2_LIBRARY})

    # sanity check: try compiling a simple program
    CHECK_CXX_SOURCE_COMPILES(
      "
      #include <libint2.h>
      int main(int argc, char** argv) {
        libint2_static_init();
        return 0;
      }
      "  LIBINT_COMPILES)
    if (NOT LIBINT_COMPILES)
      message(FATAL_ERROR "Could not compile LIBINT test program.\nSee CMakeFiles/CMakeError.log for details")
    endif()
    
    # make sure libint2 version is up to date
    CHECK_CXX_SOURCE_COMPILES(
      "
          #include <libint2.hpp>
          #include <libint2/boys.h>
          #if !(LIBINT_MAJOR_VERSION==2 && LIBINT_MINOR_VERSION==1 && LIBINT_MICRO_VERSION>=0)
          # error \"Libint2 library is too old\"
          #endif
          int main(int argc, char** argv) {
            libint2::GaussianGmEvalScratch<double,-1> scr;
            scr.init(5);
            // FmEval_Chebyshev3 converted to template in 30ea3cd4474c740bee7713bbc633d60f95b3a4c2
            libint2::FmEval_Chebyshev3<double> cheb_boys_eval(12,1e-15);
            // libint2::finalize defined in 06be4d68a7b0da073469c40ccf49acb9ed62a18e
            libint2::finalize();
            return 0;
          }
      "  LIBINT_IS_UP_TO_DATE)    
    if (NOT LIBINT_IS_UP_TO_DATE)
      message(FATAL_ERROR "Libint library is too old: a recent beta of 2.1.0 is required")
    endif()
    
    # check that libint2 uses one of orderings supported by MPQC
    CHECK_CXX_SOURCE_COMPILES(
      "
        #include <libint2.h>
        #if LIBINT2_CGSHELL_ORDERING != LIBINT2_CGSHELL_ORDERING_STANDARD && LIBINT2_CGSHELL_ORDERING != LIBINT2_CGSHELL_ORDERING_INTV3 && LIBINT2_CGSHELL_ORDERING != LIBINT2_CGSHELL_ORDERING_GAMESS
        # error \"Libint2 library is uses an Cartesian Gaussian ordering not supported by MPQC, or it is simply too old\"
        #endif
        int main(int argc, char** argv) { return 0; }
      "  LIBINT_USES_SUPPORTED_CARTGAUSS_ORDERING)    
    if (NOT LIBINT_USES_SUPPORTED_CARTGAUSS_ORDERING)
      message(FATAL_ERROR "Libint2 library is uses an Cartesian Gaussian ordering not supported by MPQC, or it's simply too old")
    endif()
    
    set(LIBINT2_FOUND TRUE)

    # check if libint2 supports [g12,T] commutator integrals
    CHECK_CXX_SOURCE_COMPILES(
      "
        #include <libint2.h>
        #if LIBINT2_SUPPORT_G12 && LIBINT2_SUPPORT_T1G12
          void libint2_support_t1g12() {}
        #endif
        int main(int argc, char** argv) { libint2_support_t1g12(); return 0; }
      "  LIBINT_SUPPORTS_G12_T1G12_INTEGRALS
    )
    
    message(STATUS "Found Libint2:")
    message(STATUS "\tLIBINT2_LIBRARY=${LIBINT2_LIBRARY}")
    message(STATUS "\tLIBINT2_INCLUDE_DIR=${LIBINT2_INCLUDE_DIR}")
    set(HAVE_LIBINT2 TRUE)
  endif()

endif()

if ("${LIBINT}" AND NOT LIBINT2_FOUND)

  if (MPQC_EXPERT)

    message("** Downloading and building Libint2 is explicitly disabled in EXPERT mode")

  else()

    set(EXTERNAL_SOURCE_DIR ${PROJECT_SOURCE_DIR}/external)
    set(EXTERNAL_BUILD_DIR ${PROJECT_BINARY_DIR}/external/build)

    include(ExternalProject)

    if (LIBINT_USE_CHECK0)
      set(LIBINT_URL ${EXTERNAL_SOURCE_DIR}/libint-2.1.0-beta.check0.tgz)
      set(LIBINT_URL_HASH MD5=1b27d78487d6f6612943449ec9361754)
    else (LIBINT_USE_CHECK0)
      set(LIBINT_URL ${EXTERNAL_SOURCE_DIR}/libint-2.1.0-beta.tgz)
      set(LIBINT_URL_HASH MD5=e0a28af51744e7abac0e07f4af3cfb20)
    endif (LIBINT_USE_CHECK0)
    
    if (NOT EXISTS ${LIBINT_URL})
      message(FATAL_ERROR "Did not find embedded copy of Libint2, something wrong with your source tree")
    endif (NOT EXISTS ${LIBINT_URL})

    message("** Will build Libint from ${LIBINT_URL}")

    if (BUILD_SHARED_LIBS)
      set(LIBINT_BUILD_TYPE --enable-shared --disable-static)
      set(LIBINT_LIBRARY_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
    else (BUILD_SHARED_LIBS)
      set(LIBINT_BUILD_TYPE --disable-shared --enable-static)
      set(LIBINT_LIBRARY_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX})
    endif (BUILD_SHARED_LIBS)
    ExternalProject_Add(
      libint
      PREFIX ${EXTERNAL_BUILD_DIR}/libint
      URL ${LIBINT_URL}
      URL_HASH ${LIBINT_URL_HASH}
      BUILD_IN_SOURCE 1
      CONFIGURE_COMMAND /bin/bash ./configure
      --prefix=${EXTERNAL_BUILD_DIR}/libint
      "${LIBINT_BUILD_TYPE}"
      CC=${CMAKE_C_COMPILER}
      "CFLAGS=${CMAKE_C_FLAGS}"
      CXX=${CMAKE_CXX_COMPILER}
      "CXXFLAGS=${CMAKE_CXX_FLAGS}"
      BUILD_COMMAND $(MAKE) SHELL=/bin/bash
      INSTALL_COMMAND make install SHELL=/bin/bash
      )

    add_dependencies(External libint)
    set(LIBINT2_LIBRARY ${EXTERNAL_BUILD_DIR}/libint/lib/libint2${LIBINT_LIBRARY_SUFFIX})
    set(LIBINT2_INCLUDE_DIR ${EXTERNAL_BUILD_DIR}/libint/include)
    set(HAVE_LIBINT2 TRUE)

  endif()

endif()

if (HAVE_LIBINT2)
  include_directories(${LIBINT2_INCLUDE_DIR})
  include_directories(${LIBINT2_INCLUDE_DIR}/libint2)
else()
  message("** Libint2 was not found")
  set(LIBINT2_LIBRARY "")
endif()

