include(CMakeParseArguments)

# -----------------------------------------------------------------------------
function(explorer_source_group GROUP_ROOT)
  set(_sources "")
  foreach(file IN LISTS ARGN)
    get_filename_component(path ${file} ABSOLUTE)
    list(APPEND _sources "${path}")
  endforeach()
  #message(STATUS "Using GROUP_ROOT ${GROUP_ROOT}")
  source_group(TREE "${GROUP_ROOT}" FILES ${_sources})
endfunction()

# -----------------------------------------------------------------------------
function(explorer_copy_runtime TARGET)
  if(NOT ${PROJECT_NAME}_RUNTIME_PREFIX STREQUAL "")
    get_target_property(_type ${TARGET} TYPE)
    if(_type STREQUAL "STATIC_LIBRARY")
      add_custom_command(
        TARGET ${TARGET} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
          $<TARGET_FILE:${TARGET}>
          ${${PROJECT_NAME}_RUNTIME_PREFIX}/${CMAKE_INSTALL_LIBDIR})
    elseif(_type STREQUAL "SHARED_LIBRARY" OR _type STREQUAL "MODULE_LIBRARY")
      add_custom_command(
        TARGET ${TARGET} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
          $<TARGET_FILE:${TARGET}>
          ${${PROJECT_NAME}_RUNTIME_PREFIX}/${CMAKE_INSTALL_BINDIR})
      if(WIN32 AND _type STREQUAL "SHARED_LIBRARY")
        add_custom_command(
          TARGET ${TARGET} POST_BUILD
          COMMAND ${CMAKE_COMMAND} -E copy
            $<TARGET_LINKER_FILE:${TARGET}>
            ${${PROJECT_NAME}_RUNTIME_PREFIX}/${CMAKE_INSTALL_LIBDIR})
      endif()
    elseif(_type STREQUAL "EXECUTABLE")
      add_custom_command(
        TARGET ${TARGET} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
          $<TARGET_FILE:${TARGET}>
          ${${PROJECT_NAME}_RUNTIME_PREFIX}/${CMAKE_INSTALL_BINDIR})
    endif()
  endif()
endfunction()

# -----------------------------------------------------------------------------
function(explorer_add_library NAME)
  set(_options VERBOSE)
  set(_oneval_arguments
    TYPE
    GROUP_ROOT
    )
  set(_multival_arguments
    MOC_HEADERS
    QT_RESOURCES
    CPP_FILES
    CONFIG_CPP_FILES
    PRIVATE_HEADERS
    PUBLIC_HEADERS
    PRIVATE_LINK_LIBRARIES
    PUBLIC_LINK_LIBRARIES
    UI_FILES
    )
  cmake_parse_arguments(
    "" # prefix (empty)
    "${_options}"
    "${_oneval_arguments}"
    "${_multival_arguments}"
    ${ARGN}
    )

  # Display arguments if being VERBOSE
  if(_VERBOSE)
    foreach(opt IN LISTS _options _oneval_arguments _multival_arguments)
      message(STATUS "explorer_add_library(${NAME}): ${opt} -> '${_${opt}}'")
    endforeach()
  endif()
  if(_MOC_HEADERS)
    QT5_WRAP_CPP(MOC_BUILT_SOURCES ${_MOC_HEADERS})
  endif()
  if(_UI_FILES)
    QT5_WRAP_UI(UI_BUILT_SOURCES ${_UI_FILES})
  endif()
  if(_QT_RESOURCES)
    QT5_ADD_RESOURCES(RESOURCES ${_QT_RESOURCES})
  endif()
  source_group("generated" FILES
    ${MOC_BUILT_SOURCES}
    ${UI_BUILT_SOURCES}
  )

  foreach(cpp ${_CONFIG_CPP_FILES})
    list(APPEND _BUILD_CONFIG_CPP_FILES ${CMAKE_BINARY_DIR}/src/${cpp})
  endforeach()
  
  # Build library
  add_library(${NAME} ${_TYPE}
    ${_CPP_FILES} ${_BUILD_CONFIG_CPP_FILES} ${_PUBLIC_HEADERS} ${_PRIVATE_HEADERS}
    ${_MOC_HEADERS} ${MOC_BUILT_SOURCES} ${UI_BUILT_SOURCES}
    )
  generate_export_header(${NAME})
  explorer_copy_runtime(${NAME})

  # Set interface include directories
  target_include_directories(${NAME}
    PUBLIC
      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
      $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/src>
      $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${${PROJECT_NAME}_INCLUDEDIR}>
    )

  # Link to dependencies
  target_link_libraries(${NAME}
    PRIVATE ${_PRIVATE_LINK_LIBRARIES}
    PUBLIC ${_PUBLIC_LINK_LIBRARIES}
    )

  if( ${${PROJECT_NAME}_LIBRARY_ONLY} OR ${${PROJECT_NAME}_CREATE_EXPORT})
    # Install headers
    foreach(h ${_PUBLIC_HEADERS} ${_MOC_HEADERS})
      #message(STATUS "Header at ${h}")
      get_filename_component(DEST_DIR ${h} DIRECTORY)
      #message(STATUS "Going to ${target_INSTALL_HEADER_DIR}/${DEST_DIR}")
      install(FILES ${h}
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${${PROJECT_NAME}_INCLUDEDIR}/${target_INSTALL_HEADER_DIR}/${DEST_DIR}
        COMPONENT Development
        )
    endforeach()

    # Install library
    install(TARGETS ${NAME} EXPORT ${PROJECT_NAME}_EXPORTS
      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT RuntimeLibraries
      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT RuntimeLibraries
      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development
      )
  endif()

  # Add sources to IDE source group
  set_target_properties(${NAME} PROPERTIES FOLDER ${PROJECT_NAME})
  if(NOT _GROUP_ROOT)
    set(_GROUP_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
  endif()
  explorer_source_group(${_GROUP_ROOT} ${_CPP_FILES} ${_PUBLIC_HEADERS} ${_PRIVATE_HEADERS} ${_MOC_HEADERS})
  source_group("generated" FILES ${_BUILD_CONFIG_CPP_FILES})
endfunction()

# -----------------------------------------------------------------------------
function(explorer_add_executable NAME)
  set(_multival_arguments
    MOC_HEADERS
    QT_RESOURCES
    SOURCES
    HEADERS
    LINK_LIBRARIES
    UI_FILES
    )
  cmake_parse_arguments(
    "" # prefix (empty)
    "" # options (none)
    "" # single-value arguments (none)
    "${_multival_arguments}"
    ${ARGN}
    )
    
  if(_MOC_HEADERS)
    QT5_WRAP_CPP(MOC_BUILT_SOURCES ${_MOC_HEADERS})
  endif()
  if(_UI_FILES)
    QT5_WRAP_UI(UI_BUILT_SOURCES ${_UI_FILES})
  endif()
  if(_QT_RESOURCES)
    QT5_ADD_RESOURCES(RESOURCES ${_QT_RESOURCES})
  endif()
  source_group("generated" FILES
    ${MOC_BUILT_SOURCES}
    ${UI_BUILT_SOURCES}
  )

  add_executable(${NAME} MACOSX_BUNDLE ${_SOURCES} ${_HEADERS}
    ${_MOC_HEADERS} ${MOC_BUILT_SOURCES} ${UI_BUILT_SOURCES}
  )
  explorer_copy_runtime(${NAME})

  target_include_directories(${NAME}
    PRIVATE ${${PROJECT_NAME}_INCLUDE_FOLDERS}
    )

  set_target_properties(${NAME} PROPERTIES
    FOLDER ${PROJECT_NAME}
    )

  # Link to dependencies
  target_link_libraries(${NAME}
    PRIVATE ${_LINK_LIBRARIES}
    )

  # Install executable
  install(TARGETS ${NAME}
    BUNDLE DESTINATION .
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Utilities
    )

  # Add sources to IDE source group
  explorer_source_group(${CMAKE_CURRENT_SOURCE_DIR} ${ARGN})

  # Configure running executable out of MSVC
  if(MSVC AND NOT ${PROJECT_NAME}_RUNTIME_PREFIX STREQUAL "")
    set_property(TARGET ${NAME}
      PROPERTY VS_DEBUGGER_WORKING_DIRECTORY
      "${${PROJECT_NAME}_RUNTIME_PREFIX}/${CMAKE_INSTALL_BINDIR}"
      )
  endif()
endfunction()
