# This module install a hook (with `variable_watch()`) on CMAKE_CURRENT_LIST_DIR
#
# That uses the non-documented fact that CMAKE_CURRENT_LIST_DIR is cleared
# by CMake at the end of the configuration process. So, if the value of
# that variable gets empty, that means that CMake has reached the end of
# the configuration.
#
# See https://stackoverflow.com/a/43300621/1728537 for the starting point.
cmake_minimum_required(VERSION 3.12...3.31)

if(CGAL_SKIP_CMAKE_HOOKS)
  return()
endif()
get_property(PROPERTY_CGAL_run_at_the_end_of_configuration_INCLUDED
  GLOBAL PROPERTY CGAL_run_at_the_end_of_configuration_INCLUDED)
if(PROPERTY_CGAL_run_at_the_end_of_configuration_INCLUDED)
  CGAL_install_hooks()
  return()
endif()

function(CGAL_hook_check_targets)
  if(NOT CGAL_CHECK_UNREFERENCES_TARGETS)
    return()
  endif()
  get_property(_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
  set(_list_of_deps)
  set(_special_targets  demos examples tests ALL_CGAL_TARGETS CGAL_Qt6_moc_and_resources uninstall install_FindCGAL)
  foreach(t ${_special_targets})
    if(NOT TARGET ${t})
      continue()
    endif()
    get_property(_deps TARGET ${t} PROPERTY MANUALLY_ADDED_DEPENDENCIES)
    # message("  deps of ${t}: ${_deps}")
    list(APPEND _list_of_deps ${_deps})
  endforeach()
  list(APPEND _list_of_deps ${CGAL_EXECUTABLE_TARGETS})
  # message(STATUS "  all deps: ${_list_of_deps}")
  foreach(target ${_targets})
    # message(STATUS "  new target: ${target}")
    if(${target} IN_LIST _special_targets)
      continue()
    endif()
    if(NOT ${target} IN_LIST _list_of_deps)
      message(AUTHOR_WARNING "  orphan target: ${target}")
    endif()
  endforeach()
endfunction()

function(CGAL_hook_check_unused_cpp_files)
  if(NOT CGAL_CHECK_UNUSED_CPP_FILES)
    return()
  endif()
  get_property(_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
  file(GLOB _cppfiles ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
  if(NOT _targets OR NOT _cppfiles)
    return()
  endif()
  set(_sources)
  foreach(_target ${_targets})
    get_property(_target_type TARGET ${_target} PROPERTY TYPE)
    if(_target_type STREQUAL INTERFACE_LIBRARY)
      continue()
    endif()
    get_property(_target_sources TARGET ${_target} PROPERTY SOURCES)
    list(APPEND _sources ${_target_sources})
  endforeach()
  if(_sources)
    list(REMOVE_ITEM _cppfiles ${_sources})
  endif()
  if(_cppfiles)
    set(_warning "In ${CMAKE_CURRENT_SOURCE_DIR}, the following files are unused:")
    foreach(_cppfile ${_cppfiles})
      set(_warning "${_warning}
  ${_cppfile}")
    endforeach()
    set(_warning  "${_warning}
  ")
    message(AUTHOR_WARNING "${_warning}")
  endif()
endfunction()

function(CGAL_hook_check_CMAKE_BUILD_TYPE)
  # Warn when CMAKE_BUILD_TYPE is empty or Debug
  if(DEFINED CMAKE_BUILD_TYPE AND ( NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") )
    set(keyword WARNING)
    set(type warning)
    if(RUNNING_CGAL_AUTO_TEST OR CGAL_TEST_SUITE)
      # No warning in the CMake test suite, but a status message
      set(keyword)
      set(type notice)
    endif()
    if(NOT CGAL_DO_NOT_WARN_ABOUT_CMAKE_BUILD_TYPE)
      message(${keyword} "\
=======================================================================\n\
CGAL performance notice:\n\
The variable CMAKE_BUILD_TYPE is set to \"${CMAKE_BUILD_TYPE}\". For \
performance reasons, you should set CMAKE_BUILD_TYPE to \"Release\".\n\
Set CGAL_DO_NOT_WARN_ABOUT_CMAKE_BUILD_TYPE to TRUE if you want to \
disable this ${type}.\n\
=======================================================================\
")
    endif()
  endif()
endfunction()

function(CGAL_hook_fix_ctest_depending_on_Qt6)
  get_property(_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
  foreach(_target ${_targets})
    if(NOT TEST "compilation of  ${_target}")
      continue()
    endif()
    get_property(_target_links TARGET ${_target} PROPERTY LINK_LIBRARIES)
    if("CGAL_Qt6" IN_LIST _target_links OR "CGAL::CGAL_Qt6" IN_LIST _target_links OR "CGAL::CGAL_Basic_viewer" IN_LIST _target_links)
      set_property(TEST "compilation of  ${_target}" APPEND PROPERTY FIXTURES_REQUIRED CGAL_Qt6_moc_and_resources_Fixture)
    endif()
    endforeach()
endfunction()

function(CGAL_hook_fix_ctest_dependencies)
  get_property(_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
  # message(STATUS "  ${CMAKE_CURRENT_SOURCE_DIR} targets: ${_targets}")
  foreach(_target ${_targets})
    if(NOT TEST "compilation of  ${_target}")
      continue()
    endif()
    get_property(linked_libraries TARGET "${_target}" PROPERTY LINK_LIBRARIES)
    get_property(deps TARGET "${_target}" PROPERTY MANUALLY_ADDED_DEPENDENCIES)
    list(APPEND deps ${linked_libraries})
    # message("  ${_target} depends on: ${deps}")
    foreach(dep ${deps})
      if(TARGET ${dep} AND NOT dep MATCHES "^CGAL::|^CGAL_|^CGAL$" )
        get_target_property(imported ${dep} IMPORTED)
        if(NOT imported)
          # message(STATUS "The target ${dep} is a dependency of ${_target}.")
          set_property(TEST "compilation of  ${_target}"
            APPEND PROPERTY DEPENDS "compilation of  ${dep}")
        endif()
      endif()
    endforeach()
  endforeach()
endfunction()

function(CGAL_hooks_at_end_of_all_directories)
  CGAL_hook_check_targets()
  CGAL_hook_check_unused_cpp_files()
  if(CGAL_ENABLE_TESTING)
    CGAL_hook_fix_ctest_depending_on_Qt6()
    CGAL_hook_fix_ctest_dependencies()
  endif()
endfunction()

function(CGAL_run_at_the_end_of_configuration variable access value current_list_file stack)
  if(NOT access STREQUAL "MODIFIED_ACCESS")
    return()
  endif()
  if(current_list_file STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt"
        AND NOT current_list_file STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt"
        OR NOT stack STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt"
        AND stack STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt"
        OR stack MATCHES doc/CMakeLists.txt
        OR stack MATCHES demo/Polyhedron/)
      return()
  endif()


  if(NOT current_list_file STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt"
     AND stack STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt")
    CGAL_hooks_at_end_of_all_directories()
  endif()

  if(value)
    # Only do the following at the end of the CMake process, when the
    # value of variable CMAKE_CURRENT_LIST_DIR is changed to the empty
    # string.
    return()
  endif()

  CGAL_hook_check_CMAKE_BUILD_TYPE()

endfunction()

function(CGAL_install_hooks)
  get_property(PROPERTY_CGAL_hooks_installed DIRECTORY PROPERTY CGAL_hooks_installed)
  if(PROPERTY_CGAL_hooks_installed)
    return()
  endif()
  # message(STATUS "Installing hooks in ${CMAKE_CURRENT_SOURCE_DIR}")
  if(CMAKE_VERSION VERSION_LESS 3.19)
    variable_watch("CMAKE_CURRENT_LIST_DIR" CGAL_run_at_the_end_of_configuration)
  else()
    cmake_language(DEFER CALL CGAL_hooks_at_end_of_all_directories)
    if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
      cmake_language(DEFER CALL CGAL_hook_check_CMAKE_BUILD_TYPE)
    endif()
  endif()
  set_property(DIRECTORY PROPERTY CGAL_hooks_installed TRUE)
endfunction()

CGAL_install_hooks()

set_property(GLOBAL PROPERTY CGAL_run_at_the_end_of_configuration_INCLUDED TRUE)
