####################################################################################################################
####################################################################################################################
####################################################################################################################
# General
####################################################################################################################
####################################################################################################################
####################################################################################################################

##########################################################
# Basic
##########################################################

cmake_minimum_required(VERSION 3.30)
project(ls-std VERSION 1.0.1)

set(MODULE_NAME_BOXING ls-std-boxing)
set(MODULE_NAME_CORE ls-std-core)
set(MODULE_NAME_ENCODING ls-std-encoding)
set(MODULE_NAME_EVENT ls-std-event)
set(MODULE_NAME_IO ls-std-io)
set(MODULE_NAME_TIME ls-std-time)

set(GOOGLE_TEST_MODULE googletest-1.15.2)

set(CLI_NAME_BASE64 cli-base64)

##########################################################
# Options
##########################################################

option(LS_STD_BUILD_WITH_TESTS "Build project with tests..." OFF)
option(LS_STD_BUILD_WITH_SUPPORTED_COMPILER "Build project with supported compiler only..." ON)
option(LS_STD_BUILD_STATIC "Build ls-std static library..." ON)
option(LS_STD_BUILD_SHARED "Build ls-std shared library..." OFF)
option(LS_STD_BUILD_WITH_JNI "Build ls-std shared library with JNI..." OFF)

set(TARGET_COUNTER 0)

if (${LS_STD_BUILD_STATIC})
    math(EXPR TARGET_COUNTER "${TARGET_COUNTER} + 1")
    set(GOAL "static library")
endif ()

if (${LS_STD_BUILD_SHARED})
    math(EXPR TARGET_COUNTER "${TARGET_COUNTER} + 1")
    set(GOAL "shared library")
endif ()

message("${PROJECT_NAME}: [Goal] ${GOAL}")

if (TARGET_COUNTER GREATER 1)
    message("${PROJECT_NAME}: [Error] only one goal supported at the same time!")
    return()
endif ()

if (TARGET_COUNTER EQUAL 0)
    message("${PROJECT_NAME}: [Error] no goal selected!")
    return()
endif ()

##########################################################
# JNI flag check
##########################################################

if (${LS_STD_BUILD_WITH_JNI})
    if (${LS_STD_BUILD_SHARED})
        message("${PROJECT_NAME}: build with JNI support...")
    else ()
        message("${PROJECT_NAME}: [Error] JNI support requires shared build goal!")
        return()
    endif ()
endif ()

##########################################################
# Compiler Settings
##########################################################

message("${PROJECT_NAME}: Setting compiler flags...")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

##########################################################
# Compiler Support
##########################################################

if (${LS_STD_BUILD_WITH_SUPPORTED_COMPILER})
    message("${PROJECT_NAME}: build with compiler support...")

    # define supported compilers

    if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC OR
            ${CMAKE_CXX_COMPILER_ID} STREQUAL Clang OR
            ${CMAKE_CXX_COMPILER_ID} STREQUAL AppleClang)
        message("${PROJECT_NAME}: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} is supported...")
    else ()
        message("${PROJECT_NAME}: [Error] ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} is not supported... terminated!")
        return()
    endif ()
endif ()

######################################################
# Find Packages
######################################################

if (${LS_STD_BUILD_WITH_JNI})
    if (DEFINED ENV{JAVA_HOME})
        message("JAVA_HOME found in '$ENV{JAVA_HOME}' location...")
    else ()
        message("[Error] JAVA_HOME not found!")
        return()
    endif ()

    message("${PROJECT_NAME}: finding JNI package in '$ENV{JAVA_HOME}'...")
    find_package(JNI REQUIRED)
endif ()

######################################################
# Include Directories
######################################################

message("${PROJECT_NAME}: Adding include directories...")

if (${LS_STD_BUILD_WITH_JNI})
    include_directories(${JAVA_INCLUDE_PATH})
    include_directories(${JAVA_INCLUDE_PATH2})
    include_directories(${JAVA_AWT_INCLUDE_PATH})
endif ()

if (${LS_STD_BUILD_WITH_TESTS})
    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/test)
    include_directories(${CMAKE_CURRENT_LIST_DIR}/test/lib/${GOOGLE_TEST_MODULE}/googletest/include)
    include_directories(${CMAKE_CURRENT_LIST_DIR}/test/lib/${GOOGLE_TEST_MODULE}/googlemock/include)
endif ()

include_directories(${CMAKE_CURRENT_LIST_DIR}/include)

######################################################
# Add Other CMake Dependencies
######################################################

message("${PROJECT_NAME}: Adding additional cmake dependencies...")

if (${LS_STD_BUILD_WITH_TESTS})
    add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/test/lib/${GOOGLE_TEST_MODULE})
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Source Files Modularization
####################################################################################################################
####################################################################################################################
####################################################################################################################

include(cmake/SourceFiles.cmake)

set(SOURCE_FILES_BOXING)
collect_boxing_module_source_files(SOURCE_FILES_BOXING)

set(SOURCE_FILES_CORE)
collect_core_module_source_files(SOURCE_FILES_CORE)

set(SOURCE_FILES_CORE_JNI)
collect_core_jni_module_source_files(SOURCE_FILES_CORE_JNI)

set(SOURCE_FILES_ENCODING)
collect_encoding_module_source_files(SOURCE_FILES_ENCODING)

set(SOURCE_FILES_EVENT)
collect_event_module_source_files(SOURCE_FILES_EVENT)

set(SOURCE_FILES_IO)
collect_io_module_source_files(SOURCE_FILES_IO)

set(SOURCE_FILES_TIME)
collect_time_module_source_files(SOURCE_FILES_TIME)

set(SOURCE_FILES_LINUX_TIME)
set(SOURCE_FILES_WINDOWS_TIME)

if (UNIX OR APPLE)
    message("${MODULE_NAME_TIME}: Add UNIX files for time module...")
    set(SOURCE_FILES_LINUX_TIME
            ${CMAKE_CURRENT_SOURCE_DIR}/source/ls-std/time/system-time/PosixClock.cpp)
else (WIN32)
    message("${MODULE_NAME_TIME}: Add Windows files for time module...")
    set(SOURCE_FILES_WINDOWS_TIME
            ${CMAKE_CURRENT_SOURCE_DIR}/source/ls-std/time/system-time/WindowsClock.cpp)
endif ()

set(SOURCE_FILES_TIME_JNI)
collect_time_jni_module_source_files(SOURCE_FILES_TIME_JNI)

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Unit Test Files Modularization
####################################################################################################################
####################################################################################################################
####################################################################################################################

if (${LS_STD_BUILD_WITH_TESTS})
    include(cmake/TestFiles.cmake)

    set(UNIT_TEST_FILES_BOXING)
    collect_boxing_module_test_files(UNIT_TEST_FILES_BOXING)

    set(UNIT_TEST_FILES_CORE)
    collect_core_module_test_files(UNIT_TEST_FILES_CORE)

    set(UNIT_TEST_FILES_CORE_JNI)
    collect_core_jni_module_test_files(UNIT_TEST_FILES_CORE_JNI)

    set(UNIT_TEST_FILES_ENCODING)
    collect_encoding_module_test_files(UNIT_TEST_FILES_ENCODING)

    set(UNIT_TEST_FILES_EVENT)
    collect_event_module_test_files(UNIT_TEST_FILES_EVENT)

    set(UNIT_TEST_FILES_IO)
    collect_io_module_test_files(UNIT_TEST_FILES_IO)

    set(UNIT_TEST_FILES_SERIALIZATION)
    collect_serialization_module_test_files(UNIT_TEST_FILES_SERIALIZATION)

    set(UNIT_TEST_FILES_TIME)
    collect_time_module_test_files(UNIT_TEST_FILES_TIME)
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Unit Test Suite Builds
####################################################################################################################
####################################################################################################################
####################################################################################################################

##########################################################
# Unit Build Tests (boxing)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_BOXING}: Building unit tests...")
    add_executable(${MODULE_NAME_BOXING}-unit-test ${UNIT_TEST_FILES_BOXING})
endif ()

##########################################################
# Unit Build Tests (core)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    if (${LS_STD_BUILD_WITH_JNI})
        message("${MODULE_NAME_CORE}: Building unit tests with JNI support...")
        add_executable(${MODULE_NAME_CORE}-unit-test ${UNIT_TEST_FILES_CORE} ${UNIT_TEST_FILES_CORE_JNI})
    else ()
        message("${MODULE_NAME_CORE}: Building unit tests...")
        add_executable(${MODULE_NAME_CORE}-unit-test ${UNIT_TEST_FILES_CORE})
    endif ()
endif ()

##########################################################
# Unit Build Tests (encoding)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_ENCODING}: Building unit tests...")
    add_executable(${MODULE_NAME_ENCODING}-unit-test ${UNIT_TEST_FILES_ENCODING})
endif ()

##########################################################
# Unit Build Tests (event)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_EVENT}: Building unit tests...")
    add_executable(${MODULE_NAME_EVENT}-unit-test ${UNIT_TEST_FILES_EVENT})
endif ()

##########################################################
# Unit Build Tests (io)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_IO}: Building unit tests...")
    add_executable(${MODULE_NAME_IO}-unit-test
            ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestException.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestHelper.cpp
            ${UNIT_TEST_FILES_IO})
endif ()

##########################################################
# Unit Build Tests (time)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_TIME}: Building unit tests...")
    add_executable(${MODULE_NAME_TIME}-unit-test ${UNIT_TEST_FILES_TIME})
endif ()

##########################################################
# Unit Build Tests (all)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    if (${LS_STD_BUILD_WITH_JNI})
        message("${PROJECT_NAME}: Building unit tests with JNI support...")
        add_executable(${PROJECT_NAME}-unit-test
                ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestException.cpp
                ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestHelper.cpp
                ${UNIT_TEST_FILES_BOXING}
                ${UNIT_TEST_FILES_CORE}
                ${UNIT_TEST_FILES_CORE_JNI}
                ${UNIT_TEST_FILES_ENCODING}
                ${UNIT_TEST_FILES_EVENT}
                ${UNIT_TEST_FILES_IO}
                ${UNIT_TEST_FILES_SERIALIZATION}
                ${UNIT_TEST_FILES_TIME})
    else ()
        message("${PROJECT_NAME}: Building unit tests...")
        add_executable(${PROJECT_NAME}-unit-test
                ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestException.cpp
                ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestHelper.cpp
                ${UNIT_TEST_FILES_BOXING}
                ${UNIT_TEST_FILES_CORE}
                ${UNIT_TEST_FILES_ENCODING}
                ${UNIT_TEST_FILES_EVENT}
                ${UNIT_TEST_FILES_IO}
                ${UNIT_TEST_FILES_SERIALIZATION}
                ${UNIT_TEST_FILES_TIME})
    endif ()
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Integration Test Files Modularization
####################################################################################################################
####################################################################################################################
####################################################################################################################

if (${LS_STD_BUILD_WITH_TESTS})
    set(INTEGRATION_TEST_FILES_IO
            ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/io/section-pair/reader/SectionPairFileReaderIT.cpp)
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Integration Test Suite Builds
####################################################################################################################
####################################################################################################################
####################################################################################################################

##########################################################
# Integration Build Tests (io)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_IO}: Building integration tests...")
    add_executable(${MODULE_NAME_IO}-integration-test
            ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestException.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestHelper.cpp
            ${INTEGRATION_TEST_FILES_IO})
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Whole Test Suite Builds
####################################################################################################################
####################################################################################################################
####################################################################################################################

if (${LS_STD_BUILD_WITH_TESTS})
    if (${LS_STD_BUILD_WITH_JNI})
        message("${PROJECT_NAME}: Building all tests...")
        add_executable(${PROJECT_NAME}-test
                ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestException.cpp
                ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestHelper.cpp
                ${UNIT_TEST_FILES_BOXING}
                ${UNIT_TEST_FILES_CORE}
                ${UNIT_TEST_FILES_CORE_JNI}
                ${UNIT_TEST_FILES_ENCODING}
                ${UNIT_TEST_FILES_EVENT}
                ${UNIT_TEST_FILES_IO}
                ${INTEGRATION_TEST_FILES_IO}
                ${UNIT_TEST_FILES_SERIALIZATION}
                ${UNIT_TEST_FILES_TIME})
    else ()
        message("${PROJECT_NAME}: Building all tests with JNI support...")
        add_executable(${PROJECT_NAME}-test
                ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestException.cpp
                ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/TestHelper.cpp
                ${UNIT_TEST_FILES_BOXING}
                ${UNIT_TEST_FILES_CORE}
                ${UNIT_TEST_FILES_ENCODING}
                ${UNIT_TEST_FILES_EVENT}
                ${UNIT_TEST_FILES_IO}
                ${INTEGRATION_TEST_FILES_IO}
                ${UNIT_TEST_FILES_SERIALIZATION}
                ${UNIT_TEST_FILES_TIME})
    endif ()
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Build Library Binaries
####################################################################################################################
####################################################################################################################
####################################################################################################################

include(cmake/Build.cmake)

build_boxing_module(LS_STD_BUILD_STATIC LS_STD_BUILD_SHARED MODULE_NAME_BOXING MODULE_NAME_CORE SOURCE_FILES_BOXING)
build_core_module(LS_STD_BUILD_STATIC LS_STD_BUILD_SHARED LS_STD_BUILD_WITH_JNI MODULE_NAME_CORE SOURCE_FILES_CORE SOURCE_FILES_CORE_JNI)
build_encoding_module(LS_STD_BUILD_STATIC LS_STD_BUILD_SHARED MODULE_NAME_ENCODING MODULE_NAME_CORE SOURCE_FILES_ENCODING)
build_event_module(LS_STD_BUILD_STATIC LS_STD_BUILD_SHARED MODULE_NAME_EVENT MODULE_NAME_CORE SOURCE_FILES_EVENT)
build_io_module(LS_STD_BUILD_STATIC LS_STD_BUILD_SHARED MODULE_NAME_IO MODULE_NAME_CORE SOURCE_FILES_IO)
build_time_module(LS_STD_BUILD_STATIC LS_STD_BUILD_SHARED LS_STD_BUILD_WITH_JNI MODULE_NAME_TIME MODULE_NAME_CORE SOURCE_FILES_TIME SOURCE_FILES_LINUX_TIME SOURCE_FILES_WINDOWS_TIME SOURCE_FILES_TIME_JNI)

# CLI base64

add_executable(${CLI_NAME_BASE64}
        ${CMAKE_CURRENT_SOURCE_DIR}/source/ls-std/encoding/cli/cli-base64-main.cpp)

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Unit Test Suite: Linking
####################################################################################################################
####################################################################################################################
####################################################################################################################

##########################################################
# Unit Linking (boxing)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_BOXING}: Linking libraries for unit test application...")
    target_link_libraries(${MODULE_NAME_BOXING}-unit-test
            gtest
            gtest_main
            "${MODULE_NAME_BOXING}"
            "${MODULE_NAME_CORE}")
endif ()

##########################################################
# Unit Linking (core)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_CORE}: Linking libraries for unit test application...")
    target_link_libraries(${MODULE_NAME_CORE}-unit-test
            gtest
            gmock
            gtest_main
            "${MODULE_NAME_CORE}")
endif ()

##########################################################
# Unit Linking (encoding)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_ENCODING}: Linking libraries for unit test application...")
    target_link_libraries(${MODULE_NAME_ENCODING}-unit-test
            gtest
            gtest_main
            "${MODULE_NAME_ENCODING}"
            "${MODULE_NAME_CORE}")
endif ()

##########################################################
# Unit Linking (event)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_EVENT}: Linking libraries for unit test application...")
    target_link_libraries(${MODULE_NAME_EVENT}-unit-test
            gtest
            gtest_main
            "${MODULE_NAME_EVENT}"
            "${MODULE_NAME_CORE}")
endif ()

##########################################################
# Unit Linking (io)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_IO}: Linking libraries for unit test application...")
    target_link_libraries(${MODULE_NAME_IO}-unit-test
            gtest
            gmock
            gtest_main
            "${MODULE_NAME_IO}"
            "${MODULE_NAME_CORE}")
endif ()

##########################################################
# Unit Linking (time)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_TIME}: Linking libraries for unit test application...")
    target_link_libraries(${MODULE_NAME_TIME}-unit-test
            gtest
            gmock
            gtest_main
            "${MODULE_NAME_TIME}"
            "${MODULE_NAME_CORE}")
endif ()

##########################################################
# Unit Linking (all)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${PROJECT_NAME}: Linking libraries for unit test application...")
    target_link_libraries(${PROJECT_NAME}-unit-test
            gtest
            gmock
            gtest_main
            "${MODULE_NAME_BOXING}"
            "${MODULE_NAME_ENCODING}"
            "${MODULE_NAME_EVENT}"
            "${MODULE_NAME_IO}"
            "${MODULE_NAME_TIME}"
            "${MODULE_NAME_CORE}")
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Integration Test Suite: Linking
####################################################################################################################
####################################################################################################################
####################################################################################################################

##########################################################
# Integration Linking (io)
##########################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${MODULE_NAME_IO}: Linking libraries for integration test application...")
    target_link_libraries(${MODULE_NAME_IO}-integration-test
            gtest
            gtest_main
            "${MODULE_NAME_IO}"
            "${MODULE_NAME_CORE}")
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# Whole Test Suite: Linking
####################################################################################################################
####################################################################################################################
####################################################################################################################

if (${LS_STD_BUILD_WITH_TESTS})
    message("${PROJECT_NAME}: Linking libraries for whole test application...")
    target_link_libraries(${PROJECT_NAME}-test
            gtest
            gmock
            gtest_main
            "${MODULE_NAME_BOXING}"
            "${MODULE_NAME_ENCODING}"
            "${MODULE_NAME_EVENT}"
            "${MODULE_NAME_IO}"
            "${MODULE_NAME_TIME}"
            "${MODULE_NAME_CORE}")
endif ()

####################################################################################################################
####################################################################################################################
####################################################################################################################
# CLI - Base64: Linking
####################################################################################################################
####################################################################################################################
####################################################################################################################

target_link_libraries(${CLI_NAME_BASE64}
        "${MODULE_NAME_ENCODING}"
        "${MODULE_NAME_CORE}")
