#!
#! @ingroup group_sdk_cmake_camitk
#!
#! macro camitk_application simplify writing a CMakeLists.txt for CamiTK application extension
#!
#! \note
#! After the execution of this macro, the variable APPLICATION_TARGET_NAME
#! holds the name of the CMake target produced by this macro.
#! The target name itself is equals to `camitk-name`, where **name** is the name of the current
#! folder in lowercase.
#!
#! On Unix additional system resources can also be automatically installed or configured: man pages,
#! desktop file and XPM icons.
#! - Man pages should be resources/camitk-appdirname.1 or resources/camitk-appdirname.1.in (in this
#! case, it will be configured first).
#! - Desktop file should be in resources/camitk-appdirname.desktop (refer to
#!    http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html and
#!    http://standards.freedesktop.org/menu-spec/1.0/apa.html for valid category details)
#! - XPM icons should be found in resources/camitk-appdirname.xpm (an icon can also be used in
#!   to set the application icon (use setWindowIcon(QIcon(":/resources/camitk-appdirname.xpm")) as well)
#!
#! To write a simple man page, please refer to SDK application examples. If you need to
#! generate a simple manpage or analyze the command line arguments, the CamiTK team recommands
#! to use Code Synthesis CLI configuration (see http://codesynthesis.com/projects/cli)
#!
#! usage:
#! \code
#! camitk_application(
#!              [DISABLED]
#!              [APPLICATION_NAME]
#!              [INTERNAL_TEST_APPLICATION]
#!              [NO_CAMITKCORE_REQUIRED]
#!              [NO_GUI]
#!              [QTEST]
#!              [TEST_RUN_SERIAL]
#!              [SOURCES source1.cpp source2.cpp ...]
#!              [NEEDS_ITK]
#!              [NEEDS_PYTHON]
#!              [NEEDS_CEP_LIBRARIES CEPLib1 CEPLib12 ...]
#!              [NEEDS_COMPONENT_EXTENSION component1 component2 ...]
#!              [NEEDS_ACTION_EXTENSION ation1 action2 ...]
#!              [NEEDS_VIEWER_EXTENSION viewer1 viewer2 ...]
#!              [NEEDS_EXTENSIONGENERATOR]
#!              [DEFINES flag1 flag2 ...]
#!              [CXX_FLAGS flag1 flag2 ...]
#!              [ADDITIONAL_SOURCES source.cxx source.cpp ...]
#!              [QRC_SOURCES file.qrc]
#!              [INCLUDE_DIRECTORIES dir1 dir2 ...]
#!              [EXTERNAL_LIBRARIES lib1 lib2 ...]
#!              [EXTRA_TRANSLATE_LANGUAGE]
#!     )
#! \endcode
#!
#! \param DISABLED                      means this is a default application is NOT to be compiled automatically
#! \param APPLICATION_NAME              this overrides the default name for the application (directory name)
#! \param INTERNAL_TEST_APPLICATION     means this application's objective is to build an internal test, 
#!                                      not to be distributed.
#!                                      Using this flag will automatically set the name and target 
#!                                      to "test-APPLICATION_NAME". test applications won't be distributed / installed.
#!                                      \note use in combination with NO_CAMITKCORE_REQUIRED if the application does not 
#!                                      depends from camitkcore nor qtpropertybrowser libraries.
#!                                      \note use in combination with NO_GUI if the application can
#!                                      be ran in console mode (useful for windows)
#!                                      \note use in combination with QTEST if the application is using
#!                                      QTest framework
#! \param NO_CAMITKCORE_REQUIRED        This application does not need camitkcore nor qtpropertybrowser
#! \param NO_GUI                        means this application doesn't require a GUI and it will be 
#!                                      compile to be ran into a console mode (useful on windows)
#! \param QTEST                         this application is a qtest application, all tests functions 
#!                                      will be separated into different specific tests named after the
#!                                      function.
#! \param TEST_RUN_SERIAL               Do not run this test in parallel with any other test. Use when the 
#!                                      test can take a loooooonnnnng time and break the CI pipeline due
#!                                      to ressources limitation
#! \param SOURCES                       if provided CMake won't look automatically (gather) headers and sources.
#!                                      Can be used in conjunction with QRC_SOURCES.
#! \param NEEDS_ITK                     means this application requires ITK to be compiled / run.
#! \param NEEDS_CEP_LIBRARIES           list of needed camitk CEP libraries
#! \param NEEDS_COMPONENT_EXTENSION     list of needed component extensions
#! \param NEEDS_ACTION_EXTENSION        list of needed action extensions
#! \param NEEDS_VIEWER_EXTENSION        list of needed viewer extensions
#! \param NEEDS_EXTENSIONGENERATOR      add this flag if your application requires only public library extensiongenerator
#! \param DEFINES                       list of define flags to add at compilation time
#! \param CXX_FLAGS                     list of compiler flags to add (such as warning levels (-Wall ...)).
#! \param ADDITIONAL_SOURCES            list of additional sources (that cannot be automatically
#!                                      found by gather_headers_and_sources macro)
#! \param QRC_SOURCES                   list of .qrc resource file to include in your application (only
#!                                      checked when SOURCES is provided)
#! \param CEP_NAME                      specify the CEP_NAME, which is used to categorized the 
#!                                      application for packaging purpose
#!                                      No CEP_NAME provided will result in default categorization (generic application).
#! \param DESCRIPTION                   Simple description of the application. Used for packaging presentation
#!                                      for instance.
#! \param INCLUDE_DIRECTORIES           additional include directories
#! \param EXTERNAL_LIBRARIES            external libraries to add to the link command
#! \param EXTRA_TRANSLATE_LANGUAGE      Additionnal extra language to translate the application
#!
macro(camitk_application)

    # Instruct CMake to run moc automatically when needed.
    set(CMAKE_AUTOMOC ON)

    #########################################################################
    #                                                                       #
    #   ARGUMENTS PARSING                                                   #
    #                                                                       #
    #   * Use a macro to create the CMAKE variables according to the        #
    #     provided options as input.                                        #
    #                                                                       #
    #########################################################################

    get_directory_name(${CMAKE_CURRENT_SOURCE_DIR} APPLICATION_NAME)

    set(options DISABLED NO_GUI NEEDS_ITK NEEDS_XSD NEEDS_XERCESC NEEDS_PYTHON INTERNAL_TEST_APPLICATION NO_CAMITKCORE_REQUIRED NEEDS_EXTENSIONGENERATOR QTEST TEST_RUN_SERIAL)
    set(oneValueArgs APPLICATION_NAME)
    set(multiValueArgs SOURCES QRC_SOURCES NEEDS_CEP_LIBRARIES NEEDS_TOOL NEEDS_COMPONENT_EXTENSION NEEDS_ACTION_EXTENSION NEEDS_VIEWER_EXTENSION DEFINES CXX_FLAGS ADDITIONAL_SOURCES CEP_NAME DESCRIPTION EXTERNAL_LIBRARIES INCLUDE_DIRECTORIES EXTRA_TRANSLATE_LANGUAGE )
    cmake_parse_arguments(${APPLICATION_NAME_CMAKE} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )



    #########################################################################
    #                                                                       #
    #   CREATE CMAKE VARIABLES                                              #
    #                                                                       #
    #   * Create required and useful CMake variables for the macro         #
    #                                                                       #
    #########################################################################

    # CMAKE CACHE VARIABLE
    # if it is the first cmake run, create the application variable with a correct initial value
    if(NOT APPLICATION_${APPLICATION_NAME_CMAKE}_INTERNAL)
        # add option to enable/disable this extension and set it to true by default
        # Building the extension can be disabled by giving the argument DISABLED to the macro
        # or by passing the flag -D${TYPE_EXTENSION_CMAKE}_${APPLICATION_NAME_CMAKE}_DISABLED:BOOL=TRUE
        if(${APPLICATION_NAME_CMAKE}_DISABLED)
            set(APPLICATION_${APPLICATION_NAME_CMAKE}_ENABLED FALSE)
        else()
            set(APPLICATION_${APPLICATION_NAME_CMAKE}_ENABLED TRUE)
        endif()
        set(APPLICATION_${APPLICATION_NAME_CMAKE} ${APPLICATION_${APPLICATION_NAME_CMAKE}_ENABLED} CACHE BOOL "Build application ${APPLICATION_NAME}")
        set(APPLICATION_${APPLICATION_NAME_CMAKE}_INTERNAL TRUE CACHE INTERNAL "Is variable APPLICATION_${APPLICATION_NAME} already created?")
    endif()

    if(${APPLICATION_NAME_CMAKE}_APPLICATION_NAME)
        set(APPLICATION_EXECUTABLE_NAME ${${APPLICATION_NAME_CMAKE}_APPLICATION_NAME})
    else()
        set(APPLICATION_EXECUTABLE_NAME ${APPLICATION_NAME})
    endif()

    if(${APPLICATION_NAME_CMAKE}_APPLICATION_NAME)
        set(APPLICATION_EXECUTABLE_NAME ${${APPLICATION_NAME_CMAKE}_APPLICATION_NAME})
    else()
        set(APPLICATION_EXECUTABLE_NAME ${APPLICATION_NAME})
    endif()

    #########################################################################
    #                                                                       #
    #   set APPLICATION TARGET NAME                                         #
    #   → prefixed with either "test" or "application"                      #
    #                                                                       #
    #########################################################################

    if (${APPLICATION_NAME_CMAKE}_INTERNAL_TEST_APPLICATION)
        set(APPLICATION_TARGET_PREFIX "test")
    else()
        set(APPLICATION_TARGET_PREFIX "application")
    endif()

    if (PACKAGING_NSIS)
        # NSIS requires that cpack component names do not feature space or "-" characters
        set(APPLICATION_TARGET_NAME ${APPLICATION_TARGET_PREFIX}_${APPLICATION_EXECUTABLE_NAME})
    else()
        set(APPLICATION_TARGET_NAME ${APPLICATION_TARGET_PREFIX}-${APPLICATION_EXECUTABLE_NAME})
    endif()



    # if this extension is enabled, do everything needed
    # otherwise... do nothing
    if (APPLICATION_${APPLICATION_NAME_CMAKE})

        message(STATUS "Building application ${APPLICATION_TARGET_NAME}")



        #########################################################################
        #                                                                       #
        #   INCLUDE DIRECTORIES                                                 #
        #                                                                       #
        #   * Include basic directories where to look header files              #
        #   * Include also additional user provided directories                 #
        #   * These directories are used for compilation step                   #
        #                                                                       #
        #########################################################################
        # BASIC DIRECTORIES
        include_directories(${CMAKE_CURRENT_SOURCE_DIR})
        include_directories(${CMAKE_CURRENT_BINARY_DIR})
        include_directories(${CAMITK_INCLUDE_DIRECTORIES})

        # USER INPUT DIRECTORIES
        include_directories(${${APPLICATION_NAME_CMAKE}_INCLUDE_DIRECTORIES})



        #########################################################################
        #                                                                       #
        #   GATHER RESOURCES                                                   #
        #                                                                       #
        #   * get all the headers (.h) and source files (.cpp) of the project   #
        #   * create the needed Qt files (using moc and uic)                    #
        #   * On Windows, Visual Studio, group .moc and .ui files               #
        #     in subdirectories                                                 #
        #                                                                       #
        #########################################################################
        set(${APPLICATION_NAME}_SOURCES) # reset for multiple application in the same directory

        if (NOT ${APPLICATION_NAME_CMAKE}_SOURCES)
            # get all headers, sources and do what is needed for Qt
            # one need to do this just before the add_library so that all defines, include directories and link directories
            # are set properly (gather_headers_and_sources include the call to Qt moc and uic)
            gather_headers_and_sources(${APPLICATION_NAME})
        else()
            # check for QRC
            if (${APPLICATION_NAME_CMAKE}_QRC_SOURCES)
                # add resource file 
                qt_add_resources(${APPLICATION_NAME}_SOURCES ${${APPLICATION_NAME_CMAKE}_QRC_SOURCES})
                # On Windows, Visual Studio, organize files in subdirectories
                if(MSVC)
                    source_group("Source Files\\Resources Files" REGULAR_EXPRESSION "^qrc_.*")
                    source_group("Source Files\\Resources Files" REGULAR_EXPRESSION ".*\\.qrc$")
                endif()
            endif()
        endif()



        #########################################################################
        #                                                                       #
        #   TARGET COMPILATION  DEFINITION                                      #
        #                                                                       #
        #   * Additional sources files to consider at compilation (.cpp)        #
        #   * CMake project target definition                                   #
        #                                                                       #
        #########################################################################
        # Additional SOURCES
        set(${APPLICATION_NAME}_SOURCES ${${APPLICATION_NAME}_SOURCES} ${${APPLICATION_NAME_CMAKE}_ADDITIONAL_SOURCES} ${${APPLICATION_NAME_CMAKE}_SOURCES})

        # APPLE BUNDLE DEFINITIONS
        if(APPLE)
            set(MACOSX_BUNDLE_INFO_STRING "${APPLICATION_TARGET_NAME} ${CAMITK_SHORT_VERSION_STRING}")
            set(MACOSX_BUNDLE_BUNDLE_VERSION "${APPLICATION_TARGET_NAME} ${CAMITK_SHORT_VERSION_STRING}")
            set(MACOSX_BUNDLE_LONG_VERSION_STRING "${APPLICATION_TARGET_NAME} ${CAMITK_SHORT_VERSION_STRING}")
            set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${CAMITK_SHORT_VERSION_STRING}")
            set(MACOSX_BUNDLE_COPYRIGHT "Univ. Grenoble Alpes")
            set(MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/resources/camitk-${APPLICATION_NAME}.icns")
            set(MACOSX_BUNDLE_BUNDLE_NAME "${APPLICATION_TARGET_NAME}")

            set(MACOSX_BUNDLE_RESOURCES "${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_TARGET_NAME}.app/Contents/Resources")
            set(MACOSX_BUNDLE_ICON "${MACOSX_BUNDLE_ICON_FILE}")
            execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${MACOSX_BUNDLE_RESOURCES})
            execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${MACOSX_BUNDLE_ICON} ${MACOSX_BUNDLE_RESOURCES})
        endif()



        #########################################################################
        #                                                                       #
        #   ADDITIONAL KNOWN LIBRARY DEPENDENCIES                               #
        #                                                                       #
        #   * Look for specific library needed                                  #
        #   * Specific libraries are specified as option with the               #
        #     NEEDS_LIBRARY syntax (see macro syntax for more options)          #
        #   * Backward compatibility : Warn user if using old NEEDS_TOOL syntax #
        #                                                                       #
        #########################################################################

        # Looking for ITK
        set(ITK_LIBRARIES "")
        if(${APPLICATION_NAME_CMAKE}_NEEDS_ITK)
            find_package(ITK REQUIRED)
            if(ITK_FOUND)
                include(${ITK_USE_FILE})
                set(ITK_VERSION ${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}.${ITK_VERSION_PATCH}) #ITK_VERSION is not always set
                set(CAMITK_ITK_VERSION ${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR})
                message(STATUS "${APPLICATION_TARGET_NAME}: Found ITK version ${ITK_VERSION}")
                set(CAMITK_ITK_LIBRARIES ${ITK_LIBRARIES})
            else()
                message(FATAL_ERROR "ITK not found but required by ${APPLICATION_TARGET_NAME}")
            endif()
        endif()

        # XERCES-C
        set(XERCESC_LIBRARIES)
        if(${APPLICATION_NAME_CMAKE}_NEEDS_XERCESC)
          # XercesC is required
          find_package(XercesC REQUIRED)
          if (XERCESC_FOUND)
            include_directories(${XERCESC_INCLUDE_DIR})
            set(XERCESC_LIBRARIES ${XERCESC_LIBRARY})
          else()
            # most probably win32 or crosscompiling
            message(FATAL_ERROR "${APPLICATION_NAME}: xerces-c required. Please provide Xerces-C path.")
          endif()
        endif()

        # XSD
        if(${APPLICATION_NAME_CMAKE}_NEEDS_XSD)
            # XercesC is required
            find_package(XercesC REQUIRED)
            if (XERCESC_FOUND)
                include_directories(${XERCESC_INCLUDE_DIR})
                set(XERCESC_LIBRARIES ${XERCESC_LIBRARY})
                find_package(XSD REQUIRED)
                include_directories(${XSD_INCLUDE_DIR})
            else()
                # most probably win32 or crosscompiling
                message(FATAL_ERROR "${APPLICATION_NAME}: xerces-c required because of XSD cxx, please set XERCESC_INCLUDE_DIR")
            endif()
            # with C++11 MSVC requires explicit XSD_CXX11 flag definition
            add_definitions(-DXSD_CXX11)
        endif()

        # PYTHON
        set(PYTHON_LIBRARIES "")
        if(${APPLICATION_NAME_CMAKE}_NEEDS_PYTHON)
            message(STATUS "Python needed by ${APPLICATION_NAME}")
            find_package(PythonLibs 2.7 REQUIRED)
            if(PYTHONLIBS_FOUND)
                message(STATUS "Python found (needed by ${APPLICATION_NAME})")
                include_directories(${PYTHON_INCLUDE_DIRS})
                # PYTHON_LIBRARIES is automatically and correctly set by find_package
            else()
                message(FATAL_ERROR "Python (2.7 or above) is required by ${APPLICATION_NAME} : please add your python installation dir to your PATH environment variable")
            endif()
        endif()



        #########################################################################
        #                                                                       #
        #   LINK DIRECTORIES                                                    #
        #                                                                       #
        #   * Link directories are used to indicate the compiler where          #
        #     to look for folder containing libraries to link with.             #
        #                                                                       #
        #########################################################################
        # CAMITK BASIC LIB DIRECTORIES
        link_directories(${CAMITK_LINK_DIRECTORIES})



        #########################################################################
        #                                                                       #
        #   TARGET COMPILATION DEFINITION                                       #
        #                                                                       #
        #   * Additional sources files to consider at compilation (.cpp)        #
        #   * CMake project target definition                                   #
        #                                                                       #
        #########################################################################
        # CMAKE TARGET DEFINITION
        # add_executable(${APPLICATION_TARGET_NAME} ${${APPLICATION_NAME}_SOURCES})
		if(WIN32 AND NOT ${APPLICATION_NAME_CMAKE}_NO_GUI)
			 add_executable(${APPLICATION_TARGET_NAME} WIN32 ${${APPLICATION_NAME}_SOURCES})
		else()
			 add_executable(${APPLICATION_TARGET_NAME} ${${APPLICATION_NAME}_SOURCES})
		endif()

        #########################################################################
        #                                                                       #
        #   QT LINKING LIBRARIES                                                #
        #                                                                       #
        #   * Set at linking the Qt libraries                                  #
        #                                                                       #
        #########################################################################
        # target_link_libraries(${APPLICATION_TARGET_NAME} PRIVATE ${CAMITK_QT_LIBRARIES})



        #########################################################################
        #                                                                       #
        #   CAMITK ACTION / COMPONENT / LIBRARIES DEPENDENCIES                  #
        #                                                                       #
        #   * Look for action / component / libraries dependencies              #
        #   * Specific actions / components / libraries are specified as option #
        #     with the NEEDS_ACTION/COMPONENT_EXTENSION/CEP_LIBRARIES syntax    #
        #   * Add dependencies to library-camitkcore and the testing            #
        #     action/component if test are runned on it                         #
        #                                                                       #
        #########################################################################

        # 1) CAMITKCORE LIBRARY DEPENDENCY
        # add the target dependency (i.e., enable proper parallelization of the build process
        # only if inside the sdk build
        if(CAMITK_COMMUNITY_EDITION_BUILD AND NOT ${APPLICATION_NAME_CMAKE}_NO_CAMITKCORE_REQUIRED)
            add_dependencies(${APPLICATION_TARGET_NAME} ${CAMITK_CORE_TARGET_LIB_NAME})
            # add the dependency to the core automoc target
            set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS ${CAMITK_CORE_TARGET_LIB_NAME})
        endif()
        # 1.2) EXTENSION GENERATOR
        if (${APPLICATION_NAME_CMAKE}_NEEDS_EXTENSIONGENERATOR)
            add_dependencies(${APPLICATION_TARGET_NAME} ${CAMITK_EXTENSIONGENERATOR_TARGET_LIB_NAME})
            # add the dependency to the core automoc target
            set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS ${CAMITK_EXTENSIONGENERATOR_TARGET_LIB_NAME})
        endif()


        # 2) COMPONENTS DEPENDENCIES
        if (${APPLICATION_NAME_CMAKE}_NEEDS_COMPONENT_EXTENSION)
            set(COMPONENTS_DEPENDENCY_LIST "") #use for generating the project.xml file
            foreach(COMPONENT_NEEDED ${${APPLICATION_NAME_CMAKE}_NEEDS_COMPONENT_EXTENSION})
                # include directories from build, camitk (local or global install).
                include_directories(${CAMITK_BUILD_INCLUDE_DIR}/components/${COMPONENT_NEEDED})
                include_directories(${CAMITK_INCLUDE_DIR}/components/${COMPONENT_NEEDED})
                # file dependency
                if (MSVC)
                    list(APPEND COMPONENT_EXTENSION_LIBRARIES
                                                    debug ${CAMITK_BUILD_PRIVATE_LIB_DIR}/components/${COMPONENT_NEEDED}${CAMITK_DEBUG_POSTFIX}.lib
                                                    optimized ${COMPONENT_NEEDED}
                    )
                else()
                    list(APPEND COMPONENT_EXTENSION_LIBRARIES ${COMPONENT_NEEDED})
                endif()
                # CMake / CDash dependencies
                if (PACKAGING_NSIS)
                    add_dependencies(${APPLICATION_TARGET_NAME} component_${COMPONENT_NEEDED})
                    # add the dependency to the component automoc target
                    set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS component_${COMPONENT_NEEDED})
                else()
                    add_dependencies(${APPLICATION_TARGET_NAME} component-${COMPONENT_NEEDED})
                    list(APPEND COMPONENTS_DEPENDENCY_LIST component-${COMPONENT_NEEDED})
                    # add the dependency to the component automoc target
                    set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS component-${COMPONENT_NEEDED})
                endif()
            endforeach()
        endif()

        # 3) ACTIONS DEPENDENCIES
        if(${APPLICATION_NAME_CMAKE}_NEEDS_ACTION_EXTENSION)
            set(ACTIONS_DEPENDENCY_LIST "") #use for generating the project.xml file
            foreach(ACTION_NEEDED ${${APPLICATION_NAME_CMAKE}_NEEDS_ACTION_EXTENSION})
                # include directories from build, camitk (local or global install).
                include_directories(${CAMITK_BUILD_INCLUDE_DIR}/actions/${ACTION_NEEDED})
                include_directories(${CAMITK_INCLUDE_DIR}/actions/${ACTION_NEEDED})
                # file dependency
                if (MSVC)
                    list(APPEND ACTION_EXTENSION_LIBRARIES
                                                   debug ${CAMITK_BUILD_PRIVATE_LIB_DIR}/actions/${ACTION_NEEDED}${CAMITK_DEBUG_POSTFIX}.lib
                                                   optimized ${ACTION_NEEDED}
                    )
                else()
                    list(APPEND ACTION_EXTENSION_LIBRARIES ${ACTION_NEEDED})
                endif()
                # CMake / CDash dependencies
                if (PACKAGING_NSIS)
                    add_dependencies(${APPLICATION_TARGET_NAME} action_${ACTION_NEEDED})
                    # add the dependency to the action automoc target
                    set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS action_${ACTION_NEEDED})
                else()
                    add_dependencies(${APPLICATION_TARGET_NAME} action-${ACTION_NEEDED})
                    list(APPEND ACTIONS_DEPENDENCY_LIST action-${ACTION_NEEDED})
                    # add the dependency to the action automoc target
                    set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS action-${ACTION_NEEDED})
                endif()
            endforeach()
        endif()

        # 4) VIEWERS DEPENDENCIES
        # differentiate SDK from other applications
        if(${APPLICATION_NAME_CMAKE}_NEEDS_VIEWER_EXTENSION)
            set(VIEWERS_DEPENDENCY_LIST "") #use for generating the project.xml file
            foreach(VIEWER_NEEDED ${${APPLICATION_NAME_CMAKE}_NEEDS_VIEWER_EXTENSION})
                # include directories from build, camitk (local or global install).
                include_directories(${CAMITK_BUILD_INCLUDE_DIR}/viewers/${VIEWER_NEEDED})
                include_directories(${CAMITK_INCLUDE_DIR}/viewers/${VIEWER_NEEDED})
                # library dependency
                if (MSVC)
                    list(APPEND VIEWER_EXTENSION_LIBRARIES
                                                   debug ${CAMITK_BUILD_PRIVATE_LIB_DIR}/viewers/${VIEWER_NEEDED}${CAMITK_DEBUG_POSTFIX}.lib
                                                   optimized ${VIEWER_NEEDED}
                    )
                else()
                    list(APPEND VIEWER_EXTENSION_LIBRARIES ${VIEWER_NEEDED})
                endif()
                # CMake / CDash dependencies
                if (PACKAGING_NSIS)
                    add_dependencies(${APPLICATION_TARGET_NAME} viewer_${VIEWER_NEEDED})
                    # add the dependency to the viewer automoc target
                    set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS viewer_${VIEWER_NEEDED})
                else()
                    add_dependencies(${APPLICATION_TARGET_NAME} viewer-${VIEWER_NEEDED})
                    list(APPEND VIEWERS_DEPENDENCY_LIST viewer-${VIEWER_NEEDED})
                    # add the dependency to the viewer automoc target
                    set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS viewer-${VIEWER_NEEDED})
                endif()
            endforeach()
        endif()

        # 5) CEP LIBRARIES DEPENDENCIES
        if(${APPLICATION_NAME_CMAKE}_NEEDS_CEP_LIBRARIES)
            set(CEP_LIBRARIES_DEPENDENCY_LIST "") #use for generating the project.xml file
            foreach(CEP_LIBRARY_NEEDED ${${APPLICATION_NAME_CMAKE}_NEEDS_CEP_LIBRARIES})
                # include directories from build, camitk (local or global install).
                include_directories(${CAMITK_BUILD_INCLUDE_DIR}/libraries/${CEP_LIBRARY_NEEDED})
                include_directories(${CAMITK_INCLUDE_DIR}/libraries/${CEP_LIBRARY_NEEDED})
                # file dependency
                if (MSVC)
                    list(APPEND CEP_LIBRARIES debug ${CEP_LIBRARY_NEEDED}${CAMITK_DEBUG_POSTFIX}.lib
                                              optimized ${CEP_LIBRARY_NEEDED}
                    )
                else()
                    list(APPEND CEP_LIBRARIES ${CEP_LIBRARY_NEEDED})
                endif()
                # CMake / CDash dependencies
                if (PACKAGING_NSIS)
                    add_dependencies(${APPLICATION_TARGET_NAME} library_${CEP_LIBRARY_NEEDED})
                    # add the dependency to the library automoc target
                    set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS library_${CEP_LIBRARY_NEEDED})
                else()
                    add_dependencies(${APPLICATION_TARGET_NAME} library-${CEP_LIBRARY_NEEDED})
                    list(APPEND CEP_LIBRARIES_DEPENDENCY_LIST library-${CEP_LIBRARY_NEEDED})
                    # add the dependency to the library automoc target
                    set_property(TARGET ${APPLICATION_TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS library-${CEP_LIBRARY_NEEDED})
                endif()
            endforeach()
        endif()



        #########################################################################
        #                                                                       #
        #   COMPILATION FLAG                                                    #
        #                                                                       #
        #   * Flags are options to give to the compiler                         #
        #   * Add user input flags                                              #
        #   * Add platform specific flags                                       #
        #                                                                       #
        #########################################################################

        # USER INPUT COMPILER FLAG
        if(${APPLICATION_NAME_CMAKE}_DEFINES)
          foreach (FLAG ${${APPLICATION_NAME_CMAKE}_DEFINES})
            add_definitions(-D${FLAG})
          endforeach()
        endif()

        # USER INPUT CUSTOM COMPILER FLAG
        if(${APPLICATION_NAME_CMAKE}_CXX_FLAGS)
          foreach (FLAG ${${APPLICATION_NAME_CMAKE}_CXX_FLAGS})
            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}")
          endforeach()
        endif()



        #########################################################################
        #                                                                       #
        #   LINKING                                                             #
        #                                                                       #
        #   * Linking is the last stage of compilation                          #
        #   * Indicate what libraries to use for linking the target             #
        #                                                                       #
        #########################################################################
        # LINKING LIBRARIES
        if (NOT ${APPLICATION_NAME_CMAKE}_NO_CAMITKCORE_REQUIRED)
            target_link_libraries(${APPLICATION_TARGET_NAME} PRIVATE ${CAMITK_CORE_LIBRARIES} ${CAMITK_LIBRARIES})
        else()
            if (${APPLICATION_NAME_CMAKE}_NEEDS_EXTENSIONGENERATOR)
                target_link_libraries(${APPLICATION_TARGET_NAME} PRIVATE ${CAMITK_EXTENSIONGENERATOR_LIBRARY})
            endif()
        endif()
        # Link other dependencies
        target_link_libraries(${APPLICATION_TARGET_NAME} PRIVATE ${COMPONENT_EXTENSION_LIBRARIES} ${ACTION_EXTENSION_LIBRARIES} ${VIEWER_EXTENSION_LIBRARIES} ${CEP_LIBRARIES} ${XERCESC_LIBRARY} ${CAMITK_ITK_LIBRARIES} ${PYTHON_LIBRARIES} ${${APPLICATION_NAME_CMAKE}_EXTERNAL_LIBRARIES} ${CAMITK_QT_LIBRARIES})

        # for VTK9, see https://docs.vtk.org/en/latest/advanced/migration_guides/ModuleMigration.html
        if("${VTK_VERSION}" VERSION_GREATER_EQUAL 9.0)
            vtk_module_autoinit(
                TARGETS ${APPLICATION_TARGET_NAME}
                MODULES ${CAMITK_VTK_LIBRARIES})
        endif()

        #########################################################################
        #                                                                       #
        #   OUTPUT                                                              #
        #                                                                       #
        #   * Define the output directory (location and name)                   #
        #   * Define the output name of the library                             #
        #   * Add ${CAMITK_DEBUG_POSTFIX} suffix to Debug MSVC built libraries  #
        #                                                                       #
        #########################################################################
        if (${APPLICATION_NAME_CMAKE}_INTERNAL_TEST_APPLICATION)
            set(EXECUTABLE_OUTPUT_NAME "test-${APPLICATION_EXECUTABLE_NAME}")
        else()
            set(EXECUTABLE_OUTPUT_NAME "camitk-${APPLICATION_EXECUTABLE_NAME}")
        endif()

        # OUTPUT NAME
        if (${APPLICATION_NAME_CMAKE}_INTERNAL_TEST_APPLICATION)
            set(EXECUTABLE_OUTPUT_NAME "test-${APPLICATION_EXECUTABLE_NAME}")
        else()
            set(EXECUTABLE_OUTPUT_NAME "camitk-${APPLICATION_EXECUTABLE_NAME}")
        endif()

        if (MSVC)
            set_target_properties(${APPLICATION_TARGET_NAME}
                                  PROPERTIES OUTPUT_NAME ${EXECUTABLE_OUTPUT_NAME}
                                  DEBUG_POSTFIX ${CAMITK_DEBUG_POSTFIX}
            )
        else()
            set_target_properties(${APPLICATION_TARGET_NAME}
                                  PROPERTIES OUTPUT_NAME ${EXECUTABLE_OUTPUT_NAME}
            )
        endif()

        # OUTPUT DIRECTORY LOCATION
        # always in bin folder
        set_target_properties(${APPLICATION_TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CAMITK_BUILD_BIN_DIR}
                                                                    RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CAMITK_BUILD_BIN_DIR}
                                                                    RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CAMITK_BUILD_BIN_DIR}
        )

        #########################################################################
        #                                                                       #
        #   INSTALLATION                                                        #
        #                                                                       #
        #   * When installing the project, header files (.h) and test data are  #
        #     copied into a installation folder to determine.                   #
        #   * Indicate in this section, where to install your project and which #
        #     files to copy into that folder (during local/global installation) #
        #                                                                       #
        #########################################################################

        # FOLDER INSTALLATION
        if (NOT ${APPLICATION_NAME_CMAKE}_INTERNAL_TEST_APPLICATION)
            message(STATUS "Installing application ${APPLICATION_EXECUTABLE_NAME} in ${CMAKE_INSTALL_BINDIR}")        
            install(TARGETS ${APPLICATION_TARGET_NAME}
                    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
                    COMPONENT ${APPLICATION_TARGET_NAME}
            )
        else()
            message(STATUS "Internal test application ${APPLICATION_EXECUTABLE_NAME} won't be installed.")
        endif()



        #########################################################################
        #                                                                       #
        #   CDASH SUBPROJECT DESCRIPTION                                        #
        #                                                                       #
        #   * Update the XML descriton of the subprojects dependenicies         #
        #     for CDash.                                                        #
        #                                                                       #
        #########################################################################
        # CDASH XML SUBPROJECTS DESCRIPTION UPDATE
        if (NOT ${APPLICATION_NAME_CMAKE}_NO_CAMITKCORE_REQUIRED)
            # We will add manually the CDash dependencies of the testing applications
            # See CamiTKCDashPublishSubProject.cmake
            camitk_register_subproject(APPLICATION ${APPLICATION_TARGET_NAME} DEPENDENCIES library-camitkcore ${COMPONENTS_DEPENDENCY_LIST} ${ACTIONS_DEPENDENCY_LIST} ${VIEWERS_DEPENDENCY_LIST} ${CEP_LIBRARIES_DEPENDENCY_LIST})
#         endif()
        else()
            camitk_register_subproject(APPLICATION ${APPLICATION_TARGET_NAME} DEPENDENCIES ${CEP_LIBRARIES_DEPENDENCY_LIST})
        endif()

        #####################################################################################
        #                                                                                   #
        #   TRANSLATION                                                                     #
        #                                                                                   #
        #   * CAMITK_TRANSLATIONS contains the list of language to translate                #
        #    the QString to.                                                                #
        #                                                                                   #
        #   * Create the translate.pro file which contains 4 sections:                      #
        #        - HEADERS:      list of .h/.hpp files to look for tr("") QString           #
        #        - SOURCES:      list of .cpp files to look for tr("") QString              #
        #        - FORMS:        list of .ui files to look for tr("") QString               #
        #        - TRANSLATIONS: list of .ts files which use CAMITK_TRANSLATIONS            #
        #            to define each .ts file                                                #
        #                                                                                   #
        #    * Execute lupdate program to update the .ts files with new QString             #
        #          found.                                                                   #
        #                                                                                   #
        #   * Execute lrelease program to create .qm files (binary equivalent of            #
        #       .ts files                                                                   #
        #                                                                                   #
        #   * Create translate.qrc which contains the list of .qm files.                    #
        #   * Create the flags.qrc file which contains the list of .png flags               #
        #         images                                                                    #
        #                                                                                   #
        #####################################################################################
        if(CAMITK_TRANSLATE)
            if(${APPLICATION_NAME_CMAKE}_EXTRA_TRANSLATE_LANGUAGE)
                camitk_translate(EXTRA_LANGUAGE ${${APPLICATION_NAME_CMAKE}_EXTRA_TRANSLATE_LANGUAGE})
            else()
                camitk_translate()
            endif()
        endif()


        #########################################################################
        #                                                                       #
        #   PACKAGING CATEGORIZATION                                            #
        #                                                                       #
        #   * On Windows, when building a package (win32 installer), the        #
        #     install shield wizard proposes you to select which component      #
        #     to install.                                                       #
        #   * Each component to install has a short description following its   #
        #     name to understand its role.                                      #
        #   * This section deals with the categorization and the description    #
        #     of the component in this installer.                               #
        #                                                                       #
        #########################################################################

        if(NOT ${APPLICATION_NAME_CMAKE}_INTERNAL_TEST_APPLICATION)
            # WINDOWS INSTALLER CATEGORIZATION
            if(${APPLICATION_NAME_CMAKE}_CEP_NAME)
                if (${APPLICATION_NAME_CMAKE}_CEP_NAME MATCHES "SDK")
                    # The default SDK extensions are categorized as "required" and are not "unselectable" by the user at installation time
                    cpack_add_component(${APPLICATION_TARGET_NAME}
                                        DISPLAY_NAME ${APPLICATION_TARGET_NAME}
                                        DESCRIPTION ${${APPLICATION_NAME_CMAKE}_DESCRIPTION}
                                        REQUIRED
                                        GROUP SDK
                                        )

                else()
                    # Extension is selectable for installation in the wizard of the installer
                    cpack_add_component(${APPLICATION_TARGET_NAME}
                                        DISPLAY_NAME ${APPLICATION_TARGET_NAME}
                                        DESCRIPTION ${${APPLICATION_NAME_CMAKE}_DESCRIPTION}
                                        GROUP ${${APPLICATION_NAME_CMAKE}_CEP_NAME}
                                        )
                endif()
            else()
                # Extension if not categorized for packaging presentation
                cpack_add_component(${APPLICATION_TARGET_NAME}
                                    DISPLAY_NAME ${APPLICATION_TARGET_NAME}
                                    DESCRIPTION ${${APPLICATION_NAME_CMAKE}_DESCRIPTION}
                                    )

            endif()

            # additional unix system files/resources
            if(UNIX)
                # Man page installation
                set(${APPLICATION_NAME_CMAKE}_MAN_PAGE ${CMAKE_CURRENT_SOURCE_DIR}/resources/camitk-${APPLICATION_NAME}.1)
                if (EXISTS ${${APPLICATION_NAME_CMAKE}_MAN_PAGE})
                    message(STATUS "Found man page for ${APPLICATION_TARGET_NAME}")
                    install(FILES ${${APPLICATION_NAME_CMAKE}_MAN_PAGE}
                            DESTINATION ${CAMITK_APPLICATION_MAN_INSTALL_DIR}
                    )
                else()
                    # check if .in exists
                    if (EXISTS "${${APPLICATION_NAME_CMAKE}_MAN_PAGE}.in")
                        message(STATUS "Found man page configuration file for ${APPLICATION_TARGET_NAME}")
                        install(CODE "message(STATUS \"Updating ${APPLICATION_NAME} man page (version ${CAMITK_VERSION_MAJOR}.${CAMITK_VERSION_MINOR} as of ${CURRENT_DATE})\")")
                        # set variable in sub-cmake shell
                        install(CODE "set(APPLICATION_NAME ${APPLICATION_NAME})")
                        install(CODE "set(CURRENT_DATE ${CURRENT_DATE})")
                        install(CODE "set(CAMITK_VERSION_MAJOR ${CAMITK_VERSION_MAJOR})")
                        install(CODE "set(CAMITK_VERSION_MINOR ${CAMITK_VERSION_MINOR})")
                        # remove previous version
                        install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/camitk-${APPLICATION_NAME}.1)")
                        # configure current version
                        install(CODE "configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/camitk-${APPLICATION_NAME}.1.in ${CMAKE_CURRENT_BINARY_DIR}/camitk-${APPLICATION_NAME}.1 @ONLY)")
                        # install file
                        install(FILES ${CMAKE_CURRENT_BINARY_DIR}/camitk-${APPLICATION_NAME}.1 DESTINATION ${CAMITK_APPLICATION_MAN_INSTALL_DIR})
                    endif()
                endif()

                # Desktop file
                set(${APPLICATION_NAME_CMAKE}_DESKTOP ${CMAKE_CURRENT_SOURCE_DIR}/resources/camitk-${APPLICATION_NAME}.desktop)
                if (EXISTS ${${APPLICATION_NAME_CMAKE}_DESKTOP})
                    message(STATUS "Found desktop file for ${APPLICATION_TARGET_NAME}")
                    install(FILES ${${APPLICATION_NAME_CMAKE}_DESKTOP} DESTINATION ${CAMITK_APPLICATION_DESKTOP_INSTALL_DIR})
                endif()

                # application pixmap
                set(${APPLICATION_NAME_CMAKE}_PIXMAP ${CMAKE_CURRENT_SOURCE_DIR}/resources/camitk-${APPLICATION_NAME}.xpm)
                if (EXISTS ${${APPLICATION_NAME_CMAKE}_PIXMAP})
                    message(STATUS "Found pixmap for ${APPLICATION_TARGET_NAME}")
                    install(FILES ${${APPLICATION_NAME_CMAKE}_PIXMAP} DESTINATION ${CAMITK_APPLICATION_PIXMAP_INSTALL_DIR})
                endif()

            endif()

        endif() # NOT ${APPLICATION_NAME_CMAKE}_INTERNAL_TEST_APPLICATION


        #########################################################################
        #                                                                       #
        #   INTERNAL_TEST_APPLICATION default test                              #
        #                                                                       #
        #########################################################################
        if (${APPLICATION_NAME_CMAKE}_INTERNAL_TEST_APPLICATION)
    
            if(${APPLICATION_NAME_CMAKE}_QTEST)
                # separate tests 
                if (${APPLICATION_NAME_CMAKE}_TEST_RUN_SERIAL)
                    qtest_discover_tests(${APPLICATION_TARGET_NAME}
                                        TEST_PREFIX ${EXECUTABLE_OUTPUT_NAME}
                                        PROPERTIES RUN_SERIAL TRUE)
                else()
                    qtest_discover_tests(${APPLICATION_TARGET_NAME}
                                         TEST_PREFIX ${EXECUTABLE_OUTPUT_NAME})
                endif()
            else()
                # internal test but not using Qtest
                camitk_init_test(${EXECUTABLE_OUTPUT_NAME})
                # default test: run application without any parameters
                camitk_add_test(PROJECT_NAME ${EXECUTABLE_OUTPUT_NAME})         
            endif()
        endif()

    endif() #APPLICATION_${APPLICATION_NAME_CMAKE}

endmacro()
