cmake_minimum_required(VERSION 3.27)
project(GeneralDichotomy)

# Linux-only support
if(NOT LINUX)
  message(FATAL_ERROR "Only Linux systems are currently supported.")
endif()

# examples can be implemented with dependencies from git repos
include(FetchContent)

# Options
OPTION(CDD_BACKEND_SUPPORT  "support for CDD backend [default:on]" ON)
OPTION(PPL_BACKEND_SUPPORT  "support for PPL backend [default:off]" OFF)

OPTION(BUILD_PYGDICHOTOMY  "Build the generalDichotomy python binding [default:off]" OFF)
OPTION(PYGDICHOTOMY_RELEASE "Release mode for pygeneraldichotomy packaging [default:off]")

OPTION(EXAMPLE_LAP_TB2  "Build linear assignment example with toulbar2 solver [default:off]" OFF)
OPTION(EXAMPLE_LAP_ORTOOLS  "Build linear assignment example with ortools solver [default:off]" OFF)
OPTION(EXAMPLE_CPLEX "Build cplex interface example [default:off]" OFF)
OPTION(EXAMPLE_TSP_ORTOOLS "Build tsp example with ortools solver [default:off]" OFF)
OPTION(EXAMPLE_KP_ORTOOLS "Build knapsack example with ortools solver [default:off]" OFF)

set(lib_sources "src/backend_cdd.cpp"
                "src/basesolver.hpp"
                "src/gdtypes.hpp"
                "src/general_dichotomy.hpp"
                "src/utils.cpp"
                "src/weight.hpp"
                "src/backend_ppl.cpp"
                "src/gdexception.hpp"
                "src/general_dichotomy.cpp"
                "src/result.hpp"
                "src/utils.hpp"
)

# add a symbolic link of the sources in build dir for use with cmake
MAKE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR}/src)
FILE(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src/gdichotomy SYMBOLIC)

# build type
IF(NOT CMAKE_BUILD_TYPE)
  SET(CMAKE_BUILD_TYPE Release CACHE STRING
      "Choose the build type, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE)
ENDIF(NOT CMAKE_BUILD_TYPE)

# cmake scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

## dependencies (polytope computation libraries)

# cdd library
SET(BACKEND_CDD OFF)
if(CDD_BACKEND_SUPPORT)
  find_package(cdd)
  if(NOT CDD_FOUND)
    MESSAGE(WARNING "CDD support set to ON but CDD library was not found")
  else()
    SET(BACKEND_CDD ON)
  endif()
endif()

# ppl library
SET(BACKEND_PPL OFF)
if(PPL_BACKEND_SUPPORT)
  find_package(ppl)
  if(NOT FOUND_PPL)
    MESSAGE(WARNING "PPL support set to ON but PPL library was not found")
  else()
    SET(BACKEND_PPL ON)
  endif()
endif()

if(NOT BACKEND_CDD AND NOT BACKEND_PPL)
  message(FATAL_ERROR "At least one polytope development library must be installed for the compilation (CDD or PPL).")
endif()

###########################
# GeneralDichotomy library
###########################

# config file
MAKE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR}/gdconfig)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/gdconfig.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/gdconfig/gdconfig.hpp)

# library source files
add_library(gdichotomy SHARED ${lib_sources})
target_include_directories(gdichotomy PUBLIC "${CMAKE_BINARY_DIR}/gdconfig")
IF(BACKEND_CDD)
  target_link_libraries(gdichotomy PUBLIC ${CDD_LIBRARY})
ENDIF()
IF(BACKEND_PPL)
  target_link_libraries(gdichotomy PUBLIC ${PPL_LIBRARY} )
ENDIF()
set_target_properties(gdichotomy PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")


###########################
# Python binding
###########################
IF(BUILD_PYGDICHOTOMY)
  file(GLOB_RECURSE src_binding "src/pygdichotomy.cpp")
  add_library(pygdichotomy SHARED ${src_binding} ${lib_sources})

  find_package(Python3 COMPONENTS Interpreter Development)

  message(STATUS "python3 include dir: ${Python3_INCLUDE_DIRS}")
  target_include_directories(pygdichotomy PUBLIC "${CMAKE_BINARY_DIR}/gdconfig" "${CMAKE_BINARY_DIR}/src;${Python3_INCLUDE_DIRS}")

  set_target_properties(pygdichotomy PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/pygeneraldichotomy/")

  IF(BACKEND_CDD)
    target_link_libraries(pygdichotomy PUBLIC ${CDD_LIBRARY})
  ENDIF()
  IF(BACKEND_PPL)
    target_link_libraries(pygdichotomy PUBLIC ${PPL_LIBRARY} )
  ENDIF()

  # release mode: python binding binary is copied into the output pygdichotomy lib dir
  # developer mode: python binding binary is copied into the lib/pygdichotomy dir 
  IF(PYGDICHOTOMY_RELEASE)
    add_custom_command(TARGET pygdichotomy POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
                "${PROJECT_BINARY_DIR}/pygeneraldichotomy/libpygdichotomy.so"
                "${PYGDICHOTOMY_RELEASE}/libpygdichotomy.so"
                BYPRODUCTS "${PYGDICHOTOMY_RELEASE}/libpygdichotomy.so")
  ELSE()
    add_custom_command(TARGET pygdichotomy POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_SOURCE_DIR}/pygeneraldichotomy/pygeneraldichotomy.py" "${PROJECT_BINARY_DIR}/pygeneraldichotomy/pygeneraldichotomy.py")
    add_custom_command(TARGET pygdichotomy POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_SOURCE_DIR}/pygeneraldichotomy/__init__.py" "${PROJECT_BINARY_DIR}/pygeneraldichotomy/__init__.py")
  ENDIF()
 
ENDIF()


###########################
## Examples
###########################

# CPLEX interface [cpp,cplex]
IF(EXAMPLE_CPLEX)
  file(GLOB_RECURSE src_cplex_cpp examples/cplex_cpp_interface/*pp)
  add_executable(example_cplex_cpp ${src_cplex_cpp})
  set_target_properties(example_cplex_cpp PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/examples/")
  target_include_directories(example_cplex_cpp PUBLIC "${CMAKE_BINARY_DIR}/src")
  # cplex library
  file(GLOB CPLEX_DIR "/opt/ibm/ILOG/CPLEX*")
  target_include_directories(example_cplex_cpp PUBLIC "${CPLEX_DIR}/cplex/include" "${CPLEX_DIR}/concert/include")
  target_link_directories(example_cplex_cpp PUBLIC "${CPLEX_DIR}/cplex/lib/x86-64_linux/static_pic/" "${CPLEX_DIR}/concert/lib/x86-64_linux/static_pic/")
  target_link_libraries(example_cplex_cpp PUBLIC gdichotomy)
  target_link_libraries(example_cplex_cpp PUBLIC ilocplex cplex concert)
ENDIF()

# Linear Assignment Problem [cpp,ortools]
IF(EXAMPLE_LAP_ORTOOLS)
  file(GLOB_RECURSE src_lap_cpp_ortools examples/lap_cpp_ortools/*.cpp lap_cpp_ortools/lap*.hpp)
  add_executable(example_lap_cpp_ortools ${src_lap_cpp_ortools})
  set_target_properties(example_lap_cpp_ortools PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/examples/")
  target_include_directories(example_lap_cpp_ortools PUBLIC "${CMAKE_BINARY_DIR}/src")
  # ortools development library
  find_package(ortools)
  target_link_libraries(example_lap_cpp_ortools PUBLIC gdichotomy ${ORTOOLS_LIBRARY})
ENDIF()

# Traveling Salesperson Problem [cpp,ortools]
IF(EXAMPLE_TSP_ORTOOLS)
  file(GLOB_RECURSE src_tsp_ortools examples/tsp_ortools/*pp)
  add_executable(example_tsp_ortools ${src_tsp_ortools})
  set_target_properties(example_tsp_ortools PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/examples/")
  target_include_directories(example_tsp_ortools PUBLIC "${CMAKE_BINARY_DIR}/src")
  find_package(ortools) # ortools development library
  target_link_libraries(example_tsp_ortools PUBLIC gdichotomy ${ORTOOLS_LIBRARY})
ENDIF()

# Knapsack Problem [cpp,ortools]
IF(EXAMPLE_KP_ORTOOLS)
  file(GLOB_RECURSE src_kp_ortools examples/kp_ortools/*pp)
  add_executable(example_kp_ortools ${src_kp_ortools})
  set_target_properties(example_kp_ortools PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/examples/")
  target_include_directories(example_kp_ortools PUBLIC "${CMAKE_BINARY_DIR}/src")
  find_package(ortools) # ortools development library
  target_link_libraries(example_kp_ortools PUBLIC gdichotomy ${ORTOOLS_LIBRARY})
ENDIF()

# Linear Assignment Problem [cpp,toulbar2]
IF(EXAMPLE_LAP_TB2)
  file(GLOB_RECURSE src_lap_cpp_tb2 examples/lap_cpp_tb2/*.cpp lap_cpp_tb2/lap*.hpp)
  add_executable(example_lap_cpp_tb2 ${src_lap_cpp_tb2})
  set_target_properties(example_lap_cpp_tb2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/examples/")
  target_include_directories(example_lap_cpp_tb2 PUBLIC "${CMAKE_BINARY_DIR}/src")
  # toulbar2 library
  option(LIBTB2 ON) # compile libtb2.so
  set(LIBTB2 ON)
  FetchContent_Declare(
    toulbar2
    GIT_REPOSITORY https://github.com/toulbar2/toulbar2.git
    GIT_TAG 20519176b05888c060701724d167b6a39d419639
    OVERRIDE_FIND_PACKAGE)
  FetchContent_MakeAvailable(toulbar2)
  # to be modified
  target_include_directories(example_lap_cpp_tb2 PUBLIC "${CMAKE_BINARY_DIR}/_deps/toulbar2-src/src;${CMAKE_BINARY_DIR}/_deps/toulbar2-build/tb2config")
  add_dependencies(example_lap_cpp_tb2 tb2)
  target_link_libraries(example_lap_cpp_tb2 PUBLIC gdichotomy tb2)
ENDIF()

