include(${PROJECT_SOURCE_DIR}/cmake/core_utils.cmake)

###############################################################################
# Add an option to build a subsystem or not.
# _var The name of the variable to store the option in.
# _name The name of the option's target subsystem.
# _desc The description of the subsystem.
# _default The default value (TRUE or FALSE)
# ARGV5 The reason for disabling if the default is FALSE.
macro(CORE_SUBSYS_OPTION _var _name _desc _default)
  set(_opt_name "BUILD_${_name}")
  CORE_GET_SUBSYS_HYPERSTATUS(subsys_status ${_name})
  if(NOT ("${subsys_status}" STREQUAL "AUTO_OFF"))
    option(${_opt_name} ${_desc} ${_default})
    if(NOT ${_default} AND NOT ${_opt_name})
      set(${_var} FALSE)
      if(${ARGC} GREATER 4)
        set(_reason ${ARGV4})
      else(${ARGC} GREATER 4)
        set(_reason "Disabled by default.")
      endif(${ARGC} GREATER 4)
      CORE_SET_SUBSYS_STATUS(${_name} FALSE ${_reason})
      CORE_DISABLE_DEPENDIES(${_name})
    elseif(NOT ${_opt_name})
      set(${_var} FALSE)
      CORE_SET_SUBSYS_STATUS(${_name} FALSE "Disabled manually.")
      CORE_DISABLE_DEPENDIES(${_name})
    else(NOT ${_default} AND NOT ${_opt_name})
      set(${_var} TRUE)
      CORE_SET_SUBSYS_STATUS(${_name} TRUE)
      CORE_ENABLE_DEPENDIES(${_name})
    endif(NOT ${_default} AND NOT ${_opt_name})
  endif(NOT ("${subsys_status}" STREQUAL "AUTO_OFF"))
  CORE_ADD_SUBSYSTEM(${_name} ${_desc})
endmacro(CORE_SUBSYS_OPTION)

###############################################################################
# Make one subsystem depend on one or more other subsystems, and disable it if
# they are not being built.
# _var The cumulative build variable. This will be set to FALSE if the
#      dependencies are not met.
# _name The name of the subsystem.
# ARGN The subsystems and external libraries to depend on.
macro(CORE_SUBSYS_DEPEND _var _name)
  set(options)
  set(oneValueArgs)
  set(multiValueArgs DEPS EXT_DEPS OPT_DEPS)
  cmake_parse_arguments(SUBSYS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
  if(SUBSYS_DEPS)
    SET_IN_GLOBAL_MAP(CORE_SUBSYS_DEPS ${_name} "${SUBSYS_DEPS}")
  endif(SUBSYS_DEPS)
  if(SUBSYS_EXT_DEPS)
    SET_IN_GLOBAL_MAP(CORE_SUBSYS_EXT_DEPS ${_name} "${SUBSYS_EXT_DEPS}")
  endif(SUBSYS_EXT_DEPS)
  if(SUBSYS_OPT_DEPS)
    SET_IN_GLOBAL_MAP(CORE_SUBSYS_OPT_DEPS ${_name} "${SUBSYS_OPT_DEPS}")
  endif(SUBSYS_OPT_DEPS)
  GET_IN_MAP(subsys_status CORE_SUBSYS_HYPERSTATUS ${_name})
  if(${_var} AND (NOT ("${subsys_status}" STREQUAL "AUTO_OFF")))
    if(SUBSYS_DEPS)
      foreach(_dep ${SUBSYS_DEPS})
        CORE_GET_SUBSYS_STATUS(_status ${_dep})
        if(NOT _status)
          set(${_var} FALSE)
          CORE_SET_SUBSYS_STATUS(${_name} FALSE "Requires ${_dep}.")
        else(NOT _status)
          CORE_GET_SUBSYS_INCLUDE_DIR(_include_dir ${_dep})
          include_directories(${PROJECT_SOURCE_DIR}/${_include_dir}/include)
        endif(NOT _status)
      endforeach(_dep)
    endif(SUBSYS_DEPS)
    if(SUBSYS_EXT_DEPS)
      foreach(_dep ${SUBSYS_EXT_DEPS})
        string(TOUPPER "${_dep}_found" EXT_DEP_FOUND)
        if(NOT ${EXT_DEP_FOUND} OR (NOT ("${EXT_DEP_FOUND}" STREQUAL "TRUE")))
          set(${_var} FALSE)
          CORE_SET_SUBSYS_STATUS(${_name} FALSE "Requires external library ${_dep}.")
        endif(NOT ${EXT_DEP_FOUND} OR (NOT ("${EXT_DEP_FOUND}" STREQUAL "TRUE")))
      endforeach(_dep)
    endif(SUBSYS_EXT_DEPS)
  endif(${_var} AND (NOT ("${subsys_status}" STREQUAL "AUTO_OFF")))
endmacro(CORE_SUBSYS_DEPEND)

###############################################################################
# Add a set of include files to install.
# _component The part of CORE that the install files belong to.
# _subdir The subdirectory for these include files.
# ARGN The include files.
macro(CORE_ADD_INCLUDES _component _subdir)
  install(FILES ${ARGN} DESTINATION ${INCLUDE_INSTALL_DIR}/${_subdir} COMPONENT 
          ${_component})
endmacro(CORE_ADD_INCLUDES)

###############################################################################
# Add a library target.
# _name The library name.
# _component The part of CORE that this library belongs to.
# ARGN The source files for the library.
macro(CORE_ADD_LIBRARY _name _component)
  add_library(${_name} ${CORE_LIB_TYPE} ${ARGN})
  # Must link explicitly against boost
  target_link_libraries(${_name} ${Boost_LIBRARIES})
  if(MSVC90 OR MSVC10)
    target_link_libraries(${_name} delayimp.lib)  # Because delay load is enabled for openmp.dll
  endif()
  # Only link if needed
  if(WIN32 AND MSVC)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS_RELEASE /OPT:REF)
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl)
  elseif(__COMPILER_PATHSCALE)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -mp)
  else()
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl,--as-needed)
  endif()
  set_target_properties(${_name} PROPERTIES
    VERSION ${CORE_VERSION}
    SOVERSION ${CORE_MAJOR_VERSION}.${CORE_MINOR_VERSION}
    DEFINE_SYMBOL "COREAPI_EXPORTS")
  if(USE_PROJECT_FOLDERS)
    set_target_properties(${_name} PROPERTIES FOLDER "Libraries")
  endif(USE_PROJECT_FOLDERS)
  install(TARGETS ${_name}
          RUNTIME DESTINATION ${BIN_INSTALL_DIR} COMPONENT ${_component}
          LIBRARY DESTINATION ${LIB_INSTALL_DIR} COMPONENT ${_component}
          ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT ${_component})
endmacro(CORE_ADD_LIBRARY)

###############################################################################
# Add a CUDA library target.
# _name The library name.
# _component The part of CORE that this library belongs to.
# ARGN The source files for the library.
macro(CORE_CUDA_ADD_LIBRARY _name _component)
  if(CORE_SHARED_LIBS)
    # To overcome a limitation in cuda_add_library, we manually add the 
    # COREAPI_EXPORTS macro
    cuda_add_library(${_name} ${CORE_LIB_TYPE} ${ARGN} OPTIONS -DCOREAPI_EXPORTS)
  else(CORE_SHARED_LIBS)
    cuda_add_library(${_name} ${CORE_LIB_TYPE} ${ARGN})
  endif(CORE_SHARED_LIBS)
  # Must link explicitly against boost
  target_link_libraries(${_name} ${Boost_LIBRARIES})
  # Only link if needed
  if(WIN32 AND MSVC)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS_RELEASE /OPT:REF)
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl)
  else()
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl,--as-needed)
  endif()
  set_target_properties(${_name} PROPERTIES
    VERSION ${CORE_VERSION}
    SOVERSION ${CORE_MAJOR_VERSION}
    DEFINE_SYMBOL "COREAPI_EXPORTS")
  if(USE_PROJECT_FOLDERS)
    set_target_properties(${_name} PROPERTIES FOLDER "Libraries")
  endif(USE_PROJECT_FOLDERS)
  install(TARGETS ${_name}
    RUNTIME DESTINATION ${BIN_INSTALL_DIR} COMPONENT ${_component}
    LIBRARY DESTINATION ${LIB_INSTALL_DIR} COMPONENT ${_component}
    ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT ${_component})
endmacro(CORE_CUDA_ADD_LIBRARY)

###############################################################################
# Add an executable target.
# _name The executable name.
# _component The part of CORE that this library belongs to.
# ARGN The source files for the library.
macro(CORE_ADD_EXECUTABLE _name _component)
  add_executable(${_name} ${ARGN})
  # Must link explicitly against boost
  if(UNIX AND NOT ANDROID_NDK)
    target_link_libraries(${_name} ${Boost_LIBRARIES} pthread)
  else()
    target_link_libraries(${_name} ${Boost_LIBRARIES})
  endif()
  # Only link if needed
  if(WIN32 AND MSVC)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS_RELEASE /OPT:REF
                          DEBUG_OUTPUT_NAME ${_name}${CMAKE_DEBUG_POSTFIX}
                          RELEASE_OUTPUT_NAME ${_name}${CMAKE_RELEASE_POSTFIX})
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl)
  elseif(__COMPILER_PATHSCALE)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -mp)
  else()
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl,--as-needed)
  endif()
  if(USE_PROJECT_FOLDERS)
    set_target_properties(${_name} PROPERTIES FOLDER "Tools and demos")
  endif(USE_PROJECT_FOLDERS)
  set(CORE_EXECUTABLES ${CORE_EXECUTABLES} ${_name})
  install(TARGETS ${_name} RUNTIME DESTINATION ${BIN_INSTALL_DIR}
      COMPONENT ${_component})
endmacro(CORE_ADD_EXECUTABLE)

###############################################################################
# Add an executable target as a bundle when available and required
# _name The executable name.
# _component The part of CORE that this library belongs to.
# _bundle 
# ARGN The source files for the library.
macro(CORE_ADD_EXECUTABLE_OPT_BUNDLE _name _component)
  if(APPLE AND VTK_USE_COCOA)
    add_executable(${_name} MACOSX_BUNDLE ${ARGN})
  else(APPLE AND VTK_USE_COCOA)
    add_executable(${_name} ${ARGN})
  endif(APPLE AND VTK_USE_COCOA)
  # Must link explicitly against boost
  if(UNIX AND NOT ANDROID_NDK)
    target_link_libraries(${_name} ${Boost_LIBRARIES} pthread)
  else()
    target_link_libraries(${_name} ${Boost_LIBRARIES})
  endif()
  # Only link if needed
  if(WIN32 AND MSVC)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS_RELEASE /OPT:REF
                          DEBUG_OUTPUT_NAME ${_name}${CMAKE_DEBUG_POSTFIX}
                          RELEASE_OUTPUT_NAME ${_name}${CMAKE_RELEASE_POSTFIX})
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl)
  elseif(__COMPILER_PATHSCALE)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -mp)
  else()
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl,--as-needed)
  endif()
  if(USE_PROJECT_FOLDERS)
    set_target_properties(${_name} PROPERTIES FOLDER "Tools and demos")
  endif(USE_PROJECT_FOLDERS)
  set(CORE_EXECUTABLES ${CORE_EXECUTABLES} ${_name})
  #message(STATUS "COMMAND ${CMAKE_COMMAND} -E create_symlink \"${_name}.app/Contents/MacOS/${_name}\" \"${_name}\"")
  if(APPLE AND VTK_USE_COCOA)
    #add_custom_command(TARGET ${_name}
    #POST_BUILD
    #COMMAND ${CMAKE_COMMAND} -E create_symlink ${CORE_OUTPUT_BIN_DIR}/${_name}.app/Contents/MacOS/${_name} ${CORE_OUTPUT_BIN_DIR}/${_name}
    #WORKING_DIRECTORY 
    #COMMENT "Creating an alias for ${_name}.app to ${_name}")
    install(TARGETS ${_name} BUNDLE DESTINATION ${BIN_INSTALL_DIR} COMPONENT ${_component})
  else(APPLE AND VTK_USE_COCOA)
    install(TARGETS ${_name} RUNTIME DESTINATION ${BIN_INSTALL_DIR} COMPONENT ${_component})
  endif(APPLE AND VTK_USE_COCOA)
endmacro(CORE_ADD_EXECUTABLE_OPT_BUNDLE)

###############################################################################
# Add an executable target.
# _name The executable name.
# _component The part of CORE that this library belongs to.
# ARGN The source files for the library.
macro(CORE_CUDA_ADD_EXECUTABLE _name _component)
  cuda_add_executable(${_name} ${ARGN})
  # Must link explicitly against boost
  target_link_libraries(${_name} ${Boost_LIBRARIES})
  # Only link if needed
  if(WIN32 AND MSVC)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS_RELEASE /OPT:REF
                          DEBUG_OUTPUT_NAME ${_name}${CMAKE_DEBUG_POSTFIX}
                          RELEASE_OUTPUT_NAME ${_name}${CMAKE_RELEASE_POSTFIX})
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl)
  else()
    set_target_properties(${_name} PROPERTIES LINK_FLAGS -Wl,--as-needed)
  endif()
  if(USE_PROJECT_FOLDERS)
    set_target_properties(${_name} PROPERTIES FOLDER "Tools and demos")
  endif(USE_PROJECT_FOLDERS)
  set(CORE_EXECUTABLES ${CORE_EXECUTABLES} ${_name})
  install(TARGETS ${_name} RUNTIME DESTINATION ${BIN_INSTALL_DIR}
         COMPONENT ${_component})
endmacro(CORE_CUDA_ADD_EXECUTABLE)

###############################################################################
# Add a test target.
# _name The test name.
# _exename The exe name.
# ARGN:
#    FILES The source files for the test
#    ARGUMENTS Arguments for test executable
#    LINK_WITH Link test executable with libraries
macro(CORE_ADD_TEST _name _exename)
  set(options)
  set(oneValueArgs)
  set(multiValueArgs FILES ARGUMENTS LINK_WITH)
  cmake_parse_arguments(CORE_ADD_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  add_executable(${_exename} ${CORE_ADD_TEST_FILES})
  if(NOT WIN32)
    set_target_properties(${_exename} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
  endif(NOT WIN32)
  target_link_libraries(${_exename} ${GTEST_BOTH_LIBRARIES} ${CORE_ADD_TEST_LINK_WITH})
  # Only link if needed
  if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    set_target_properties(${_exename} PROPERTIES LINK_FLAGS -Wl)
    target_link_libraries(${_exename} pthread)
  elseif(UNIX AND NOT ANDROID_NDK)
    set_target_properties(${_exename} PROPERTIES LINK_FLAGS -Wl,--as-needed)
    # GTest >= 1.5 requires pthread and CMake's 2.8.4 FindGTest is broken
    target_link_libraries(${_exename} pthread)
  elseif(WIN32)
    set_target_properties(${_exename} PROPERTIES LINK_FLAGS_RELEASE /OPT:REF)
  endif()
  # Must link explicitly against boost only on Windows
  target_link_libraries(${_exename} ${Boost_LIBRARIES})
  if(USE_PROJECT_FOLDERS)
    set_target_properties(${_exename} PROPERTIES FOLDER "Tests")
  endif(USE_PROJECT_FOLDERS)
  if(${CMAKE_VERSION} VERSION_LESS 2.8.4)
    add_test(${_name} ${_exename} ${CORE_ADD_TEST_ARGUMENTS})
  else(${CMAKE_VERSION} VERSION_LESS 2.8.4)
    add_test(NAME ${_name} COMMAND ${_exename} ${CORE_ADD_TEST_ARGUMENTS})
  endif(${CMAKE_VERSION} VERSION_LESS 2.8.4)
endmacro(CORE_ADD_TEST)

###############################################################################
# Add an example target.
# _name The example name.
# ARGN:
#    FILES the source files for the example
#    LINK_WITH link example executable with libraries
macro(CORE_ADD_EXAMPLE _name)
  set(options)
  set(oneValueArgs)
  set(multiValueArgs FILES LINK_WITH)
  cmake_parse_arguments(CORE_ADD_EXAMPLE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
  add_executable(${_name} ${CORE_ADD_EXAMPLE_FILES})
  target_link_libraries(${_name} ${CORE_ADD_EXAMPLE_LINK_WITH})
  if(WIN32 AND MSVC)
    set_target_properties(${_name} PROPERTIES DEBUG_OUTPUT_NAME ${_name}${CMAKE_DEBUG_POSTFIX}
                          RELEASE_OUTPUT_NAME ${_name}${CMAKE_RELEASE_POSTFIX})
  endif(WIN32 AND MSVC)
  if(USE_PROJECT_FOLDERS)
    set_target_properties(${_name} PROPERTIES FOLDER "Examples")
  endif(USE_PROJECT_FOLDERS)
endmacro(CORE_ADD_EXAMPLE)

###############################################################################
# Add compile flags to a target (because CMake doesn't provide something so
# common itself).
# _name The target name.
# _flags The new compile flags to be added, as a string.
macro(CORE_ADD_CFLAGS _name _flags)
  get_target_property(_current_flags ${_name} COMPILE_FLAGS)
  if(NOT _current_flags)
    set_target_properties(${_name} PROPERTIES COMPILE_FLAGS ${_flags})
  else(NOT _current_flags)
    set_target_properties(${_name} PROPERTIES COMPILE_FLAGS "${_current_flags} ${_flags}")
  endif(NOT _current_flags)
endmacro(CORE_ADD_CFLAGS)

###############################################################################
# Add link flags to a target (because CMake doesn't provide something so
# common itself).
# _name The target name.
# _flags The new link flags to be added, as a string.
macro(CORE_ADD_LINKFLAGS _name _flags)
  get_target_property(_current_flags ${_name} LINK_FLAGS)
  if(NOT _current_flags)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS ${_flags})
  else(NOT _current_flags)
    set_target_properties(${_name} PROPERTIES LINK_FLAGS "${_current_flags} ${_flags}")
  endif(NOT _current_flags)
endmacro(CORE_ADD_LINKFLAGS)

###############################################################################
# Make a pkg-config file for a library. Do not include general CORE stuff in the
# arguments; they will be added automatically.
# _name The library name. "core_" will be preprended to this.
# _component The part of CORE that this pkg-config file belongs to.
# _desc Description of the library.
# _core_deps External dependencies to core libs, as a list. (Will get mangled to 
#           external pkg-config name)
# _ext_deps External dependencies, as a list.
# _int_deps Internal dependencies, as a list.
# _cflags Compiler flags necessary to build with the library.
# _lib_flags Linker flags necessary to link to the library.
macro(CORE_MAKE_PKGCONFIG _name _component _desc _core_deps _ext_deps _int_deps _cflags
      _lib_flags)
  set(PKG_NAME ${_name})
  set(PKG_DESC ${_desc})
  set(PKG_CFLAGS ${_cflags})
  set(PKG_LIBFLAGS ${_lib_flags})
  LIST_TO_STRING(_ext_deps_str "${_ext_deps}")
  set(PKG_EXTERNAL_DEPS ${_ext_deps_str})
  foreach(_dep ${_core_deps})
    set(PKG_EXTERNAL_DEPS "${PKG_EXTERNAL_DEPS} core_${_dep}-${CORE_MAJOR_VERSION}.${CORE_MINOR_VERSION}")
  endforeach(_dep)
  set(PKG_INTERNAL_DEPS "")
  foreach(_dep ${_int_deps})
    set(PKG_INTERNAL_DEPS "${PKG_INTERNAL_DEPS} -l${_dep}")
  endforeach(_dep)
  set(_pc_file ${CMAKE_CURRENT_BINARY_DIR}/${_name}-${CORE_MAJOR_VERSION}.${CORE_MINOR_VERSION}.pc)
  configure_file(${PROJECT_SOURCE_DIR}/cmake/pkgconfig.cmake.in ${_pc_file} @ONLY)
  install(FILES ${_pc_file} DESTINATION ${PKGCFG_INSTALL_DIR} COMPONENT ${_component})
endmacro(CORE_MAKE_PKGCONFIG)

###############################################################################
# PRIVATE
###############################################################################
# Reset the subsystem status map.
macro(CORE_RESET_MAPS)
  set(CORE_SUBSYS_HYPERSTATUS "" CACHE INTERNAL
      "To Build Or Not To Build, That Is The Question." FORCE)
  set(CORE_SUBSYS_STATUS "" CACHE INTERNAL
      "To build or not to build, that is the question." FORCE)
  set(CORE_SUBSYS_REASONS "" CACHE INTERNAL
      "But why?" FORCE)
  set(CORE_SUBSYS_DEPS "" CACHE INTERNAL "A depends on B and C." FORCE)
  set(CORE_SUBSYS_EXT_DEPS "" CACHE INTERNAL "A depends on B and C." FORCE)
  set(CORE_SUBSYS_OPT_DEPS "" CACHE INTERNAL "A depends on B and C." FORCE)
  set(CORE_SUBSYSTEMS "" CACHE INTERNAL "Internal list of subsystems" FORCE)
  set(CORE_SUBSYS_DESC "" CACHE INTERNAL "Subsystem descriptions" FORCE)
endmacro(CORE_RESET_MAPS)

###############################################################################
# Register a subsystem.
# _name Subsystem name.
# _desc Description of the subsystem
macro(CORE_ADD_SUBSYSTEM _name _desc)
  set(_temp ${CORE_SUBSYSTEMS})
  list(APPEND _temp ${_name})
  set(CORE_SUBSYSTEMS ${_temp} CACHE INTERNAL "Internal list of subsystems" 
      FORCE)
  SET_IN_GLOBAL_MAP(CORE_SUBSYS_DESC ${_name} ${_desc})
endmacro(CORE_ADD_SUBSYSTEM)

###############################################################################
# Set the status of a subsystem.
# _name Subsystem name.
# _status TRUE if being built, FALSE otherwise.
# ARGN[0] Reason for not building.
macro(CORE_SET_SUBSYS_STATUS _name _status)
  if(${ARGC} EQUAL 3)
    set(_reason ${ARGV2})
  else(${ARGC} EQUAL 3)
    set(_reason "No reason")
  endif(${ARGC} EQUAL 3)
  SET_IN_GLOBAL_MAP(CORE_SUBSYS_STATUS ${_name} ${_status})
  SET_IN_GLOBAL_MAP(CORE_SUBSYS_REASONS ${_name} ${_reason})
endmacro(CORE_SET_SUBSYS_STATUS)

###############################################################################
# Get the status of a subsystem.
# _var Destination variable.
# _name Name of the subsystem.
macro(CORE_GET_SUBSYS_STATUS _var _name)
    GET_IN_MAP(${_var} CORE_SUBSYS_STATUS ${_name})
endmacro(CORE_GET_SUBSYS_STATUS)

###############################################################################
# Set the hyperstatus of a subsystem and its dependee.
# _name Subsystem name.
# _dependee Dependant subsystem.
# _status AUTO_OFF to disable AUTO_ON to enable
# ARGN[0] Reason for not building.
macro(CORE_SET_SUBSYS_HYPERSTATUS _name _dependee _status) 
  SET_IN_GLOBAL_MAP(CORE_SUBSYS_HYPERSTATUS ${_name}_${_dependee} ${_status})
  if(${ARGC} EQUAL 4)
    SET_IN_GLOBAL_MAP(CORE_SUBSYS_REASONS ${_dependee} ${ARGV3})
  endif(${ARGC} EQUAL 4)
endmacro(CORE_SET_SUBSYS_HYPERSTATUS)

###############################################################################
# Get the hyperstatus of a subsystem and its dependee.
# _name IN subsystem name.
# _dependee IN dependant subsystem.
# _var OUT hyperstatus
# ARGN[0] Reason for not building.
macro(CORE_GET_SUBSYS_HYPERSTATUS _var _name)
  set(${_var} "AUTO_ON")
  if(${ARGC} EQUAL 3)
    GET_IN_MAP(${_var} CORE_SUBSYS_HYPERSTATUS ${_name}_${ARGV2})
  else(${ARGC} EQUAL 3)
    foreach(subsys ${CORE_SUBSYS_DEPS_${_name}})
      if("${CORE_SUBSYS_HYPERSTATUS_${subsys}_${_name}}" STREQUAL "AUTO_OFF")
        set(${_var} "AUTO_OFF")
        break()
      endif("${CORE_SUBSYS_HYPERSTATUS_${subsys}_${_name}}" STREQUAL "AUTO_OFF")
    endforeach(subsys)
  endif(${ARGC} EQUAL 3)
endmacro(CORE_GET_SUBSYS_HYPERSTATUS)

###############################################################################
# Set the hyperstatus of a subsystem and its dependee.
macro(CORE_UNSET_SUBSYS_HYPERSTATUS _name _dependee)
  unset(CORE_SUBSYS_HYPERSTATUS_${_name}_${dependee})
endmacro(CORE_UNSET_SUBSYS_HYPERSTATUS)

###############################################################################
# Set the include directory name of a subsystem.
# _name Subsystem name.
# _includedir Name of subdirectory for includes 
# ARGN[0] Reason for not building.
macro(CORE_SET_SUBSYS_INCLUDE_DIR _name _includedir)
  SET_IN_GLOBAL_MAP(CORE_SUBSYS_INCLUDE ${_name} ${_includedir})
endmacro(CORE_SET_SUBSYS_INCLUDE_DIR)

###############################################################################
# Get the include directory name of a subsystem - return _name if not set.
# _var Destination variable.
# _name Name of the subsystem.
macro(CORE_GET_SUBSYS_INCLUDE_DIR _var _name)
  GET_IN_MAP(${_var} CORE_SUBSYS_INCLUDE ${_name})
  if(NOT ${_var})
    set (${_var} ${_name})
  endif(NOT ${_var})
endmacro(CORE_GET_SUBSYS_INCLUDE_DIR)

###############################################################################
# Write a report on the build/not-build status of the subsystems.
macro(CORE_WRITE_STATUS_REPORT)
  message(STATUS "The following subsystems will be built:")
  foreach(_ss ${CORE_SUBSYSTEMS})
    CORE_GET_SUBSYS_STATUS(_status ${_ss})
    if(_status)
      message(STATUS "  ${_ss}")
    endif(_status)
  endforeach(_ss)
  message(STATUS "The following subsystems will not be built:")
  foreach(_ss ${CORE_SUBSYSTEMS})
    CORE_GET_SUBSYS_STATUS(_status ${_ss})
    CORE_GET_SUBSYS_STATUS(_hyper_status ${_ss})
    if(NOT _status OR ("${_hyper_status}" STREQUAL "AUTO_OFF"))
      GET_IN_MAP(_reason CORE_SUBSYS_REASONS ${_ss})
      message(STATUS "  ${_ss}: ${_reason}")
    endif(NOT _status OR ("${_hyper_status}" STREQUAL "AUTO_OFF"))
  endforeach(_ss)
endmacro(CORE_WRITE_STATUS_REPORT)

##############################################################################
# Collect subdirectories from dirname that contains filename and store them in
# varname.
# WARNING: If extra arguments are given then they are considered as an 
# exception list and varname will contain subdirectories of dirname that 
# contains fielename but doesn't belong to exception list.
# dirname IN parent directory
# filename IN file name to look for in each subdirectory of parent directory
# varname OUT list of subdirectories containing filename
# exception_list OPTIONAL and contains list of subdirectories not to account
macro(collect_subproject_directory_names dirname filename names dirs)
  file(GLOB globbed RELATIVE "${dirname}" "${dirname}/*/${filename}")
  if(${ARGC} GREATER 3)
    set(exclusion_list ${ARGN})
    foreach(file ${globbed})
      get_filename_component(dir ${file} PATH)
      list(FIND exclusion_list ${dir} excluded)
      if(excluded EQUAL -1)
        set(${dirs} ${${dirs}} ${dir})
      endif(excluded EQUAL -1)
    endforeach()
  else(${ARGC} GREATER 3)
    foreach(file ${globbed})
      get_filename_component(dir ${file} PATH)
      set(${dirs} ${${dirs}} ${dir})
    endforeach(file)      
  endif(${ARGC} GREATER 3)
  foreach(subdir ${${dirs}})
    file(STRINGS ${dirname}/${subdir}/CMakeLists.txt name REGEX "set.*SUBSYS_NAME .*\\)$")
    string(REGEX REPLACE "set.*SUBSYS_NAME" "" name "${name}")
    string(REPLACE ")" "" name "${name}")
    string(STRIP "${name}" name)
    #message(STATUS "setting ${subdir} component name to ${name}")
    set(${names} ${${names}} ${name})
    file(STRINGS ${dirname}/${subdir}/CMakeLists.txt DEPENDENCIES REGEX "set.*SUBSYS_DEPS .*\\)")
    string(REGEX REPLACE "set.*SUBSYS_DEPS" "" DEPENDENCIES "${DEPENDENCIES}")
    string(REPLACE ")" "" DEPENDENCIES "${DEPENDENCIES}")
    string(STRIP "${DEPENDENCIES}" DEPENDENCIES)
    string(REPLACE " " ";" DEPENDENCIES "${DEPENDENCIES}")
    if(NOT("${DEPENDENCIES}" STREQUAL ""))
      list(REMOVE_ITEM DEPENDENCIES "#")
      string(TOUPPER "CORE_${name}_DEPENDS" SUBSYS_DEPENDS)
      set(${SUBSYS_DEPENDS} ${DEPENDENCIES})
      foreach(dependee ${DEPENDENCIES})
        string(TOUPPER "CORE_${dependee}_DEPENDIES" SUBSYS_DEPENDIES)
        set(${SUBSYS_DEPENDIES} ${${SUBSYS_DEPENDIES}} ${name})
      endforeach(dependee)
    endif(NOT("${DEPENDENCIES}" STREQUAL ""))
  endforeach(subdir)
endmacro()

########################################################################################
# Macro to disable subsystem dependies.
# _subsys IN subsystem name
macro(CORE_DISABLE_DEPENDIES _subsys)
  string(TOUPPER "core_${_subsys}_dependies" CORE_SUBSYS_DEPENDIES)
  if(NOT ("${${CORE_SUBSYS_DEPENDIES}}" STREQUAL ""))
    foreach(dep ${${CORE_SUBSYS_DEPENDIES}})
      CORE_SET_SUBSYS_HYPERSTATUS(${_subsys} ${dep} AUTO_OFF "Disabled: ${_subsys} missing.")
      set(BUILD_${dep} OFF CACHE BOOL "Disabled: ${_subsys} missing." FORCE)
    endforeach(dep)
  endif(NOT ("${${CORE_SUBSYS_DEPENDIES}}" STREQUAL ""))
endmacro(CORE_DISABLE_DEPENDIES subsys)

########################################################################################
# Macro to enable subsystem dependies.
# _subsys IN subsystem name
macro(CORE_ENABLE_DEPENDIES _subsys)
  string(TOUPPER "core_${_subsys}_dependies" CORE_SUBSYS_DEPENDIES)
  if(NOT ("${${CORE_SUBSYS_DEPENDIES}}" STREQUAL ""))
    foreach(dep ${${CORE_SUBSYS_DEPENDIES}})
      CORE_GET_SUBSYS_HYPERSTATUS(dependee_status ${_subsys} ${dep})
      if("${dependee_status}" STREQUAL "AUTO_OFF")
        CORE_SET_SUBSYS_HYPERSTATUS(${_subsys} ${dep} AUTO_ON)
        GET_IN_MAP(desc CORE_SUBSYS_DESC ${dep})
        set(BUILD_${dep} ON CACHE BOOL "${desc}" FORCE)
      endif("${dependee_status}" STREQUAL "AUTO_OFF")
    endforeach(dep)
  endif(NOT ("${${CORE_SUBSYS_DEPENDIES}}" STREQUAL ""))
endmacro(CORE_ENABLE_DEPENDIES subsys)

########################################################################################
# Macro to build subsystem centric documentation.
# _subsys IN the name of the subsystem to generate documentation for
macro(CORE_ADD_DOC _subsys)
  string(TOUPPER "${_subsys}" SUBSYS)
  set(doc_subsys "doc_${_subsys}")
  GET_IN_MAP(dependencies CORE_SUBSYS_DEPS ${_subsys})
  if(DOXYGEN_FOUND)
    if(HTML_HELP_COMPILER)
      set(DOCUMENTATION_HTML_HELP YES)
    else(HTML_HELP_COMPILER)
      set(DOCUMENTATION_HTML_HELP NO)
    endif(HTML_HELP_COMPILER)
    if(DOXYGEN_DOT_EXECUTABLE)
      set(HAVE_DOT YES)
    else(DOXYGEN_DOT_EXECUTABLE)
      set(HAVE_DOT NO)
    endif(DOXYGEN_DOT_EXECUTABLE)
    if(NOT "${dependencies}" STREQUAL "")
      set(STRIPPED_HEADERS "${CORE_SOURCE_DIR}/${dependencies}/include")
      string(REPLACE ";" "/include \\\n\t\t\t\t\t\t\t\t\t\t\t\t ${CORE_SOURCE_DIR}/" 
             STRIPPED_HEADERS "${STRIPPED_HEADERS}")
    endif(NOT "${dependencies}" STREQUAL "")
    set(DOC_SOURCE_DIR "\"${CMAKE_CURRENT_SOURCE_DIR}\"\\")
    foreach(dep ${dependencies})
      set(DOC_SOURCE_DIR 
          "${DOC_SOURCE_DIR}\n\t\t\t\t\t\t\t\t\t\t\t\t \"${CORE_SOURCE_DIR}/${dep}\"\\")
    endforeach(dep)
    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html")
    set(doxyfile "${CMAKE_CURRENT_BINARY_DIR}/doxyfile")
    configure_file("${CORE_SOURCE_DIR}/doc/doxygen/doxyfile.in" ${doxyfile})
    add_custom_target(${doc_subsys} ${DOXYGEN_EXECUTABLE} ${doxyfile})
    if(USE_PROJECT_FOLDERS)
      set_target_properties(${doc_subsys} PROPERTIES FOLDER "Documentation")
    endif(USE_PROJECT_FOLDERS)
  endif(DOXYGEN_FOUND)
endmacro(CORE_ADD_DOC)
