cmake_minimum_required(VERSION 3.28)

project(whale-dev)


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

option(WHL_BUILD_EXAMPLES "Build Whale examples" ON)
option(WHLJS_BUILD_DOCS_GENERATOR "Build documentation generator" OFF)


###############################################################################
# Emscripten

if(EMSCRIPTEN)
  set(EMSCRIPTEN_COMPILE_FLAGS "--use-port=libpng --use-port=zlib --use-port=sdl2 --use-port=boost_headers -s DISABLE_EXCEPTION_CATCHING=0")

  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EMSCRIPTEN_COMPILE_FLAGS}")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EMSCRIPTEN_COMPILE_FLAGS}")
endif()


###############################################################################
# Android

if(ANDROID)
  # WHALEJS_DEPS_DIR should contain builds for all the Android platforms.
  #
  # / WHALEJS_DEPS_DIR
  #   + android-arm64-v8a
  #     + install
  #       + bin
  #       + include
  #       + lib
  #       + share
  #     + install_debug
  #       ...
  #   + android-armeabi-v7a
  #     ...
  #   + android-x86
  #     ...
  #   + android-x86_64
  #     ...

  if(NOT EXISTS "${WHALEJS_DEPS_DIR}/lib")
    set(WHALEJS_DEPS_DIR "${WHALEJS_DEPS_DIR}/android-${ANDROID_ABI}/install")
    if(NOT EXISTS "${WHALEJS_DEPS_DIR}/lib")
      message(FATAL_ERROR "Dependencies not found.")
    endif()
  endif()
  set(CMAKE_FIND_ROOT_PATH "${WHALEJS_DEPS_DIR}")
endif()


###############################################################################
# Submodules

if(NOT EMSCRIPTEN)
  find_package(Boost REQUIRED CONFIG
    COMPONENTS
      filesystem
      program_options
  )
  find_package(PNG REQUIRED)
  find_package(ZLIB REQUIRED)
  find_package(OpenAL REQUIRED CONFIG)
endif()
find_package(GLEW)
find_package(SDL2 CONFIG)
find_package(minizip-ng REQUIRED CONFIG)
find_package(Ogg REQUIRED CONFIG)
find_package(Opus REQUIRED CONFIG)
find_package(OpusFile REQUIRED CONFIG)

include(whale-assets/whale-assets.cmake)

add_subdirectory(whale-core)
add_subdirectory(whale-bmfont)
add_subdirectory(whale-pyxel)
add_subdirectory(whale-sfx)
add_subdirectory(whalejs-duktape)
add_subdirectory(whalejs-common)
add_subdirectory(whalejs)
add_subdirectory(whalejs-core)
add_subdirectory(whalejs-bmfont)
add_subdirectory(whalejs-pyxel)
add_subdirectory(whalejs-sfx)


set(ALL_DEPENDENCY_TARGETS
  PNG::PNG
  ZLIB::ZLIB
)

# Libraries that come with Emscripten and Android by default. Other platforms need to link against them explicitly.
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Emscripten")
  if(NOT ANDROID)
    list(APPEND ALL_DEPENDENCY_TARGETS
      GLEW::GLEW
    )
  endif()

  list(APPEND ALL_DEPENDENCY_TARGETS
    SDL2::SDL2
  )
endif()

set(ALL_SHARED_LIB_TARGETS
  whale-core-sp-shared
  whale-bmfont-sp-shared
  whale-pyxel-sp-shared
  whale-sfx-sp-shared
  whalejs-common
  whalejs-common-dbg
  whalejs-duktape
  whalejs-duktape-dbg
)

set(ALL_RUNTIME_TARGETS
  whale-core-example-canvas
  whale-core-example-hello-world
  whalejs
  whalejs-dbg
)

set(WHALEJS_NO_DEBUG_MODULE_TARGETS
  whalejs-core
  whalejs-bmfont
  whalejs-pyxel
  whalejs-sfx
)

set(WHALEJS_DEBUG_MODULE_TARGETS
  whalejs-core-dbg
  whalejs-bmfont-dbg
  whalejs-pyxel-dbg
  whalejs-sfx-dbg
)

set(ALL_WHALEJS_MODULE_TARGETS
  ${WHALEJS_NO_DEBUG_MODULE_TARGETS}
  ${WHALEJS_DEBUG_MODULE_TARGETS}
)


###############################################################################
# For convenience add dependencies between WhaleJS targets and their modules.

if(EMSCRIPTEN)
  target_link_libraries(whalejs PRIVATE ${WHALEJS_NO_DEBUG_MODULE_TARGETS})
  target_link_libraries(whalejs-dbg PRIVATE ${WHALEJS_DEBUG_MODULE_TARGETS})
else()
  add_dependencies(whalejs ${WHALEJS_NO_DEBUG_MODULE_TARGETS})
  add_dependencies(whalejs-dbg ${WHALEJS_DEBUG_MODULE_TARGETS})
endif()


###############################################################################
# WhaleJS examples

if(MSVC)
  function(whljs_module_examples MODULE_NAME)
    file(GLOB EXAMPLE_DIRS "${MODULE_NAME}/example/*")
    foreach(EXAMPLE_DIR IN LISTS EXAMPLE_DIRS)
      get_filename_component(EXAMPLE_NAME "${EXAMPLE_DIR}" NAME)
      set(FULL_EXAMPLE_NAME "${MODULE_NAME}-${EXAMPLE_NAME}")
      string(REPLACE "_" "-" FULL_EXAMPLE_NAME "${FULL_EXAMPLE_NAME}")
      file(GLOB_RECURSE EXAMPLE_SOURCE_FILES "${EXAMPLE_DIR}/*")
      
      string(REPLACE ";" "\\;" SHARED_LIB_PATHS_ESCAPED "${SHARED_LIB_PATHS}")
      string(REPLACE ";" "\\;" WHLJS_MODULE_PATHS_ESCAPED "${WHLJS_MODULE_PATHS}")
      
      file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${FULL_EXAMPLE_NAME}")
      
      add_custom_target(${FULL_EXAMPLE_NAME}
        DEPENDS whalejs whalejs-core ${MODULE_NAME} ${ARGN}
        SOURCES "${EXAMPLE_SOURCE_FILES}"
        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${FULL_EXAMPLE_NAME}"
        COMMAND "${CMAKE_COMMAND}" -E copy_directory "${WHL_ASSETS_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/whale-assets"
        COMMAND "${CMAKE_COMMAND}" -E copy_directory "${EXAMPLE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/${FULL_EXAMPLE_NAME}"
        COMMAND "${CMAKE_COMMAND}" -E env PATH="${SHARED_LIB_PATHS_ESCAPED}" WHLJS_MODULE_PATH="${WHLJS_MODULE_PATHS_ESCAPED}" WHLJS_STD_LIB_PATH="${WHLJS_STD_LIB_PATH}" "$<TARGET_FILE:whalejs>"
      )
    endforeach()
  endfunction()

  whljs_module_examples(whalejs-pyxel)
endif()


###############################################################################
# NSIS

if (NOT EMSCRIPTEN)

  install(
    TARGETS
      whale-core-sp-shared
      whale-bmfont-sp-shared
      whale-pyxel-sp-shared
      whale-sfx-sp-shared
      whalejs-common
      whalejs-common-dbg
      whalejs-duktape
      whalejs-duktape-dbg
      whalejs
      whalejs-dbg
      ${ALL_SHARED_LIB_TARGETS}
      ${ALL_WHALEJS_MODULE_TARGETS}

    RUNTIME
      DESTINATION .
      COMPONENT whalejs

    LIBRARY
      DESTINATION .
      COMPONENT whalejs
  )

  install(
    TARGETS
      ${ALL_SHARED_LIB_TARGETS}
      ${ALL_WHALEJS_MODULE_TARGETS}

    LIBRARY
      DESTINATION .
      COMPONENT whalejs
  )

  install(
    DIRECTORY
      "whalejs/std"
      "assets/demo"
    
    DESTINATION .
    COMPONENT whalejs
  )

  if(GENERATOR_IS_MULTI_CONFIG)
    list(APPEND BUILD_CONFIG_LIST ${CMAKE_CONFIGURATION_TYPES})
  else()
    list(APPEND BUILD_CONFIG_LIST ${CMAKE_BUILD_TYPE})
  endif()

  foreach(CONFIG_NAME IN LISTS BUILD_CONFIG_LIST)
    string(TOUPPER ${CONFIG_NAME} CONFIG_NAME_UPPER)
    
    get_target_property(BOOST_FILESYSTEM_SHARED_LIB_PATH Boost::filesystem IMPORTED_LOCATION_${CONFIG_NAME_UPPER})
    get_target_property(BOOST_PROGRAM_OPTIONS_SHARED_LIB_PATH Boost::program_options IMPORTED_LOCATION_${CONFIG_NAME_UPPER})
    get_target_property(MINIZIP_SHARED_LIB_PATH MINIZIP::minizip-ng IMPORTED_LOCATION_${CONFIG_NAME_UPPER})
    get_target_property(MINIZIP_SHARED_LIB_SONAME MINIZIP::minizip-ng IMPORTED_SONAME_${CONFIG_NAME_UPPER})
    get_target_property(OGG_SHARED_LIB_PATH Ogg::ogg IMPORTED_LOCATION_${CONFIG_NAME_UPPER})
    get_target_property(OPENAL_SHARED_LIB_PATH OpenAL::OpenAL IMPORTED_LOCATION_${CONFIG_NAME_UPPER})
    get_target_property(OPUS_SHARED_LIB_PATH Opus::opus IMPORTED_LOCATION_${CONFIG_NAME_UPPER})
    get_target_property(OPUSFILE_SHARED_LIB_PATH OpusFile::opusfile IMPORTED_LOCATION_${CONFIG_NAME_UPPER})
    get_target_property(SDL2_SHARED_LIB_PATH SDL2::SDL2 IMPORTED_LOCATION_${CONFIG_NAME_UPPER})

    if(NOT ANDROID)
      get_target_property(GLEW_SHARED_LIB_PATH GLEW::GLEW IMPORTED_LOCATION_${CONFIG_NAME_UPPER})
    endif()

    install(
      FILES
        "LICENSE"

      DESTINATION .
      COMPONENT whalejs
      CONFIGURATIONS ${CONFIG_NAME}
    )

    if(WIN32)
      install(
        FILES
          "${BOOST_FILESYSTEM_SHARED_LIB_PATH}"
          "${BOOST_PROGRAM_OPTIONS_SHARED_LIB_PATH}"
          "${MINIZIP_SHARED_LIB_PATH}"
          "${GLEW_SHARED_LIB_PATH}"
          "${OPENAL_SHARED_LIB_PATH}"
          "${OPUS_SHARED_LIB_PATH}"
          "${OPUSFILE_SHARED_LIB_PATH}"
          "${SDL2_SHARED_LIB_PATH}"
          
        DESTINATION .
        COMPONENT whalejs
        CONFIGURATIONS ${CONFIG_NAME}
      )

      # Needed because of a bug in libogg (https://github.com/xiph/ogg/pull/72).
      install(
        FILES
          "${OGG_SHARED_LIB_PATH}"
          
        DESTINATION .
        COMPONENT whalejs
        CONFIGURATIONS ${CONFIG_NAME}
        RENAME "ogg.dll"
      )
    else()
      install(
        FILES
          "${MINIZIP_SHARED_LIB_PATH}"
          
        DESTINATION .
        COMPONENT whalejs
        CONFIGURATIONS ${CONFIG_NAME}
        RENAME "${MINIZIP_SHARED_LIB_SONAME}"
      )
    endif()
  endforeach()

else() # NOT EMSCRIPTEN

  install(
    FILES
      "LICENSE"

    DESTINATION .
    COMPONENT whalejs
  )

  install(
    DIRECTORY
      "${CMAKE_CURRENT_BINARY_DIR}/whalejs/"

    DESTINATION "${CMAKE_INSTALL_BINDIR}"
    COMPONENT whalejs

    FILES_MATCHING
      PATTERN "*.js"
      PATTERN "*.wasm"
      PATTERN "*.data"
      PATTERN "*.html"

    PATTERN "CMakeFiles" EXCLUDE
  )

endif() # NOT EMSCRIPTEN

cmake_host_system_information(RESULT OS_NAME QUERY OS_NAME)

if(MINGW)
  if(OS_NAME STREQUAL "Linux")
    install(
      FILES
        "/usr/lib/gcc/x86_64-w64-mingw32/13-win32/libgcc_s_seh-1.dll"
        "/usr/lib/gcc/x86_64-w64-mingw32/13-win32/libstdc++-6.dll"
        "${CMAKE_FIND_ROOT_PATH}/bin/libpng16.dll"
        "${CMAKE_FIND_ROOT_PATH}/bin/libzlib1.dll"

      DESTINATION .
      COMPONENT whalejs
    )
  endif()
endif()

set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")

set(CPACK_NSIS_MENU_LINKS
  "whalejs.exe" "WhaleJS"
  "Uninstall.exe" "Uninstall"
)

set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
set(CPACK_NSIS_MODIFY_PATH ON)

set(CPACK_NSIS_INSTALLED_ICON_NAME "whalejs.exe")

set(WHLJS_NSIS_ICON "${WHL_ASSETS_DIR}/whalejs.ico")
cmake_path(NATIVE_PATH WHLJS_NSIS_ICON WHLJS_NSIS_ICON)
string(REPLACE "\\" "\\\\" WHLJS_NSIS_ICON "${WHLJS_NSIS_ICON}")

set(WHLJS_NSIS_LOGO "${CMAKE_CURRENT_LIST_DIR}/assets/nsis/whalejs-logo.bmp")
cmake_path(NATIVE_PATH WHLJS_NSIS_LOGO WHLJS_NSIS_LOGO)
string(REPLACE "\\" "\\\\" WHLJS_NSIS_LOGO "${WHLJS_NSIS_LOGO}")

set(WHLJS_NSIS_HEADER "${CMAKE_CURRENT_LIST_DIR}/assets/nsis/whalejs-header.bmp")
cmake_path(NATIVE_PATH WHLJS_NSIS_HEADER WHLJS_NSIS_HEADER)
string(REPLACE "\\" "\\\\" WHLJS_NSIS_HEADER "${WHLJS_NSIS_HEADER}")

set(WHLJS_LICENSE_FILE "${CMAKE_CURRENT_LIST_DIR}/LICENSE")
cmake_path(NATIVE_PATH WHLJS_LICENSE_FILE WHLJS_LICENSE_FILE)
string(REPLACE "\\" "\\\\" WHLJS_LICENSE_FILE "${WHLJS_LICENSE_FILE}")

set(CPACK_NSIS_MUI_ICON "${WHLJS_NSIS_ICON}")
set(CPACK_NSIS_MUI_UNIICON "${WHLJS_NSIS_ICON}")
set(CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP "${WHLJS_NSIS_LOGO}")
set(CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP "${WHLJS_NSIS_LOGO}")
set(CPACK_NSIS_MUI_HEADERIMAGE "${WHLJS_NSIS_HEADER}")
set(CPACK_RESOURCE_FILE_LICENSE "${WHLJS_LICENSE_FILE}")

set(CPACK_PACKAGE_NAME "WhaleJS")
set(CPACK_PACKAGE_VENDOR "whalejs.org")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "WhaleJS Framework")
set(CPACK_PACKAGE_VERSION "0.4.0")
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "4")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "WhaleJS")

set(CPACK_COMPONENTS_ALL whalejs)
set(CPACK_COMPONENT_WHALEJS_DISPLAY_NAME "WhaleJS")
set(CPACK_COMPONENT_WHALEJS_DESCRIPTION "WhaleJS Framework")


###############################################################################
# Android

if(ANDROID)
  set(ANDROID_BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/android")

  add_custom_target(package-android
    DEPENDS whalejs
    WORKING_DIRECTORY "${ANDROID_BIN_DIR}"
    COMMAND "${CMAKE_COMMAND}" -E copy_directory "android-project" "${ANDROID_BIN_DIR}"
  )
endif()


###############################################################################
# Source

# TODO
set(CPACK_SOURCE_ZIP OFF)
set(CPACK_SOURCE_7Z OFF)


###############################################################################
# CPack

# CPack must always be included last!
include(CPack)
