cmake_minimum_required(VERSION 3.5)
cmake_policy(SET CMP0048 NEW)

project(ADLjack VERSION "1.1.0" LANGUAGES C CXX)

list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")

set(CMAKE_CXX_STANDARD 11)
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")

if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$")
  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)$")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()

option(PREFER_PDCURSES "Prefer PDCurses as terminal library" "OFF")
option(ENABLE_VIRTUALMIDI "Enable virtualMIDI for Windows" "OFF")
option(USE_SYSTEM_RTAUDIO "Use system libraries for RtAudio" "OFF")
option(USE_SYSTEM_RTMIDI "Use system libraries for RtMidi" "OFF")
set(ENABLE_GETTEXT "" CACHE STRING "Enable gettext")

set(WITH_MIDI_SEQUENCER OFF CACHE STRING "")
set(WITH_MUS_SUPPORT OFF CACHE STRING "")
set(WITH_XMI_SUPPORT OFF CACHE STRING "")
set(libADLMIDI_STATIC ON CACHE STRING "")
set(libADLMIDI_SHARED OFF CACHE STRING "")
set(libOPNMIDI_STATIC ON CACHE STRING "")
set(libOPNMIDI_SHARED OFF CACHE STRING "")
add_subdirectory("thirdparty/libADLMIDI" EXCLUDE_FROM_ALL)
add_subdirectory("thirdparty/libOPNMIDI" EXCLUDE_FROM_ALL)
add_subdirectory("thirdparty/flatbuffers" EXCLUDE_FROM_ALL)

include(FindPkgConfig)
include(CheckFunctionExists)

find_package(Threads REQUIRED)

if(ENABLE_GETTEXT STREQUAL "")
  find_package(Intl)
  find_package(Iconv)
  find_package(Gettext)
  if(Intl_FOUND AND Iconv_FOUND AND GETTEXT_FOUND)
    set(ENABLE_GETTEXT "ON" CACHE STRING "Enable gettext" FORCE)
  endif()
endif()
if(ENABLE_GETTEXT)
  find_package(Intl REQUIRED)
  find_package(Iconv REQUIRED)
  find_package(Gettext REQUIRED)
endif()

set(CURSES_FOUND FALSE)
set(PDCURSES_FOUND FALSE)
if(NOT PREFER_PDCURSES)
  find_path(CURSES_INCLUDE_DIR "curses.h")
  message(STATUS "Curses include dir: ${CURSES_INCLUDE_DIR}")
  find_library(CURSES_LIBRARY NAMES "ncursesw" "cursesw")
  message(STATUS "Curses library: ${CURSES_LIBRARY}")
  if(CURSES_INCLUDE_DIR AND CURSES_LIBRARY)
    set(CURSES_FOUND TRUE)
  else()
    set(CURSES_FOUND FALSE)
  endif()
endif()
if(PREFER_PDCURSES OR NOT CURSES_FOUND)
  find_library(SDL2_LIBRARY "SDL2")
  find_path(SDL2_INCLUDE_DIR_PREFIX "SDL2/SDL.h")
  if(SDL2_LIBRARY)
    message(STATUS "Found SDL2 library: ${SDL2_LIBRARY}")
  else()
    message(STATUS "Could not find the SDL2 library")
  endif()
  if(SDL2_INCLUDE_DIR_PREFIX)
    message(STATUS "Found SDL2 headers: ${SDL2_INCLUDE_DIR_PREFIX}")
  else()
    message(STATUS "Could not find the SDL2 headers")
  endif()
  if(NOT SDL2_INCLUDE_DIR_PREFIX OR NOT SDL2_LIBRARY)
    message(FATAL_ERROR "cannot find SDL2")
  endif()
  add_library(SDL2 INTERFACE)
  target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR_PREFIX}/SDL2")
  target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
  #
  file(GLOB PDCURSES_SOURCES
    "thirdparty/PDCurses/sdl2/*.c"
    "thirdparty/PDCurses/pdcurses/*.c")
  add_library(pdcurses STATIC ${PDCURSES_SOURCES})
  target_include_directories(pdcurses PUBLIC "thirdparty/PDCurses")
  target_link_libraries(pdcurses PUBLIC SDL2)
  #
  check_function_exists("vsnprintf" HAVE_VSNPRINTF)
  check_function_exists("vsscanf" HAVE_VSSCANF)
  if(HAVE_VSNPRINTF)
    target_compile_definitions(pdcurses PUBLIC "HAVE_VSNPRINTF")
  endif()
  if(HAVE_VSSCANF)
    target_compile_definitions(pdcurses PUBLIC "HAVE_VSSCANF")
  endif()
  set(PDCURSES_FOUND TRUE)
endif()
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
  pkg_check_modules(JACK "jack")
  pkg_check_modules(PULSEAUDIO "libpulse-simple")
  if(ENABLE_VIRTUALMIDI)
    message(FATAL_ERROR "virtualMIDI is only available on Windows")
  endif()
else()
  set(JACK_FOUND FALSE)
  set(PULSEAUDIO_FOUND FALSE)
endif()

set(DESKTOP_FILE_EXTRA "")
if(CURSES_FOUND)
  set(DESKTOP_FILE_EXTRA "Terminal=true\n")
endif()

if(JACK_FOUND)
  pkg_check_modules(LIBLO "liblo")
endif()

set(Iconv_DEFINITIONS)
if(Iconv_FOUND AND CMAKE_SYSTEM_NAME STREQUAL "Windows")
  list(APPEND Iconv_DEFINITIONS "WINICONV_CONST=")
endif()

check_function_exists("mlockall" HAVE_MLOCKALL)

if(USE_SYSTEM_RTAUDIO)
  pkg_check_modules(SYSTEM_RTAUDIO "rtaudio" REQUIRED)
endif()
if(USE_SYSTEM_RTMIDI)
  pkg_check_modules(SYSTEM_RTMIDI "rtmidi" REQUIRED)
endif()

message("!! Feature summary:")
macro(print_feature NAME VAR)
  if(${VAR})
    message("!!   ${NAME}: YES")
  else()
    message("!!   ${NAME}: NO")
  endif()
endmacro()
print_feature("Curses" CURSES_FOUND)
print_feature("PdCurses" PDCURSES_FOUND)
print_feature("Jack" JACK_FOUND)
print_feature("LibLO" LIBLO_FOUND)
print_feature("Pulseaudio" PULSEAUDIO_FOUND)
print_feature("virtualMIDI" ENABLE_VIRTUALMIDI)
print_feature("RtAudio system library" USE_SYSTEM_RTAUDIO)
print_feature("RtMidi system library" USE_SYSTEM_RTMIDI)
print_feature("gettext" ENABLE_GETTEXT)
print_feature("POSIX mlockall" HAVE_MLOCKALL)

set(adl_sources
  "sources/tui.cc"
  "sources/tui_channels.cc"
  "sources/tui_fileselect.cc"
  "sources/insnames.cc"
  "sources/player_traits.cc"
  "sources/player.cc"
  "sources/i18n.cc"
  "sources/common.cc")
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  list(APPEND adl_sources
    "sources/winmm_dialog.cc"
    "sources/winmm_dialog.rc"
    "sources/win_application.rc")
endif()

## Jack version
if(NOT JACK_FOUND)
  message(WARNING "Jack not found. Not building ADL-jack.")
else()
  add_executable(adljack WIN32 "sources/jackmain.cc" ${adl_sources})
  target_compile_definitions(adljack PRIVATE "ADLJACK_PREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
  target_include_directories(adljack PRIVATE ${JACK_INCLUDE_DIRS})
  link_directories(${JACK_LIBRARY_DIRS})
  target_link_libraries(adljack PRIVATE ADLMIDI_static OPNMIDI_static ring_buffer ${JACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
  if(CURSES_FOUND)
    target_compile_definitions(adljack PRIVATE "ADLJACK_USE_CURSES")
    target_include_directories(adljack PRIVATE "${CURSES_INCLUDE_DIR}")
    target_link_libraries(adljack PRIVATE "${CURSES_LIBRARY}")
  elseif(PDCURSES_FOUND)
    target_compile_definitions(adljack PRIVATE "ADLJACK_USE_CURSES")
    target_compile_definitions(adljack PRIVATE "ADLJACK_USE_GRAPHIC_TERMINAL")
    target_link_libraries(adljack PRIVATE pdcurses)
  endif()
  if(LIBLO_FOUND)
    target_compile_definitions(adljack PRIVATE "ADLJACK_USE_NSM")
    target_include_directories(adljack PRIVATE "thirdparty/nonlib")
    target_include_directories(adljack PRIVATE ${LIBLO_INCLUDE_DIRS})
    target_link_libraries(adljack PRIVATE ${LIBLO_LIBRARIES})
    link_directories(${LIBLO_LIBRARY_DIRS})
    target_sources(adljack PRIVATE "sources/state.cc")
    target_link_libraries(adljack PRIVATE flatbuffers)
    target_include_directories(adljack PRIVATE "thirdparty/flatbuffers/include")
  endif()
  if(ENABLE_GETTEXT)
    target_compile_definitions(adljack PRIVATE "ADLJACK_I18N" ${Iconv_DEFINITIONS})
    target_include_directories(adljack PRIVATE ${Intl_INCLUDE_DIRS} ${Iconv_INCLUDE_DIRS})
    target_link_libraries(adljack PRIVATE ${Intl_LIBRARIES} ${Iconv_LIBRARIES})
  endif()
  if(HAVE_MLOCKALL)
    target_compile_definitions(adljack PRIVATE "ADLJACK_HAVE_MLOCKALL")
  endif()
  install(TARGETS adljack DESTINATION "bin")
  if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
    configure_file("resources/adljack.desktop.in" "adljack.desktop" @ONLY)
    install(FILES "${CMAKE_BINARY_DIR}/adljack.desktop" DESTINATION "share/applications")
  endif()
endif()

## RtMidi library
if(USE_SYSTEM_RTMIDI)
  add_library(RtMidi INTERFACE)
  target_include_directories(RtMidi INTERFACE ${SYSTEM_RTMIDI_INCLUDE_DIRS})
  target_link_libraries(RtMidi INTERFACE ${SYSTEM_RTMIDI_LIBRARIES})
else()
  include(RtMidi)
endif()

## RtAudio library
if(USE_SYSTEM_RTAUDIO)
  add_library(RtAudio INTERFACE)
  target_include_directories(RtAudio INTERFACE ${SYSTEM_RTAUDIO_INCLUDE_DIRS})
  target_link_libraries(RtAudio INTERFACE ${SYSTEM_RTAUDIO_LIBRARIES})
else()
  include(RtAudio)
endif()

## Ring buffer
add_library(ring_buffer STATIC "thirdparty/ring-buffer/sources/ring_buffer.cc")
target_include_directories(ring_buffer PUBLIC "thirdparty/ring-buffer/include")

## Cross platform version
add_executable(adlrt WIN32 "sources/rtmain.cc" ${adl_sources})
target_compile_definitions(adlrt PRIVATE "ADLJACK_PREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
target_link_libraries(adlrt PRIVATE ADLMIDI_static OPNMIDI_static ring_buffer RtAudio RtMidi ${CMAKE_THREAD_LIBS_INIT})
if(CURSES_FOUND)
  target_compile_definitions(adlrt PRIVATE "ADLJACK_USE_CURSES")
  target_include_directories(adlrt PRIVATE "${CURSES_INCLUDE_DIR}")
  target_link_libraries(adlrt PRIVATE "${CURSES_LIBRARY}")
elseif(PDCURSES_FOUND)
  target_compile_definitions(adlrt PRIVATE "ADLJACK_USE_CURSES")
  target_compile_definitions(adlrt PRIVATE "ADLJACK_USE_GRAPHIC_TERMINAL")
  target_link_libraries(adlrt PRIVATE pdcurses)
endif()
if(ENABLE_VIRTUALMIDI)
  target_compile_definitions(adlrt PRIVATE "ADLJACK_ENABLE_VIRTUALMIDI")
endif()
if(ENABLE_GETTEXT)
  target_compile_definitions(adlrt PRIVATE "ADLJACK_I18N" ${Iconv_DEFINITIONS})
  target_include_directories(adlrt PRIVATE ${Intl_INCLUDE_DIRS} ${Iconv_INCLUDE_DIRS})
  target_link_libraries(adlrt PRIVATE ${Intl_LIBRARIES} ${Iconv_LIBRARIES})
endif()
if(HAVE_MLOCKALL)
  target_compile_definitions(adlrt PRIVATE "ADLJACK_HAVE_MLOCKALL")
endif()
install(TARGETS adlrt DESTINATION "bin")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  configure_file("resources/adlrt.desktop.in" "adlrt.desktop" @ONLY)
  install(FILES "${CMAKE_BINARY_DIR}/adlrt.desktop" DESTINATION "share/applications")
endif()

## Haiku version
if(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
  add_executable(adlhaiku WIN32 "sources/haikumain.cc" ${adl_sources})
  target_compile_definitions(adlhaiku PRIVATE "ADLJACK_PREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
  find_library(MEDIA_KIT_LIBRARY "media")
  find_library(MIDI2_KIT_LIBRARY "midi2")
  target_link_libraries(adlhaiku PRIVATE ADLMIDI_static OPNMIDI_static ring_buffer "${MEDIA_KIT_LIBRARY}" "${MIDI2_KIT_LIBRARY}" ${CMAKE_THREAD_LIBS_INIT})
  if(CURSES_FOUND)
    target_compile_definitions(adlhaiku PRIVATE "ADLJACK_USE_CURSES")
    target_include_directories(adlhaiku PRIVATE "${CURSES_INCLUDE_DIR}")
    target_link_libraries(adlhaiku PRIVATE "${CURSES_LIBRARY}")
  elseif(PDCURSES_FOUND)
    target_compile_definitions(adlhaiku PRIVATE "ADLJACK_USE_CURSES")
    target_compile_definitions(adlhaiku PRIVATE "ADLJACK_USE_GRAPHIC_TERMINAL")
    target_link_libraries(adlhaiku PRIVATE pdcurses)
  endif()
  if(ENABLE_GETTEXT)
    target_compile_definitions(adlhaiku PRIVATE "ADLJACK_I18N" ${Iconv_DEFINITIONS})
    target_include_directories(adlhaiku PRIVATE ${Intl_INCLUDE_DIRS} ${Iconv_INCLUDE_DIRS})
    target_link_libraries(adlhaiku PRIVATE ${Intl_LIBRARIES} ${Iconv_LIBRARIES})
  endif()
endif()

## Data files
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  install(FILES "${CMAKE_SOURCE_DIR}/resources/adl.ico" DESTINATION "icons")
  install(FILES "${CMAKE_SOURCE_DIR}/resources/opn.ico" DESTINATION "icons")
  install(DIRECTORY "${CMAKE_SOURCE_DIR}/thirdparty/libADLMIDI/fm_banks/wopl_files/" DESTINATION "banks/wopl_files")
  install(DIRECTORY "${CMAKE_SOURCE_DIR}/thirdparty/libOPNMIDI/fm_banks/" DESTINATION "banks/wopn_files")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  install(FILES "${CMAKE_SOURCE_DIR}/resources/adl.png" DESTINATION "share/pixmaps" RENAME "adljack.png")
  install(FILES "${CMAKE_SOURCE_DIR}/resources/opn.png" DESTINATION "share/pixmaps" RENAME "opnjack.png")
  install(DIRECTORY "${CMAKE_SOURCE_DIR}/thirdparty/libADLMIDI/fm_banks/wopl_files/" DESTINATION "share/adljack/wopl_files")
  install(DIRECTORY "${CMAKE_SOURCE_DIR}/thirdparty/libOPNMIDI/fm_banks/" DESTINATION "share/adljack/wopn_files")
endif()

## Translations
if(ENABLE_GETTEXT)
  set(TRANSLATIONS "fr")
  foreach(translation ${TRANSLATIONS})
    gettext_process_po_files("${translation}" ALL INSTALL_DESTINATION "share/locale" PO_FILES
      "po/${translation}/adljack.po"
      "po/${translation}/adljack_inst.po"
      "po/${translation}/adljack_perc.po"
      "po/${translation}/adljack_ex.po")
  endforeach()
endif()

## Packaging
include(CPackLists.txt)
