#*******************************************************************************
#**  This file is part of Dux Rei Nummariae.                                 ***
#**                                                                          ***
#**  Copyright (C) 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024            ***
#**  John Schneiderman <Licencing _AT_ Schneiderman _DOT_ me>                ***
#**                                                                          ***
#**  This program is free software: you can redistribute it and/or modify it ***
#**  under the terms of the GNU Affero General Public License as published   ***
#**  by the Free Software Foundation, either version 3 of the License, or    ***
#**  (at your option) any later version.                                     ***
#**                                                                          ***
#**  This program is distributed in the hope that it will be useful, but     ***
#**  WITHOUT ANY WARRANTY; without even the implied warranty of              ***
#**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                    ***
#**  See the GNU Affero General Public License for more details.             ***
#**                                                                          ***
#**  You should have received a copy of the GNU Affero General Public License***
#**  along with this program. If not, see <http://www.gnu.org/licenses/>.    ***
#*******************************************************************************
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
project(DuxReiNummariae
		VERSION 0.7.0
		DESCRIPTION "Simple and powerful budgeting application"
		HOMEPAGE_URL "http://www.budgetnav.com"
		LANGUAGES CXX
)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_DEBUG_POSTFIX "d")
set(${PROJECT_NAME}_COPYRIGHT_YEARS "\"2017 - 2024\"")

set(
		${PROJECT_NAME}_OPEN_EXCHANGE_RATES_API_KEY
		""
		CACHE
		STRING
		"The application API key for Open Exchange Rates"
)
option(${PROJECT_NAME}_ENABLE_TESTS "Enables compiling and executing tests." OFF)
option(${PROJECT_NAME}_ENABLE_CODE_COVERAGE_TARGET
		"Enables/disables the creation of a code coverage target."
		OFF
)

if ("" STREQUAL "${${PROJECT_NAME}_OPEN_EXCHANGE_RATES_API_KEY}")
	message(WARNING "The Open Exchange Rates API key is empty.")
endif ("" STREQUAL "${${PROJECT_NAME}_OPEN_EXCHANGE_RATES_API_KEY}")

if (${PROJECT_NAME}_ENABLE_CODE_COVERAGE_TARGET AND NOT ${PROJECT_NAME}_ENABLE_TESTS)
	message(FATAL_ERROR "Code coverage target requires unit tests to be enabled.")
endif ()

set(
		${PROJECT_NAME}_PACKAGE_RELEASE
		1
		CACHE
		STRING
		"Sets the release number of the package."
)
mark_as_advanced(${PROJECT_NAME}_PACKAGE_RELEASE)

if (${PROJECT_NAME}_ENABLE_TESTS)
	include(CTest)
	enable_testing()
endif ()

# Allow for packagers to supply the name of the library directory.
if (DEFINED LIB_INSTALL_DIR)
	message(STATUS "Using supplied library directory installation path.")
	set(${PROJECT_NAME}_LIBRARY_INSTALL_DIR ${LIB_INSTALL_DIR})
else ()
	if (EXISTS "${CMAKE_INSTALL_PREFIX}/lib32/" AND CMAKE_SIZEOF_VOID_P EQUAL 4)
		set(${PROJECT_NAME}_LIBRARY_INSTALL_DIR lib32)
	elseif (EXISTS "${CMAKE_INSTALL_PREFIX}/lib64/" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
		set(${PROJECT_NAME}_LIBRARY_INSTALL_DIR lib64)
	else ()
		set(${PROJECT_NAME}_LIBRARY_INSTALL_DIR lib)
	endif (EXISTS "${CMAKE_INSTALL_PREFIX}/lib32/" AND CMAKE_SIZEOF_VOID_P EQUAL 4)
endif ()

if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)
	message(DEBUG "Adding additional warning checks for GCC.")
	add_compile_options("-Wall")
	add_compile_options("-Wcast-qual")
	add_compile_options("-Wconversion")
	add_compile_options("-Wdangling-else")
	add_compile_options("-Wdeprecated")
	add_compile_options("-Wdeprecated-declarations")
	add_compile_options("-Wduplicated-branches")
	add_compile_options("-Wduplicated-cond")
	add_compile_options("-Werror")
	add_compile_options("-Wextra")
	add_compile_options("-Wextra-semi")
	add_compile_options("-Wfloat-equal")
	add_compile_options("-Winit-self")
	add_compile_options("-Wlogical-op")
	# TODO add_compile_options("-Wmissing-declarations")
	add_compile_options("-Wpedantic")
	# TODO add_compile_options("-Wshadow")
	# TODO add_compile_options("-Wsign-conversion")
	add_compile_options("-Wsuggest-override")
	add_compile_options("-Wundef")
	add_compile_options("-Wuninitialized")
	add_compile_options("-Wunused-macros")
	# TODO add_compile_options("-Winline")
	# Justification: caused by the interaction between forward declarations and definitions of
	# enum classes.
	add_compile_options("-Wno-attributes")
	add_compile_options("-fconcepts-diagnostics-depth=5")

	if ("${CMAKE_BUILD_TYPE}" STREQUAL Debug)
		add_compile_options("-fprofile-arcs")
		add_compile_options("-ftest-coverage")
		add_link_options("--coverage")
		add_link_options("-lgcov")
	endif ()
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)
	message(WARNING "Compilations options not set.")
	set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
	message(DEBUG "Adding additional warning checks for MSVC.")
	add_compile_options("/permissive-")
	add_compile_options("/fp:strict")
	add_compile_options("/external:anglebrackets")
	add_compile_options("/external:W0")
	add_compile_options("/W4")
	add_compile_options("/utf-8")
	add_compile_options("/WX")
	# Justification: The code is meant to be compiled as a single collection. When this changes,
	# make the templates member variables unique pointers.
	add_compile_options("/wd4251")
	# Justification: Using pragmas from other compilers.
	add_compile_options("/wd4068")
	# Justification: Using the Qt test skip triggers it.
	add_compile_options("/wd4702")
endif ()

add_subdirectory(src)

if (${PROJECT_NAME}_ENABLE_CODE_COVERAGE_TARGET)
	find_program(LCOV_FILE_PATH lcov)

	if (NOT LCOV_FILE_PATH)
		message(FATAL_ERROR "Failed to locate 'lcov' not found!")
	endif ()
	find_program(GENHTML_FILE_PATH genhtml)

	if (NOT GENHTML_FILE_PATH)
		message(FATAL_ERROR "Failed to locate 'genhtml' not found!")
	endif ()
	find_program(GCOVR_FILE_PATH gcovr)

	if (NOT GCOVR_FILE_PATH)
		message(FATAL_ERROR "Failed to locate 'gcovr' not found!")
	endif ()
	add_custom_target(Code-Coverage
			COMMAND "${LCOV_FILE_PATH}"
			--quiet
			--output-file cpp-code-coverage.info
			--capture
			--directory "${PROJECT_BINARY_DIR}"
			--parallel 4
			--ignore-errors gcov,source
			COMMAND "${LCOV_FILE_PATH}"
			--quiet
			--directory "${PROJECT_BINARY_DIR}"
			--remove cpp-code-coverage.info '/usr/*'
			--remove cpp-code-coverage.info '*unit-tests'
			--remove cpp-code-coverage.info '*autogen*'
			--parallel 4
			--output-file cpp-code-coverage.info
			COMMAND "${GENHTML_FILE_PATH}"
			--quiet
			--output-directory code-coverage
			--title "${PROJECT_NAME} Unit Tests"
			--legend
			--dark-mode
			--parallel 4
			cpp-code-coverage.info
			COMMAND "${GCOVR_FILE_PATH}"
			--cobertura
			--root "${PROJECT_SOURCE_DIR}"
			--exclude-unreachable-branches
			--print-summary
			--exclude-directories '/usr'
			-j 4
			--output "${PROJECT_BINARY_DIR}/cpp-code-coverage.xml"
			"${PROJECT_BINARY_DIR}"
			COMMAND rm --force "${PROJECT_BINARY_DIR}/cpp-code-coverage.info"
			COMMAND echo "Generated Report Path:"
			COMMAND echo "file://${PROJECT_BINARY_DIR}/code-coverage/index.html"
			DEPENDS drn-desktop
			BYPRODUCTS "${PROJECT_BINARY_DIR}/code-coverage/index.html"
			WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
			COMMENT "Generating code coverage information..."
	)
endif ()
