cmake_minimum_required(VERSION 3.20.3)

project(lidarview-superbuild)

# Set a default build type if none was specified
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to 'Release' as none was specified.")
  set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
  # Set the possible values of build type for cmake-gui
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
    "MinSizeRel" "RelWithDebInfo")
endif()

list(INSERT CMAKE_MODULE_PATH 0
  "${CMAKE_CURRENT_LIST_DIR}/pvsb/cmake"
  "${CMAKE_CURRENT_LIST_DIR}/cmake")

macro (superbuild_setup_variables)
  include(SuperbuildVersionMacros)

  # Determine paraview version
  if (paraview_SOURCE_SELECTION STREQUAL "git")
    # Default value should be updated with the ParaView version needed by LidarView
    set(PARAVIEW_VERSION_DEFAULT "6.0.1"
      CACHE STRING "The default version of ParaView to use if it cannot be detected")
    mark_as_advanced(PARAVIEW_VERSION_DEFAULT)
    set(paraview_default_version "${PARAVIEW_VERSION_DEFAULT}")
  elseif (paraview_SOURCE_SELECTION STREQUAL "source")
    # If it is a git repo, we'll get it that way, otherwise we will look at the
    # `version.txt` in the checkout.
    set(paraview_default_version "")
  else ()
    # The selection is the version number; use it.
    set(paraview_default_version "${paraview_SOURCE_SELECTION}")
  endif()
  set(GIT_FOUND_save "${GIT_FOUND}")
  set(GIT_FOUND 0)
  superbuild_set_version_variables(paraview "${paraview_default_version}" "paraview-version.cmake" "version.txt")
  set(GIT_FOUND "${GIT_FOUND_save}")
  set(paraview_version "${paraview_version_major}.${paraview_version_minor}")

  # Determine lidarview (or lidarview based-app) version
  if (lidarview_SOURCE_SELECTION STREQUAL "git")
    # Assuming master; just use the latest version, but let the user set their
    # own version in case it is actually a branch from some other version.
    set(LIDARVIEW_VERSION_DEFAULT "5.2.0"
      CACHE STRING "The default version of LidarView to use if it cannot be detected")
    mark_as_advanced(LIDARVIEW_VERSION_DEFAULT)
    set(lidarview_default_version "${LIDARVIEW_VERSION_DEFAULT}")
  elseif (lidarview_SOURCE_SELECTION STREQUAL "source")
    # If it is a git repo, we'll get it that way, otherwise we will look at the
    # `version.txt` in the checkout.
    set(lidarview_default_version "")
  else ()
    # The selection is the version number; use it.
    set(lidarview_default_version "${lidarview_SOURCE_SELECTION}")
  endif()
  superbuild_set_version_variables(lidarview "${lidarview_default_version}" "lidarview-version.cmake" "version.txt")
  set(lidarview_version "${lidarview_version_major}.${lidarview_version_minor}")
endmacro ()

#------------------------------------------------------------------------------
#SuperBuild Macros

function (superbuild_find_projects var)
  include(ParaViewSuperbuildMacros)

  # Some of these allow using system libraries.
  set(projects
    asio
    boost
    bzip2
    ceres
    cuda
    cudnn
    curl
    cxx11
    cxx14
    cxx17
    eigen
    fastcdr
    fastdds
    ffmpeg
    flann
    foonathan
    fortran
    freetype
    g2o
    gdal
    geotiff
    glog
    gtsam
    hesaisdk
    jsonc
    jsoncpp
    lapack
    leishensdk
    libxml2
    libxslt
    lidarview
    livoxsdk
    lz4
    mcap
    meson
    nanoflann
    ninja
    nlohmannjson
    numpy
    opencv
    opencvcontrib
    openmp
    openxrsdk
    pahoc
    pahocpp
    paraview
    paraviewweb
    paraviewwebglance
    pcap
    pcl
    pclplugin
    pdal
    pkgconf
    png
    proj
    pybind11
    python3
    pythonaiohttp
    pythonaiosignal
    pythonasynctimeout
    pythonattrs
    pythonbeniget
    pythonchardet
    pythoncharsetnormalizer
    pythoncython
    pythonflitcore
    pythonfrozenlist
    pythongast
    pythonhatchfancypypireadme
    pythonhatchling
    pythonhatchvcs
    pythonidna
    pythonmesonpython
    pythonmultidict
    pythonpackaging
    pythonpathspec
    pythonpluggy
    pythonply
    pythonpygments
    pythonpyprojectmetadata
    pythonpythran
    pythonsetuptools
    pythonsetuptoolsscm
    pythontomli
    pythontroveclassifiers
    pythontypingextensions
    pythonwheel
    pythonwslinkasync
    pythonyarl
    qhull
    qt
    qt5
    qt6
    robosensesdk
    ros2io
    scipy
    scs
    slam
    sqlite
    tbb
    tiff
    tins
    tinyxml2
    velodynesdk
    vrpn
    xerces
    xz
    yaml
    zlib
    zstd
  )

  if (WIN32)
    list(APPEND projects
      flexbison
      npcap
      openvr
      pywin32)
  endif()

  if (UNIX)
    list(APPEND projects
      ffi)

    if (NOT APPLE)
      list(APPEND projects
        bimprocessing
        clipper
        fontconfig
        gperf
        libusb
        teaserpp
        utillinux)
    endif()
  endif()

  foreach (_add_sb_folder IN LISTS SUPERBUILD_ADDITIONAL_FOLDERS)
    if (EXISTS "${SUPERBUILD_ADDITIONAL_FOLDERS}/projects.cmake")
      include("${SUPERBUILD_ADDITIONAL_FOLDERS}/projects.cmake")
    else ()
      message(WARNING "An additional superbuild folder was specified: ${_add_sb_folder},"
             " but it does not contain in projects.cmake file. No projects have been added for this folder.")
    endif ()
  endforeach()

  set("${var}"
    ${projects}
    PARENT_SCOPE)
endfunction ()

function (superbuild_sanity_check)
  if (qt5_enabeld AND qt6_enabled)
    message(SEND_ERROR "Only one of Qt5 and Qt6 may be enabled")
  endif ()
endfunction ()

function (superbuild_add_packaging)

  # Qt logic from pvsb
  if (qt5_enabled AND (USE_SYSTEM_qt5 OR APPLE OR WIN32))
    list(APPEND superbuild_export_variables
      Qt5_DIR)
    find_package(Qt5 QUIET REQUIRED COMPONENTS Core)
    set(qt5_version "${Qt5Core_VERSION_MAJOR}.${Qt5Core_VERSION_MINOR}")
  else ()
    set(qt5_version "${qt5_SOURCE_SELECTION}")
  endif ()
  list(APPEND superbuild_export_variables
    qt5_version)

  if (qt6_enabled)
    list(APPEND superbuild_export_variables
      Qt6_DIR)
    find_package(Qt6 QUIET REQUIRED COMPONENTS Core)
    set(qt6_version "${Qt6Core_VERSION_MAJOR}.${Qt6Core_VERSION_MINOR}")
  endif ()
  list(APPEND superbuild_export_variables
    qt6_version)

  foreach (_add_sb_folder IN LISTS SUPERBUILD_ADDITIONAL_FOLDERS)
    if (EXISTS "${SUPERBUILD_ADDITIONAL_FOLDERS}/bundle.cmake")
      list(APPEND lidarview_additional_bundle_files
        "${SUPERBUILD_ADDITIONAL_FOLDERS}/bundle.cmake")
    endif ()
  endforeach()

  # pass some variables that are required for packaging step:
  list(APPEND superbuild_export_variables
    paraview_version
    lidarview_additional_plugins
    lidarview_additional_bundle_files)

  # Packaging tests
  if (WIN32)
    set(generators
      ZIP
      WIX)
  elseif (APPLE)
    set(generators
      DragNDrop)
  else ()
    set(generators
      TGZ)
  endif ()
  list(GET generators 0 default_generator)
  foreach (generator IN LISTS generators)
      superbuild_add_extra_package_test(lidarview "${generator}"
      LABELS  "LidarView" # does not have to be ${SOFTWARE_NAME} I think, it is currently not available here
      TIMEOUT 6400)
  endforeach ()

  foreach (_add_sb_folder IN LISTS SUPERBUILD_ADDITIONAL_FOLDERS)
    if (EXISTS "${SUPERBUILD_ADDITIONAL_FOLDERS}/package.cmake")
      include("${SUPERBUILD_ADDITIONAL_FOLDERS}/package.cmake")
    endif ()
  endforeach()
endfunction ()

function (superbuild_add_tests)
  add_subdirectory("${CMAKE_SOURCE_DIR}/tests" "${CMAKE_BINARY_DIR}/tests")
endfunction ()

# Dependencies Options
option(ENABLE_all "Enable all optional dependencies like pcl, ceres, opencv, ..." OFF)
if (ENABLE_all)
  set(ENABLE_opencv ON CACHE BOOL "enable OpenCV")
  set(ENABLE_ceres ON CACHE BOOL "enable Ceres")
  set(ENABLE_pcl ON CACHE BOOL "enable PCL")
  set(ENABLE_nanoflann ON CACHE BOOL "enable nanoflann")
  set(ENABLE_g2o ON CACHE BOOL "enable G2O")
  set(ENABLE_gtsam ON CACHE BOOL "enable Gtsam")
  set(ENABLE_teaserpp ON CACHE BOOL "enable Teaser++")
endif(ENABLE_all)

# Qt logic from pvsb
# Differences:
#   - add qtspeech
set(qt5_skip_modules
  qtspeech
  qtconnectivity
  qtgamepad
  qtlocation
  qtsensors
  qtserialport
  qtwayland
  qtwebchannel
  qtwebengine
  qtwebsockets)
set(_superbuild_qt5_default_selection "5.15")
set(qt5_ENABLE_SVG ON CACHE INTERNAL "ParaView requires SVG support") # Localisation lib only required for qtwebkit
set(qt6_ENABLE_SVG ON CACHE INTERNAL "ParaView requires SVG support")

# Config Boost
set(boost_libraries
  atomic
  date_time
  filesystem
  iostreams
  program_options
  thread
  timer
  chrono
  regex
  serialization
  system)
set(boost_extra_options
  "-sNO_BZIP2=1")

# Check if some Boost environment variables could hide local Boost install
if (NOT USE_SYSTEM_boost AND (DEFINED ENV{BOOSTROOT} OR DEFINED ENV{BOOST_ROOT} OR DEFINED ENV{BOOST_LIBRARYDIR} OR DEFINED ENV{BOOST_INCLUDEDIR}))
  message(WARNING "Some Boost environment variables are set and may hide the local superbuild Boost installation. "
                  "Consider enabling USE_SYSTEM_boost flag or unsetting the following environement variables :\n"
                  " BOOSTROOT=$ENV{BOOSTROOT}\n BOOST_ROOT=$ENV{BOOST_ROOT}\n BOOST_LIBRARYDIR=$ENV{BOOST_LIBRARYDIR}\n BOOST_INCLUDEDIR=$ENV{BOOST_INCLUDEDIR}")
endif()

set(SUPERBUILD_ADDITIONAL_FOLDERS ""
  CACHE PATH "A semicolon separated list of folders to check for additional superbuild infrastructure")
mark_as_advanced(SUPERBUILD_ADDITIONAL_FOLDERS)

# Put SUPERBUILD_ADDITIONAL_FOLDERS first so that they override any behavior or versions
list(APPEND _sb_folders ${SUPERBUILD_ADDITIONAL_FOLDERS})

# Add ParaView superbuild projects
list(APPEND _sb_folders
  "${CMAKE_CURRENT_LIST_DIR}/pvsb"
  "${CMAKE_CURRENT_LIST_DIR}")

# For each folder
foreach (_sb_folder IN LISTS _sb_folders)
  # Add versions.cmake if it exists
  if (EXISTS "${_sb_folder}/versions.cmake")
    list(APPEND superbuild_version_files "${_sb_folder}/versions.cmake")
  endif ()

  # Add the projects folder to check for projects
  list(APPEND superbuild_project_roots "${_sb_folder}/projects")

  # Add CTestCustom.cmake if it exists
  if (EXISTS "${_sb_folder}/cmake/CTestCustom.cmake")
    list(APPEND superbuild_ctest_custom_files "${_sb_folder}/cmake/CTestCustom.cmake")
  endif ()
endforeach()

# set the default arguments used for "git clone"
set(_git_clone_arguments_default --progress)

# set the default projects
set(_superbuild_default_cxx11 ON)
set(_superbuild_default_lidarview ON)
set(_superbuild_default_qt ON)
set(_superbuild_default_qt6 ON)
set(_superbuild_default_libxslt ON)
set(_superbuild_default_python3 ON)

# set the default for qt5 to be 5.15
set(_superbuild_qt5_default_selection "5.15")

# Force qt SVG support, so ParaView can use SVG icons
set(qt5_ENABLE_SVG ON CACHE INTERNAL "ParaView requires SVG support")

# Force build shared libs
set(_superbuild_no_static_everywhere ON)
set(BUILD_SHARED_LIBS ON)

mark_as_advanced(paraview_GIT_TAG)
mark_as_advanced(paraview_GIT_REPOSITORY)

set(paraview_GIT_TAG "v6.0.1" CACHE STRING "")

# Set ParaView arguments
set(PARAVIEW_EXTRA_CMAKE_ARGUMENTS
  "-DPARAVIEW_PLUGIN_ENABLE_ParFlow=NO" # Version missmatch with nlohmannjson, should be removed when paraview is updated
  "-DPARAVIEW_PLUGIN_dsp_enable_audio_player=NO" # Cannot be build on windows CI
  "-DVTK_MODULE_ENABLE_VTK_libproj=YES"
  "-DVTK_MODULE_ENABLE_VTK_InteractionImage=YES"  # For PCL
  "-DVTK_MODULE_ENABLE_VTK_RenderingLOD=YES"      # For PCL
  "-DVTK_MODULE_ENABLE_VTK_ImagingMorphological=YES" # For LidarView filters
  "-DVTK_MODULE_USE_EXTERNAL_VTK_png=OFF"         # Avoid crash with external png on windows
  CACHE INTERNAL "")

# common-superbuild
add_subdirectory(pvsb/superbuild "superbuild")
