cmake_minimum_required (VERSION 3.24)

project (Tapkee  LANGUAGES CXX)

# set paths
set (CMAKE_CXX_STANDARD 20)
set (TAPKEE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
set (TAPKEE_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
set (TAPKEE_TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/test/unit")
set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/cmake")

set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")

# Eigen3 detection
find_package(Eigen3 3.3 REQUIRED NO_MODULE)
set (EIGEN3_LIBRARY_TO_LINK "Eigen3::Eigen")

# fmt
find_package(fmt REQUIRED)
set (FMT_LIBRARY_TO_LINK "fmt::fmt-header-only")

# ARPACK detection
find_package(Arpack)
if (ARPACK_FOUND)
	link_directories("${ARPACK_PATH}")
endif()

# OpenMP detection
find_package(OpenMP)
if (OPENMP_FOUND)
	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

# ViennaCL detection
find_package(OpenCL)
if (OPENCL_FOUND)
	find_package(ViennaCL)
	if (VIENNACL_FOUND)
		set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPENCL_C_FLAGS}")
		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENCL_CXX_FLAGS}")
		set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OPENCL_EXE_LINKER_FLAGS}")
		include_directories("${VIENNACL_INCLUDE_DIRS}")
	endif()
endif()

include_directories("${TAPKEE_INCLUDE_DIR}")
# CLI executable
add_executable(tapkee "${TAPKEE_SRC_DIR}/cli/main.cpp")
# Examples
option(BUILD_EXAMPLES "Whether to build examples or not" OFF)
if (BUILD_EXAMPLES)
	add_subdirectory(examples)
endif()

option(USE_SLASH_CLI_WINDOWS "Whether to use slash command line parameters" OFF)

# library interface
file(GLOB_RECURSE headers_library "${TAPKEE_INCLUDE_DIR}/*.hpp")
add_library(tapkee_library INTERFACE)
target_include_directories(tapkee_library INTERFACE "${TAPKEE_INCLUDE_DIR}")

if (ARPACK_FOUND)
	target_link_libraries(tapkee PUBLIC arpack)
	target_link_libraries(tapkee_library INTERFACE arpack)
	add_definitions(-DTAPKEE_WITH_ARPACK)
endif()

if (VIENNACL_FOUND)
	target_link_libraries(tapkee PUBLIC OpenCL)
	target_link_libraries(tapkee_library INTERFACE OpenCL)
	add_definitions(-DTAPKEE_WITH_VIENNACL)
endif()

target_link_libraries(tapkee PRIVATE "${FMT_LIBRARY_TO_LINK}")
target_link_libraries(tapkee_library INTERFACE "${FMT_LIBRARY_TO_LINK}")
target_link_libraries(tapkee PRIVATE "${EIGEN3_LIBRARY_TO_LINK}")
target_link_libraries(tapkee_library INTERFACE "${EIGEN3_LIBRARY_TO_LINK}")

if (TAPKEE_CUSTOM_INSTALL_DIR)
	set (TAPKEE_INSTALL_DIR
		"${TAPKEE_CUSTOM_INSTALL_DIR}")
else()
	set (TAPKEE_INSTALL_DIR
		"${CMAKE_INSTALL_PREFIX}/include/tapkee")
endif()

install(
	DIRECTORY "${TAPKEE_INCLUDE_DIR}/tapkee"
	DESTINATION "${TAPKEE_INSTALL_DIR}"
)

install(
	DIRECTORY "${TAPKEE_INCLUDE_DIR}/stichwort"
	DESTINATION "${TAPKEE_INSTALL_DIR}"
)

# G++ specific flags
option(USE_GCOV "Use gcov to analyze test coverage" OFF)

if (CMAKE_COMPILER_IS_GNUCXX)
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wshadow")
	if (USE_GCOV)
		set(CMAKE_BUILD_TYPE Debug)
		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
		set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")

		add_custom_target(lcov DEPENDS tapkee)
		add_custom_command(TARGET lcov COMMAND mkdir -p coverage WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
		add_custom_command(TARGET lcov COMMAND lcov --directory . --zerocounters WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
		add_custom_command(TARGET lcov COMMAND make test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
		add_custom_command(TARGET lcov COMMAND lcov --directory . --capture --output-file ./coverage/out.info WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
		add_custom_command(TARGET lcov COMMAND lcov --remove ./coverage/out.info /usr/local/include\\* /usr/include\\* unit\\* --output ./coverage/clean.info "${CMAKE_BINARY_DIR}" VERBATIM)
		add_custom_command(TARGET lcov COMMAND genhtml -o ./coverage ./coverage/clean.info --branch-coverage --demangle-cpp WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
	endif()
endif()

if (MSVC)
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
endif()

if (NOT CMAKE_BUILD_TYPE)
	set(CMAKE_BUILD_TYPE Release)
endif()

if (CMAKE_BUILD_TYPE MATCHES Debug)
	add_definitions(-DTAPKEE_DEBUG)
endif()

option(GPL_FREE "Build without GPL-licensed components" OFF)

if (NOT GPL_FREE)
	add_definitions(-DTAPKEE_USE_LGPL_COVERTREE)
endif()

option(BUILD_TESTS "Build tests" OFF)

if (BUILD_TESTS)
	find_package(GTest REQUIRED)
	enable_testing()

	aux_source_directory("${TAPKEE_TESTS_DIR}" "TAPKEE_TESTS_SOURCES")
	foreach(i ${TAPKEE_TESTS_SOURCES})
		get_filename_component(exe ${i} NAME_WE)
		add_executable(test_${exe} ${i})
		target_link_libraries(test_${exe} PUBLIC GTest::gtest GTest::gtest_main)
		target_link_libraries(test_${exe} PRIVATE ${FMT_LIBRARY_TO_LINK})
		target_link_libraries(test_${exe} PRIVATE ${EIGEN3_LIBRARY_TO_LINK})
		if (ARPACK_FOUND)
			target_link_libraries(test_${exe} PUBLIC arpack)
		endif()
		if (VIENNACL_FOUND)
			target_link_libraries(test_${exe} PUBLIC OpenCL)
		endif()
		add_test(
			NAME ${exe}
			WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
			COMMAND "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_${exe}"
			--gtest_color=yes)
	endforeach()
endif()

export(
	TARGETS tapkee_library
	NAMESPACE tapkee::
	FILE ${PROJECT_BINARY_DIR}/tapkee.cmake
)
