#------------------------------------------------------------------------------
# CMake config file for Reduze package
# subdir 'reduze'
#------------------------------------------------------------------------------


#------------------------------------------------------------------------------
# options
#------------------------------------------------------------------------------
option (USE_MPI        "Build with MPI support"         OFF)
option (USE_DATABASE   "Build with Berkeley DB support" OFF)
option (USE_FERMAT     "Build with Fermat support"      ON)
option (USE_HASH_TABLE "Build with hash table support (experimental)"  OFF)
option (USE_NEW_REDUZE_STYLE_FILE "Build for new reduze.sty file"  OFF)
option (DEBUG          "Enable many debugging messages and internal checks"  OFF)

#------------------------------------------------------------------------------
# default flags
#------------------------------------------------------------------------------

add_definitions (-DPACKAGE_NAME="${PROJECT_NAME}")
add_definitions (-DPACKAGE_VERSION="${CPACK_PACKAGE_VERSION}")
add_definitions (-DUSE_OLD_SHIFTS)
add_definitions("-Wall -Wno-long-long -pedantic")
# suppress auto_ptr deprecation warnings due to yaml-cpp
add_definitions("-Wno-deprecated-declarations")

#------------------------------------------------------------------------------
# external libraries
#------------------------------------------------------------------------------

### misc
include (FindPkgConfig)
include (CheckIncludeFileCXX)
#include (CheckIncludeFiles)
#check_include_files(someheader.h HAVE_SOMEHEADER)

### hash table
if (USE_HASH_TABLE)
  check_include_file_cxx ("tr1/unordered_map" HAVE_TR1_UNORDERED_MAP)
  check_include_file_cxx ("tr1/unordered_set" HAVE_TR1_UNORDERED_SET)
  if (NOT (HAVE_TR1_UNORDERED_MAP AND HAVE_TR1_UNORDERED_SET))
    message (FATAL_ERROR "Couldn't find header files for hash table support: Try again with the option -DUSE_HASH_TABLE=OFF")
  endif (NOT (HAVE_TR1_UNORDERED_MAP AND HAVE_TR1_UNORDERED_SET))
  add_definitions (-DUSE_HASH_TABLE)
endif (USE_HASH_TABLE)

### new reduze style file
if (USE_NEW_REDUZE_STYLE_FILE)
  add_definitions (-DHAVE_NEW_REDUZE_STYLE_FILE)
endif (USE_NEW_REDUZE_STYLE_FILE)

### DEBUG
if (DEBUG)
  add_definitions (-DDEBUG)
  add_definitions (-ggdb)
else (DEBUG)
  add_definitions (-O2)
endif (DEBUG)

### MPI
if (USE_MPI)
	message (STATUS "MPI build required")
	find_package (MPI)
	if (NOT MPI_FOUND)
		message (FATAL_ERROR "Failed to find MPI environment"
		    	 " (use -DUSE_MPI=OFF if you really want to build without MPI).")
	endif (NOT MPI_FOUND)
	if (NOT MPIEXEC)
		message (FATAL_ERROR "Failed to find an MPI binary"
				" (install e.g. \"openmpi-bin\" or"
				" use -DUSE_MPI=OFF if you really want to build without MPI).")
	endif (NOT MPIEXEC)
	message (STATUS "  found MPI binary ${MPIEXEC}")
	add_definitions (-DHAVE_MPI)
	include_directories (${MPI_INCLUDE_PATH})
    set (REDUZE_LIBRARIES       ${REDUZE_LIBRARIES} ${MPI_LIBRARIES})
	set (CMAKE_CXX_FLAGS        "${CMAKE_CXX_FLAGS} ${MPI_COMPILE_FLAGS}")
	set (CMAKE_EXE_LINKER_FLAGS "${MPI_LINK_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}")
else (USE_MPI)
	message (STATUS "Non-MPI build required")
endif (USE_MPI)

### Berkeley DB
if (USE_DATABASE)
	message (STATUS "Building with Berkeley DB support")
	find_path(DB_INCLUDE_PATH NAMES dbstl_common.h
	          PATHS /usr/local/include/db4 /usr/local/include
	                /usr/include/db4 /usr/include)
    # we also need db.h but just assume its in the same directory
	find_library(DB_LIBRARY NAMES db_stl
	             PATHS /usr/lib /usr/local/lib)
	if (NOT (DB_LIBRARY AND DB_INCLUDE_PATH))
		message (FATAL_ERROR "Failed to find Berkeley DB or its STL interface"
		    	 " (use -DUSE_DATABASE=OFF if you want to build without database).")
	endif (NOT (DB_LIBRARY AND DB_INCLUDE_PATH))
	add_definitions (-DHAVE_DATABASE)
    message (STATUS "  found DB headers in: ${DB_INCLUDE_PATH}") 
    message (STATUS "  found DB library: ${DB_LIBRARY}") 
	include_directories (${DB_INCLUDE_PATH})
    set (REDUZE_LIBRARIES ${REDUZE_LIBRARIES} ${DB_LIBRARY})
else (USE_DATABASE)
	message (STATUS "Building without Berkeley DB support")
endif (USE_DATABASE)

### Fermat
if (USE_FERMAT)
   message (STATUS "Building with Fermat support")
   add_definitions (-DHAVE_FERMAT)
else (USE_FERMAT)
   message (STATUS "Building without Fermat support")
endif (USE_FERMAT)

### GiNaC
function(_ginac_headers_version _out_major _out_minor _out_patch _version_h)
	file(STRINGS ${_version_h} _ginac_vinfo REGEX "^#define[\t ]+GINACLIB_.*_VERSION.*")
	if (NOT _ginac_vinfo)
		message(FATAL_ERROR "include file ${_version_h} does not exist")
	endif()
	string(REGEX REPLACE "^.*GINACLIB_MAJOR_VERSION[ \t]+([0-9]+).*" "\\1" ${_out_major} "${_ginac_vinfo}")
	string(REGEX REPLACE "^.*GINACLIB_MINOR_VERSION[ \t]+([0-9]+).*" "\\1" ${_out_minor} "${_ginac_vinfo}")
	string(REGEX REPLACE "^.*GINACLIB_MICRO_VERSION[ \t]+([0-9]+).*" "\\1" ${_out_patch} "${_ginac_vinfo}")
	if (NOT ${_out_major} MATCHES "[0-9]+")
		message(FATAL_ERROR "failed to determine GINACLIB_MAJOR_VERSION, "
			            "expected a number, got ${${_out_major}}")
	endif()
	if (NOT ${_out_minor} MATCHES "[0-9]+")
		message(FATAL_ERROR "failed to determine GINACLIB_MINOR_VERSION, "
			            "expected a number, got ${${_out_minor}}")
	endif()
	if (NOT ${_out_patch} MATCHES "[0-9]+")
		message(FATAL_ERROR "failed to determine GINACLIB_MINOR_VERSION, "
			            "expected a number, got ${${_out_patch}}")
	endif()
	set(${_out_major} ${${_out_major}} PARENT_SCOPE)
	set(${_out_minor} ${${_out_minor}} PARENT_SCOPE)
	set(${_out_patch} ${${_out_patch}} PARENT_SCOPE)
endfunction()
#
message (STATUS "Searching for GiNaC and CLN")
find_path(GINAC_INCLUDE_PATH NAMES ginac/ginac.h PATHS /usr/include /usr/local/include)
find_path(CLN_INCLUDE_PATH   NAMES cln/cln.h     PATHS /usr/include /usr/local/include)
find_library(GINAC_LIBRARIES NAMES ginac PATHS /usr/lib /usr/local/lib)
find_library(CLN_LIBRARIES   NAMES cln   PATHS /usr/lib /usr/local/lib)
if (GINAC_INCLUDE_PATH AND GINAC_LIBRARIES AND CLN_INCLUDE_PATH AND CLN_LIBRARIES)
    message (STATUS "  found GiNaC headers in: ${GINAC_INCLUDE_PATH}")
    message (STATUS "  found GiNaC library: ${GINAC_LIBRARIES}")
    message (STATUS "  found CLN headers in: ${CLN_INCLUDE_PATH}")
    message (STATUS "  found CLN library: ${CLN_LIBRARIES}")
    include_directories (${GINAC_INCLUDE_PATH})
    include_directories (${CLN_INCLUDE_PATH})
    set (REDUZE_LIBRARIES ${REDUZE_LIBRARIES} ${GINAC_LIBRARIES})
    set (REDUZE_LIBRARIES ${REDUZE_LIBRARIES} ${CLN_LIBRARIES})
else (GINAC_INCLUDE_PATH AND GINAC_LIBRARIES AND CLN_INCLUDE_PATH AND CLN_LIBRARIES)
    message (STATUS "  not found in direct search, checking via pkg-config now")
    pkg_check_modules (GINAC ginac>=1.5.0)
    if (NOT GINAC_FOUND)
      # pkg-config might only fail because of dependencies, inform user about it
      message (FATAL_ERROR "Failed to find GiNaC or its dependencies (e.g. CLN)") 
    endif (NOT GINAC_FOUND)
    message (STATUS "  found compiler flags for GiNaC: ${GINAC_INCLUDE_DIRS}")
    message (STATUS "  found linker flags for GiNaC: ${GINAC_LDFLAGS}")
    include_directories (${GINAC_INCLUDE_DIRS})
    set (REDUZE_LIBRARIES ${REDUZE_LIBRARIES} ${GINAC_LDFLAGS})
endif (GINAC_INCLUDE_PATH AND GINAC_LIBRARIES AND CLN_INCLUDE_PATH AND CLN_LIBRARIES)

# fix compilation for GiNaC 1.7.1:
file (STRINGS "${GINAC_INCLUDE_PATH}/ginac/version.h" GINAC_VERSIONS REGEX "^#define[\t ]+GINACLIB_.*_VERSION.*")
if (NOT GINAC_VERSIONS)
  message (FATAL_ERROR "  version file ${GINAC_INCLUDE_PATH}/ginac/version.h" not found)
endif (NOT GINAC_VERSIONS)
string(REGEX REPLACE "^.*GINACLIB_MAJOR_VERSION[ \t]+([0-9]+).*" "\\1" GINAC_VERSION_MAJOR "${GINAC_VERSIONS}")
string(REGEX REPLACE "^.*GINACLIB_MINOR_VERSION[ \t]+([0-9]+).*" "\\1" GINAC_VERSION_MINOR "${GINAC_VERSIONS}")
string(REGEX REPLACE "^.*GINACLIB_MICRO_VERSION[ \t]+([0-9]+).*" "\\1" GINAC_VERSION_PATCH "${GINAC_VERSIONS}")
set (GINAC_VERSION "${GINAC_VERSION_MAJOR}.${GINAC_VERSION_MINOR}.${GINAC_VERSION_PATCH}")
message (STATUS "  detected GiNaC version: ${GINAC_VERSION}")
if (GINAC_VERSION VERSION_GREATER 1.7 OR GINAC_VERSION VERSION_EQUAL 1.7)
	message (STATUS "  found GiNaC >= 1.7, forcing C++11 compilation")
	add_definitions("-std=c++11")
    add_definitions(-DNEW_GINAC)
    add_definitions(-Wno-undefined-var-template)
    add_definitions(-Wno-unused-local-typedef)
endif()


#------------------------------------------------------------------------------
# target reduze
#------------------------------------------------------------------------------

# note: we include the header files to generate proper XCode project files
file (GLOB REDUZE_SOURCES *.cpp *.h)

configure_file ("${CMAKE_SOURCE_DIR}/reduze/gittag.cpp.in" "${CMAKE_BINARY_DIR}/reduze/gittag.cpp" @ONLY)
list (APPEND REDUZE_SOURCES "${CMAKE_BINARY_DIR}/reduze/gittag.cpp" gittag.h)

add_executable        (reduze ${REDUZE_SOURCES})
target_link_libraries (reduze ${REDUZE_LIBRARIES})
target_link_libraries (reduze yaml-cpp)

#------------------------------------------------------------------------------
# installation
#------------------------------------------------------------------------------

install (TARGETS reduze DESTINATION bin)

