#*******************************************************************************
#**  This file is part of Pecunia.                                           ***
#**                                                                          ***
#**  Copyright (C) 2017, 2018, 2019, 2020, 2021, 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 Lesser 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 Lesser General Public License for more details.             ***
#**                                                                          ***
#**  You should have received a copy of the GNU Lesser General Public License***
#**  along with this program. If not, see <http://www.gnu.org/licenses/>.    ***
#*******************************************************************************
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
project(Pecunia
	VERSION 0.8.0
	DESCRIPTION "Library using the ISO-4217 currency standard & a fixed monetary unit size"
	HOMEPAGE_URL "http://pecunia.schneiderman.me"
	LANGUAGES CXX
)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_DEBUG_POSTFIX "d")

if (EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
	message(STATUS "Enabling Conan.io support.")
	include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
	conan_basic_setup()
endif (EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")

option(${PROJECT_NAME}_BUILD_SHARED_LIBRARY "Enables building as a shared library, else static." ON)


if (${PROJECT_NAME}_BUILD_SHARED_LIBRARY)
	set(${PROJECT_NAME}_LIBRARY_TYPE "SHARED")
else ()
	set(${PROJECT_NAME}_LIBRARY_TYPE "STATIC")
endif (${PROJECT_NAME}_BUILD_SHARED_LIBRARY)

option(${PROJECT_NAME}_ENABLE_TESTS "Enables building and executing tests." OFF)

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

set(
	${PROJECT_NAME}_SUB_MINOR_DIGITS
	2u
	CACHE
	STRING
	"Sets the extra number of digits to have after the minor unit."
)
set(
	${PROJECT_NAME}_MINOR_UNIT_TYPE
	std::uint16_t
	CACHE
	STRING
	"Sets the type used for the minor unit."
)
set(
	${PROJECT_NAME}_UNIT_STORAGE_TYPE
	std::int64_t
	CACHE
	STRING
	"Sets the type used for the money amount storage unit."
)
set(
	${PROJECT_NAME}_FLOATING_POINT_TYPE
	double
	CACHE
	STRING
	"Sets the type used for floating point operations."
)
set(
	${PROJECT_NAME}_FLOATING_POINT_PRECISION
	2u
	CACHE
	STRING
	"Sets the extra number of digit precision during floating point operations."
)
mark_as_advanced(${PROJECT_NAME}_FLOATING_POINT_PRECISION)
set(
	${PROJECT_NAME}_DEFAULT_ROUNDING_DIGITS
	3u
	CACHE
	STRING
	"Sets the number of digits during rounding operations to use as a default."
)
mark_as_advanced(${PROJECT_NAME}_DEFAULT_ROUNDING_DIGITS)
option(${PROJECT_NAME}_ENABLE_CODE_COVERAGE_TARGET
	"Enables/disables the creation of a code coverage target."
	OFF
)
set(
	${PROJECT_NAME}_ERROR_STACK_FRAME_SIZE
	256u
	CACHE
	STRING
	"Sets the maximum number of stack frames to collect in an exception thrown."
)
mark_as_advanced(${PROJECT_NAME}_ERROR_STACK_FRAME_SIZE)

if (UNIX)
	set(
		${PROJECT_NAME}_LOCALE
		"C.UTF-8"
		CACHE
		STRING
		"Sets the default locale used when setting up the library."
	)
else ()
	set(
		${PROJECT_NAME}_LOCALE
		"en_US.UTF-8"
		CACHE
		STRING
		"Sets the default locale used when setting up the library."
	)
endif ()
mark_as_advanced(${PROJECT_NAME}_LOCALE)
set(${PROJECT_NAME}_COPYRIGHT_YEARS "\"2017 - 2024\"")

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)

# 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 (DEFINED LIB_INSTALL_DIR)

if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)
	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")
	add_compile_options("-Wmissing-declarations")
	add_compile_options("-Wpedantic")
	add_compile_options("-Wshadow")
	add_compile_options("-Wsign-conversion")
	add_compile_options("-Wsuggest-override")
	add_compile_options("-Wundef")
	add_compile_options("-Wuninitialized")
	add_compile_options("-Wunused-macros")
	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")
	add_link_options("-rdynamic")

	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)
	add_compile_options("/permissive-")
	add_compile_options("/fp:strict")
	add_compile_options("/W4")
	add_compile_options("/utf-8")
	add_compile_options("/WX")
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
			--test-name "unit_tests"
			--output-file cpp-code-coverage.info
			--capture
			--directory "${PROJECT_BINARY_DIR}"
			--parallel 4
			--ignore-errors gcov
		COMMAND "${LCOV_FILE_PATH}"
			--quiet
			--directory "${PROJECT_BINARY_DIR}"
			--remove cpp-code-coverage.info '/usr/*'
			--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 pecunia
		BYPRODUCTS "${PROJECT_BINARY_DIR}/code-coverage/index.html"
		WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
		COMMENT "Generating code coverage information..."
	)
endif()
