# Set minimum required version and baseline policy
cmake_minimum_required(VERSION 3.5)

# Declare project
project(libswarmio LANGUAGES CXX)

# Enforce C++17
include("${CMAKE_CURRENT_LIST_DIR}/../cmake/helpers/cxx-standard.cmake")

# Add main library target
add_library(swarmio SHARED

	# Built-in services
	"src/swarmio/services/PeriodicService.cpp"
	"src/swarmio/services/ErrorAwaiter.cpp"
	"src/swarmio/services/event/Service.cpp"
	"src/swarmio/services/ping/Service.cpp"
	"src/swarmio/services/ping/TimingAwaiter.cpp"
	"src/swarmio/services/keyvalue/Service.cpp"
	"src/swarmio/services/keyvalue/ValueAwaiter.cpp"
	"src/swarmio/services/discovery/Service.cpp"
	"src/swarmio/services/telemetry/Service.cpp"

	# Zyre endpoint implementation
	"src/swarmio/transport/zyre/ZyreControlSocket.cpp"
	"src/swarmio/transport/zyre/ZyreEndpoint.cpp"
	"src/swarmio/transport/BasicEndpoint.cpp"
	"src/swarmio/transport/base64.cpp"

	# Protobuf messages
	"proto/swarmio/data/Message.proto"
	"proto/swarmio/data/Variant.proto"
	"proto/swarmio/data/ping/Echo.proto"
	"proto/swarmio/data/event/Notification.proto"
	"proto/swarmio/data/keyvalue/GetRequest.proto"
	"proto/swarmio/data/keyvalue/GetResponse.proto"
	"proto/swarmio/data/keyvalue/SetRequest.proto"
	"proto/swarmio/data/discovery/Schema.proto"
	"proto/swarmio/data/discovery/Response.proto"
	"proto/swarmio/data/discovery/Request.proto"
	"proto/swarmio/data/telemetry/SubscribeRequest.proto"
	"proto/swarmio/data/telemetry/UnsubscribeRequest.proto"
	"proto/swarmio/data/telemetry/Update.proto"
	"proto/swarmio/data/telemetry/Status.proto"

	# Data helper
	"src/swarmio/data/Helper.cpp"
)

# Add simulator executable target
add_executable(swarmio-simulator
	"src/swarmio/simulator/main.cpp"
	"src/swarmio/simulator/LinearPathTelemetrySimulator.cpp"
	"src/swarmio/simulator/ExampleDevice.cpp"
)

# Add tool executable target
add_executable(swarmio-tool
	"src/swarmio/tool/main.cpp"
	"src/swarmio/tool/Loop.cpp"
	"src/swarmio/tool/Command.cpp"
)

# Add include directories
target_include_directories(swarmio PUBLIC
	$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
	$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
	$<INSTALL_INTERFACE:include>
)
target_include_directories(swarmio-tool PRIVATE
	"include"
)
target_include_directories(swarmio-simulator PRIVATE
	"include"
)

# Add export/import macros
if (MSVC)
	target_compile_definitions(swarmio 
		PRIVATE "SWARMIO_API=__declspec(dllexport)"
		INTERFACE "SWARMIO_API=__declspec(dllimport)"
		PUBLIC "PROTOBUF_USE_DLLS"
	)
else()
	target_compile_definitions(swarmio 
		PRIVATE "SWARMIO_API=__attribute__((visibility(\"default\")))"
		INTERFACE "SWARMIO_API="
		PUBLIC "PROTOBUF_USE_DLLS"
	)
endif()

# Create directory for the files generated by protobuf
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include")

# Generate C++ files for Protobuf definitions
get_target_property(_sources swarmio SOURCES)
foreach(_source ${_sources})

	# Match .proto files
	if(_source MATCHES "^proto/(.+)\.proto$")

		# Build output file names
		set(_outputs
			"${CMAKE_CURRENT_BINARY_DIR}/include/${CMAKE_MATCH_1}.pb.h"
			"${CMAKE_CURRENT_BINARY_DIR}/include/${CMAKE_MATCH_1}.pb.cc"
		)

		# Generate sources
		add_custom_command(
			OUTPUT ${_outputs}
			COMMAND ${TOOL_PROTOC}
			ARGS 
				--cpp_out dllexport_decl=SWARMIO_API:${CMAKE_CURRENT_BINARY_DIR}/include 
				--proto_path ${CMAKE_CURRENT_SOURCE_DIR}/proto 
				${CMAKE_CURRENT_SOURCE_DIR}/${_source}
			DEPENDS
				${_source} 
			COMMENT "Running CPP protocol buffer compiler on ${_source}"
			VERBATIM
		)

		# Add sources to target
		target_sources(swarmio PRIVATE ${_outputs})

	endif()

endforeach()

# Ignore protobuf related warnings
if (MSVC)
	target_compile_options(swarmio PUBLIC
		"/wd4251"
		"/wd4996"
		"/wd4275"
		"/wd4661"
	)
endif()

# Find required packages
find_package(libzmq REQUIRED)
find_package(czmq REQUIRED)
find_package(zyre REQUIRED)
find_package(protobuf REQUIRED)
find_package(g3log REQUIRED)
find_package(replxx REQUIRED)
find_package(readerwriterqueue REQUIRED)
find_package(concurrentqueue REQUIRED)
find_package(Threads REQUIRED)
find_package(libconfig REQUIRED)
find_package(sodium REQUIRED)

# Link libraries
target_link_libraries(swarmio PUBLIC
	${SODIUM_LIBRARIES}
	${PROTOBUF_LIBRARIES}
	${LIBZMQ_LIBRARIES}
	${CZMQ_LIBRARIES}
	${ZYRE_LIBRARIES}
	${G3LOG_LIBRARIES}
	${LIBCONFIG_LIBRARIES}
	Threads::Threads
)
target_link_libraries(swarmio-tool PRIVATE
	${REPLXX_LIBRARIES}
	swarmio
)
target_link_libraries(swarmio-simulator PRIVATE 
	swarmio
)

# Add library include paths
target_include_directories(swarmio PUBLIC
	${PROTOBUF_INCLUDE_DIRS}
	${LIBZMQ_INCLUDE_DIRS}
	${CZMQ_INCLUDE_DIRS}
	${ZYRE_INCLUDE_DIRS}
	${G3LOG_INCLUDE_DIRS}
	${READERWRITERQUEUE_INCLUDE_DIRS}
	${CONCURRENTQUEUE_INCLUDE_DIRS}
	${SODIUM_INCLUDE_DIRS}
	${LIBCONFIG_INCLUDE_DIRS}
)
target_include_directories(swarmio-tool PRIVATE
	${REPLXX_INCLUDE_DIRS}
)

# Use GNUInstallDirs to determine directories
include(GNUInstallDirs)

# Install library
install(
	TARGETS swarmio 
	EXPORT swarmio-config
	RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
	ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
	LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}	 
)

# Install executables
install(
	TARGETS swarmio-simulator swarmio-tool
	RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

# Install headers
install(
	DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
	DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
	FILES_MATCHING 
		PATTERN "*.h"
		PATTERN "swarmio/tool/*" EXCLUDE
		PATTERN "swarmio/simulator/*" EXCLUDE
)

# Install compiled protobuf headers
install(
	DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/"
	DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
	FILES_MATCHING PATTERN "*.h"
)

# Copy test scripts
file(COPY
	${CMAKE_CURRENT_SOURCE_DIR}/src/swarmio/test/test_installer.sh
	${CMAKE_CURRENT_SOURCE_DIR}/src/swarmio/test/logparser.py
	DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
)
