cmake_policy(SET CMP0048 NEW)
project(ObloMB 
        VERSION 1.8.9
        LANGUAGES CXX C)
cmake_minimum_required(VERSION 3.0)

include(GNUInstallDirs)
include(ObloUtil.cmake)

#########################
##### CMAKE OPTIONS #####
#########################

option(WITH_OPENSSL "Include SSL support?" OFF)
option(WITH_POCO_STATIC "Use Poco as a static library?" OFF)
option(WITH_BIG_ENDIAN "Use big endian byte order (for e.g. MIPS architecture)?" OFF)
option(WITH_TEST_API "Include additions for testing?" OFF)
option(WITH_DEV_PACKAGE "Install include and lib directories?" OFF)

set(PRODUCT_PLATFORM "dev" CACHE STRING "Select supported platform (list directories in product/platform)")
set(PRODUCT_CUSTOMER "rtrk" CACHE STRING "Select supported customer (list directories in product/customer)")

# Remove install prefix
#set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/bins")

set(OMB_INCLUDE_DIRS "")
set(OMB_LINK_DIRS "")
set(OMB_LINK_LIBS "")

set(OMB_SOURCE_FILES "")
set(OMB_HEADER_FILES "")

set(OMB_INSTALL_CFG_PATH "${CMAKE_INSTALL_SYSCONFDIR}/${PRODUCT_CUSTOMER}/omb/cfg/")
set(OMB_INSTALL_DATA_PATH "${CMAKE_INSTALL_SYSCONFDIR}/${PRODUCT_CUSTOMER}/omb/data")
set(OMB_INSTALL_BIN_PATH "${CMAKE_INSTALL_PREFIX}/bin")

message(STATUS "Platform: " ${PRODUCT_PLATFORM})
message(STATUS "Customer: " ${PRODUCT_CUSTOMER})
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
add_definitions(-DPLATFORM="${PRODUCT_PLATFORM}")
add_definitions(-DCUSTOMER="${PRODUCT_CUSTOMER}")

#####################################
##### PRODUCT & FEATURE OPTIONS #####
#####################################

set(OBLO_AVAILABLE_FEATURES "")
set(OBLO_AVAILABLE_PLATFORMS "")
set(OBLO_AVAILABLE_CUSTOMERS "")

OBLO_LIST_SUBDIRS("${PROJECT_SOURCE_DIR}/src/feature" OBLO_AVAILABLE_FEATURES)
OBLO_LIST_SUBDIRS("${PROJECT_SOURCE_DIR}/product/platform" OBLO_AVAILABLE_PLATFORMS)
OBLO_LIST_SUBDIRS("${PROJECT_SOURCE_DIR}/product/customer" OBLO_AVAILABLE_CUSTOMERS)
set_property(CACHE PRODUCT_PLATFORM PROPERTY STRINGS ${OBLO_AVAILABLE_PLATFORMS})
set_property(CACHE PRODUCT_CUSTOMER PROPERTY STRINGS ${OBLO_AVAILABLE_CUSTOMERS})

##### Check if product is changed #####
set(OBLO_PRODUCT_UID_TMP "${PRODUCT_CUSTOMER}_${PRODUCT_PLATFORM}")

if(NOT "${OBLO_PRODUCT_UID_TMP}" STREQUAL "${PRODUCT_UID}")
    # Unset features cached for previous customer.
    # New set should be performed according to customer's configuration
    set(PRODUCT_UID ${OBLO_PRODUCT_UID_TMP} CACHE STRING "Cached product (customer+platform) value" FORCE)
    message(STATUS "Cached product updated: ${PRODUCT_UID}")

    foreach(OBLO_AVAILABLE_FEATURE ${OBLO_AVAILABLE_FEATURES})
        set(OPTION_NAME "FEATURE_${OBLO_AVAILABLE_FEATURE}")
        string(TOUPPER ${OPTION_NAME} OPTION_NAME)
        unset(${OPTION_NAME})
        unset(${OPTION_NAME} CACHE)
    endforeach()
endif()

###################
##### PRODUCT #####
###################

include("${PROJECT_SOURCE_DIR}/product/platform/${PRODUCT_PLATFORM}/Platform.cmake"
    OPTIONAL RESULT_VARIABLE OBLO_FILE)
message(STATUS "Platform external: " ${OBLO_FILE})
include("${PROJECT_SOURCE_DIR}/product/platform/${PRODUCT_PLATFORM}/Variables.cmake"
    OPTIONAL RESULT_VARIABLE OBLO_FILE)
message(STATUS "Platform variables: " ${OBLO_FILE})
include("${PROJECT_SOURCE_DIR}/product/customer/${PRODUCT_CUSTOMER}/Customer.cmake"
    OPTIONAL RESULT_VARIABLE OBLO_FILE)
message(STATUS "Customer external: " ${OBLO_FILE})
include("${PROJECT_SOURCE_DIR}/product/customer/${PRODUCT_CUSTOMER}/Variables.cmake"
    OPTIONAL RESULT_VARIABLE OBLO_FILE)
message(STATUS "Customer variables: " ${OBLO_FILE})

add_definitions(-DOMB_CONFIG_FILE="${OMB_CONFIG_FILE}")
add_definitions(-DOMB_DB_FILE="${OMB_DB_FILE}")
add_definitions(-DOMB_PRIVATE_KEY_PASSWORD=\"${OMB_PRIVATE_KEY_PASSWORD}\")

#################
##### FLAGS #####
#################

if(MSVC)
    # Force to always compile with W4
    if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
        string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    else()
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
    endif()
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fdata-sections -ffunction-sections -Wl,--gc-sections")
endif()

message(STATUS "CXX_FLAGS: ${CMAKE_CXX_FLAGS}")

###################
##### DEFINES #####
###################

if(WITH_OPENSSL)
    add_definitions(-DUSE_SECURE_CONNECTION)
    message(STATUS "Using OpenSSL support.")
endif()

if(WITH_POCO_STATIC)
    add_definitions(-DPOCO_STATIC)
    message(STATUS "Using Poco static.")
endif()

if(WITH_BIG_ENDIAN)
    add_definitions(-DUSE_BIG_ENDIAN)
    ## Paho REVERSED flag
    add_definitions(-DREVERSED)
    message(STATUS "Using big-endian.")
endif()

if(WITH_TEST_API)
    add_definitions(-DUSE_TEST_API)
    message(STATUS "Including test additions.")
endif()

if(WITH_DEV_PACKAGE)
    message(STATUS "Including development package.")
    set(WITH_DEV_MESSENGER ON)
else()
    set(WITH_DEV_MESSENGER OFF)
endif()

if(POCO_ANDROID)
    message(STATUS "Using POCO_ANDROID flag")
    add_definitions(-DPOCO_ANDROID)
endif()

###################
##### VERSION #####
###################

find_package(Git)
if(GIT_FOUND)
    ##### Get version
    execute_process(
            COMMAND ${GIT_EXECUTABLE} describe --tags --dirty
            WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
            OUTPUT_VARIABLE OMB_VERSION
            ERROR_QUIET
            OUTPUT_STRIP_TRAILING_WHITESPACE)
    if(OMB_VERSION)
        string(REPLACE "-dirty" "" OMB_VERSION ${OMB_VERSION})
        message(STATUS "Version: " ${OMB_VERSION} ".")
        add_definitions(-DOMB_VERSION=\"${OMB_VERSION}\")
    endif()
else()
    set(OMB_VERSION, ${OMB_VERSION})
    message(STATUS "Version: " ${OMB_VERSION} ".")
    add_definitions(-DOMB_VERSION=\"${OMB_VERSION}\")
endif()

#####################
##### LIBRARIES #####
#####################

##### OBLO messenger #####
set(OBLO_MESSENGER_INCLUDE_DIRS ${OMB_INCLUDE_DIRS})
set(OBLO_MESSENGER_LINK_DIRS ${OMB_LINK_DIRS})
set(OBLO_MESSENGER_LIBS ${OMB_LINK_LIBS})
add_subdirectory("${PROJECT_SOURCE_DIR}/libs/oblomessenger")

list(APPEND OMB_INCLUDE_DIRS
        "${PROJECT_SOURCE_DIR}/libs/oblomessenger/include"
        "${PROJECT_SOURCE_DIR}/libs/oblomessenger/include/paho"
    )
list(APPEND OMB_LINK_DIRS
        "${PROJECT_SOURCE_DIR}/libs/oblomessenger/lib"
    )
list(APPEND OMB_LINK_LIBS
        oblomessenger
    )

##### Mosquitto #####
set(OBLO_MOSQUITTO_INCLUDE_DIRS ${OMB_INCLUDE_DIRS})
set(OBLO_MOSQUITTO_LIB_DIRS ${OMB_LINK_DIRS})
add_subdirectory("${PROJECT_SOURCE_DIR}/libs/mosquitto")

list(APPEND OMB_INCLUDE_DIRS
        "${PROJECT_SOURCE_DIR}/libs/mosquitto"
        "${PROJECT_SOURCE_DIR}/libs/mosquitto/src"
        "${PROJECT_SOURCE_DIR}/libs/mosquitto/lib")
list(APPEND OMB_LINK_DIRS
        "${PROJECT_SOURCE_DIR}/libs/mosquitto/lib")
list(APPEND OMB_LINK_LIBS
        mosquitto)

###################
##### SOURCES #####
###################

include(src/CMakeLists.txt)

list(APPEND OMB_INCLUDE_DIRS
        "${PROJECT_SOURCE_DIR}"
        "${PROJECT_SOURCE_DIR}/src"
    )

############################
##### INCLUDE FEATURES #####
############################

set(OMB_FEATURE_INCLUDE_LIST "")
set(OMB_FEATURE_EXCLUDE_LIST "")

foreach(OBLO_AVAILABLE_FEATURE ${OBLO_AVAILABLE_FEATURES})
    set(OPTION_NAME "FEATURE_${OBLO_AVAILABLE_FEATURE}")
    string(TOUPPER ${OPTION_NAME} OPTION_NAME)

    if(${OPTION_NAME})
        list(APPEND OMB_FEATURE_INCLUDE_LIST ${OBLO_AVAILABLE_FEATURE})
        include("${PROJECT_SOURCE_DIR}/src/feature/${OBLO_AVAILABLE_FEATURE}/Feature.cmake")
    else()
        list(APPEND OMB_FEATURE_EXCLUDE_LIST ${OBLO_AVAILABLE_FEATURE})
        option(${OPTION_NAME} "Include feature ${OBLO_AVAILABLE_FEATURE}" OFF)
    endif()
endforeach()

list(SORT OMB_FEATURE_INCLUDE_LIST)

message(STATUS "Feature list:")
OBLO_PRETTY_LIST_PRINT("${OMB_FEATURE_INCLUDE_LIST}")

#######################
##### APPLICATION #####
#######################

link_directories(${OMB_LINK_DIRS})

add_executable(oblomb ${OMB_SOURCE_FILES} ${OMB_HEADER_FILES})

target_include_directories(oblomb PRIVATE ${OMB_INCLUDE_DIRS})
target_link_libraries(oblomb ${OMB_LINK_LIBS})

set_target_properties(oblomb PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/bin")

if(MSVC)
    set_target_properties(oblomb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/output/bin")
    set_target_properties(oblomb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/output/bin")
endif()

message(STATUS "Include directories: ")
OBLO_PRETTY_LIST_PRINT("${OMB_INCLUDE_DIRS}")
message(STATUS "Link directories: ")
OBLO_PRETTY_LIST_PRINT("${OMB_LINK_DIRS}")
message(STATUS "Libraries: ")
OBLO_PRETTY_LIST_PRINT("${OMB_LINK_LIBS}")

#########################
##### DOCUMENTATION #####
#########################

add_subdirectory(doc)

###################
##### INSTALL #####
###################

set(OBLO_INSTALL_STAGE_DIR ${PROJECT_SOURCE_DIR}/product/tmp-install-data)

install(CODE "
    ##### Include variables to have them during the installation #####
    include(\"${PROJECT_SOURCE_DIR}/product/platform/${PRODUCT_PLATFORM}/Variables.cmake\" OPTIONAL)
    include(\"${PROJECT_SOURCE_DIR}/product/customer/${PRODUCT_CUSTOMER}/Variables.cmake\" OPTIONAL)
    include(\"${PROJECT_SOURCE_DIR}/ObloUtil.cmake\")
    OBLO_GENERATE_INSTALL_FILES(
        \"\$ENV{DESTDIR}${OBLO_INSTALL_STAGE_DIR}\"
        \"${PROJECT_SOURCE_DIR}/product\"
        \"${PRODUCT_PLATFORM}\"
        \"${PRODUCT_CUSTOMER}\"
        )
    ##### Install cfg #####
    OBLO_COPY_DIR(\"\$ENV{DESTDIR}${OBLO_INSTALL_STAGE_DIR}/cfg\" \"\$ENV{DESTDIR}${CMAKE_INSTALL_SYSCONFDIR}/${PRODUCT_CUSTOMER}/omb/cfg\")
    ##### Install data #####
    OBLO_COPY_DIR(\"\$ENV{DESTDIR}${OBLO_INSTALL_STAGE_DIR}/data\" \"\$ENV{DESTDIR}${CMAKE_INSTALL_SYSCONFDIR}/${PRODUCT_CUSTOMER}/omb/data\")
    ##### Remote stage dir #####
    file(REMOVE_RECURSE \"${OBLO_INSTALL_STAGE_DIR}\")
    message(STATUS \"Installation COMPLETED.\")
    ")

install(TARGETS oblomb DESTINATION bin)
