##*************************************************************************##
##  CUBE        http://www.scalasca.org/                                   ##
##*************************************************************************##
##  Copyright (c) 2024-2025                                                ##
##  Forschungszentrum Juelich GmbH, Juelich Supercomputing Centre          ##
##                                                                         ##
##  This software may be modified and distributed under the terms of       ##
##  a BSD-style license.  See the COPYING file in the package base         ##
##  directory for details.                                                 ##
##*************************************************************************##


#####################################################################################
# creates cube cubegui library and executable
#####################################################################################

#####################################################################################
# headers and sources
#####################################################################################

# headers to be installed
list(APPEND CUBEGUI_HEADERS_PUBLIC
    ${CMAKE_BINARY_DIR}/src/cubegui-config.h
    ${CMAKE_BINARY_DIR}/src/cubegui-version.h
    AggregatedTreeItem.h
    ColorMap.h
    Constants.h
    Future.h
    Globals.h
    SettingsHandler.h
    TabInterface.h
    Task.h
    TreeItem.h
    TreeItemMarker.h
    plugins/ContextFreePlugin.h
    plugins/ContextFreeServices.h
    plugins/CubePlugin.h
    plugins/PluginInterface.h
    plugins/PluginServiceExports.h
    plugins/PluginServices.h
    plugins/ValueView.h
    utils/Compatibility.h
    utils/RemoteFileDialog.h
    utils/StatisticalInformation.h
)

if (Qt${QT_VERSION_MAJOR}WebEngineWidgets_FOUND)
   list( APPEND OPTIONAL_SOURCES utils/HtmlWidgetWebEngine.cpp utils/HtmlWidgetWebEngine.h )
endif()

file(GLOB CUBEGUI_HEADERS_ALL "*.h" "utils/*.h" "plugins/*.h")

# use either TCP sockets (default) or WebSockets (Webassembly only)
if (WEB_SOCKETS)
   list(APPEND CUBEGUI_SOURCES CubeQtWebSocket.cpp)
   list(APPEND OPTIONAL_LINK_LIBRARIES Qt::WebSockets)
   list(REMOVE_ITEM CUBEGUI_HEADERS_ALL "${CMAKE_CURRENT_SOURCE_DIR}/CubeQtStreamSocket.h")
   message( ${CUBEGUI_HEADERS_ALL})
   message( ${CMAKE_CURRENT_SOURCE_DIR}/CubeQtStreamSocket.h )
else()
   list(APPEND CUBEGUI_SOURCES CubeQtStreamSocket.cpp)
   list(REMOVE_ITEM CUBEGUI_HEADERS_ALL "${CMAKE_CURRENT_SOURCE_DIR}/CubeQtWebSocket.h")
endif()

###
list(APPEND CUBEGUI_SOURCES
    AggregatedTreeItem.cpp
    CallTree.cpp
    CallTreeLabelDialog.cpp
    CallTreeView.cpp
    CubeWriter.cpp
    DefaultCallTree.cpp
    DefaultColorMap.cpp
    DefaultValueView.cpp
    DimensionOrderDialog.cpp
    FlatTree.cpp
    FlatTreeView.cpp
    Future.cpp
    Globals.cpp
    MainWidget.cpp
    MetricTree.cpp
    MetricTreeView.cpp
    PrecisionWidget.cpp
    Settings.cpp
    SettingsToolBar.cpp
    SynchronizationToolBar.cpp
    SystemTree.cpp
    SystemTreeView.cpp
    TabManager.cpp
    TabWidget.cpp
    TaskCallTree.cpp
    Tree.cpp
    TreeConfig.cpp
    TreeItem.cpp
    TreeItemMarker.cpp
    TreeItemMarkerDialog.cpp
    TreeModel.cpp
    TreeModelProxy.cpp
    TreeStatistics.cpp
    TreeView.cpp
    ValueWidget.cpp
    plugins/ContextFreePlugin.cpp
    plugins/ContextFreeServices.cpp
    plugins/CubePlugin.cpp
    plugins/PluginList.cpp
    plugins/PluginManager.cpp
    plugins/PluginServices.cpp
    plugins/PluginSettingDialog.cpp
    utils/BoxPlot.cpp
    utils/Chart.cpp
    utils/ColorScale.cpp
    utils/CubeApplication.cpp
    utils/DefaultMarkerLabel.cpp
    utils/DownloadThread.cpp
    utils/Environment.cpp
    utils/FindWidget.cpp
    utils/HelpBrowser.cpp
    utils/HtmlWidget.cpp
    utils/HtmlWidgetTextView.cpp
    utils/InfoWidget.cpp
    utils/PresentationCursor.cpp
    utils/ProgressBar.cpp
    utils/RemoteFileDialog.cpp
    utils/RemoteFileSystemModel.cpp
    utils/ScrollArea.cpp
    utils/StatisticalInformation.cpp
    utils/StatusBar.cpp
    utils/StyleSheetEditor.cpp
    utils/ValueModusCombo.cpp
    utils/ValueViewConfig.cpp
    utils/VersionCheck.cpp
    ${OPTIONAL_SOURCES}
    ${CUBEGUI_HEADERS_ALL} # for IDEs to display header files
)

include_directories(
    ${CMAKE_BINARY_DIR}/src # eg. cubegui-version.h
    utils/
    plugins/
)

##################################################################################
# build cubegui library: CubeGui
##################################################################################

if (NOT EMSCRIPTEN)
qt_add_library(CubeGui SHARED
    ${CUBEGUI_SOURCES}
)
endif()

##################################################################################
# special case WebAssembly
##################################################################################
if(EMSCRIPTEN)
    qt_add_library(CubeGui OBJECT
        ${CUBEGUI_SOURCES}
    )

    SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)

    target_compile_definitions(CubeGui PRIVATE LIBDIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")

    # emscription specific comiler and linker options
    # -sASYNCIFY required to use blocking dialogs
    # -Os for optimization of the executable size
    # -pthread required for POSIX threads
    # -fwasm-exceptions required to use C++ exceptions
    list(APPEND COMPILER_LINKER_OPTIONS -pthread -fexceptions)
    target_compile_options(CubeGui PUBLIC ${COMPILER_LINKER_OPTIONS})
    target_link_options(CubeGui PUBLIC ${COMPILER_LINKER_OPTIONS} -sASYNCIFY -Os)

    # static plugins
    set( PLUGINS
        advancedcolormap
        #advisor
        #barplot
        #diff
        #mean
        #merge
        #heatmap
        #launch
        #measurement
        metriceditor
        metricidentify
        popadvisor
        #scaling
        scorepconfig
        # sourcecodeviewer -> allow read/write to any files?
        statistics
        #sunburst
        systemboxplot
        systemtopology
        #tau2cube
        treeitemmarker
    )
endif()


#####################################################################################
# optional libraries
#####################################################################################

# optional package QtConcurrent
if (Qt${QT_VERSION_MAJOR}Concurrent_FOUND)
    list(APPEND OPTIONAL_LINK_LIBRARIES
        Qt::Concurrent
    )
endif()

# optional package WebEngine to display html content
if (Qt${QT_VERSION_MAJOR}WebEngineWidgets_FOUND)
    list(APPEND OPTIONAL_LINK_LIBRARIES
        Qt::WebEngineWidgets
    )
endif()
message(STATUS "Optional libraries found: ${OPTIONAL_LINK_LIBRARIES}")

# optional libraries for demangling; todo: emscripten
check_include_file_cxx(cxxabi.h CXXABI_H_AVAILABLE)
if (CXXABI_H_AVAILABLE)
     target_compile_definitions( CubeGui PRIVATE -DCXXABI_H_AVAILABLE )
else ()
    check_include_file_cxx(demangle.h DEMANGLE_H_AVAILABLE)
     if (DEMANGLE_H_AVAILABLE)
          target_compile_definitions( CubeGui PRIVATE -DDEMANGLE_H_AVAILABLE )
     else ()
          message(WARNING "Couldn't find a library to demangle symbols (cxxabi.h, demangle.h).")
     endif ()
endif ()

target_compile_definitions(CubeGui PRIVATE
    LIBDIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
)

# all plugins will need the following libraries and the include pathes
target_link_libraries(CubeGui PUBLIC
    Qt::Core
    Qt::Gui
    Qt::Widgets
    Qt::Network
    ${OPTIONAL_LINK_LIBRARIES}
    CubeLib
)

# CubeGui ist the main library which is installed and used by plugins. Therefore the required include pathes have to be
# exported to the plugins.
# $<BUILD_INTERFACE:...> is only used for building CubeGui and the internal plugins.
# $<INSTALL_INTERFACE:...> is used for building external plugins after cubegui has been installed.
target_include_directories(CubeGui PUBLIC
    $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/utils>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/plugins>
    $<INSTALL_INTERFACE:include/cubegui>
)

# set version information of the shared library
# SOVERSION = the oldest interface that the library is compatible with.
math(EXPR SOVERSION "${CUBEGUI_LIBRARY_CURRENT} - ${CUBEGUI_LIBRARY_AGE}")

set_target_properties(CubeGui
    PROPERTIES
    OUTPUT_NAME cube4gui
    SOVERSION ${SOVERSION}
    VERSION ${SOVERSION}.${CUBEGUI_LIBRARY_AGE}.${CUBEGUI_LIBRARY_REVISION}
)
##################################################################################
# build cubegui executable: cube
##################################################################################

qt_add_executable(cube
    main.cpp
    ../cubeguires.qrc
)

target_link_libraries(cube PRIVATE
    CubeGui
    ${PLUGINS} # static plugins for webassembly
)

# create a link so that cube library is found if cube is executed in the build directory
if (NOT WIN32)
    file(CREATE_LINK ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/../${CMAKE_INSTALL_LIBDIR}" SYMBOLIC)
endif()

##################################################################################
# webassembly: copy files to distribution directory instead of installing
##################################################################################

if(EMSCRIPTEN)
    message(STATUS "Creating WASM binary distribution package in: ${CMAKE_BINARY_DIR}/dist")
    add_custom_target(dist_dir
        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/dist
    )
    add_custom_target(dist
        COMMAND ${CMAKE_COMMAND} -E copy
            ${CMAKE_CURRENT_BINARY_DIR}/cube.wasm
            ${CMAKE_CURRENT_BINARY_DIR}/cube.js
            ${CMAKE_CURRENT_BINARY_DIR}/cube.html
            ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/qtloader.js
        ${CMAKE_BINARY_DIR}/dist
        COMMAND ${CMAKE_COMMAND} -E copy
            ${CMAKE_SOURCE_DIR}/COPYING
            ${CMAKE_BINARY_DIR}/dist/cubelicense.txt
        COMMENT "Creating WASM binary distribution package"
        DEPENDS cube dist_dir
    )
endif()

##################################################################################
# install cubegui library, headers, icons and executable
##################################################################################

# don't remove rpath from CubeGui library
set_target_properties(CubeGui PROPERTIES
    BUILD_WITH_INSTALL_RPATH TRUE
    INSTALL_RPATH_USE_LINK_PATH TRUE
)
install(TARGETS CubeGui
    EXPORT CubeGuiTargets # target CubeGui will be used for export configuration
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}  # for Windows import libraries
)

install(FILES
    ${CUBEGUI_HEADERS_PUBLIC}
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cubegui
)

install(TARGETS cube
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

# install all icons
install(DIRECTORY
    ${CMAKE_SOURCE_DIR}/share/icons/
    DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/cubegui
)

if (NOT WIN32)
    # set relative rpath to CubeGui library
    if(APPLE)
         set( INSTALL_RPATH "@executable_path/../lib" )
    else()
         set( INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}" )
    endif()

    # build and install with relative rpath to CubeLib because CubeLib is often not installed in a public location
    set_target_properties(cube PROPERTIES
        BUILD_WITH_INSTALL_RPATH TRUE
        INSTALL_RPATH_USE_LINK_PATH TRUE
        INSTALL_RPATH "${INSTALL_RPATH}"
    )
endif()

#####################################################################################
# create CubeGui export configuration (required for external plugins to find CubeGui)
#####################################################################################

include(CMakePackageConfigHelpers)

# install the configuration targets for find_package()
install(EXPORT CubeGuiTargets
    FILE CubeGuiTargets.cmake
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CubeGui
)
# provide version information for find_package()
write_basic_package_version_file(
    "${CMAKE_CURRENT_BINARY_DIR}/CubeGuiConfigVersion.cmake"
    VERSION ${CUBEGUI_VERSION_MAJOR}.${CUBEGUI_VERSION_MINOR}.${CUBEGUI_VERSION_PATCH}
    COMPATIBILITY AnyNewerVersion
)
# create the configuration file for find_package()
configure_package_config_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/CubeGuiConfig.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/CubeGuiConfig.cmake"
    INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CubeGui
)
install( FILES
    "${CMAKE_CURRENT_BINARY_DIR}/CubeGuiConfig.cmake"
    "${CMAKE_CURRENT_BINARY_DIR}/CubeGuiConfigVersion.cmake"
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CubeGui
)
export( EXPORT CubeGuiTargets
    FILE "${CMAKE_BINARY_DIR}/CubeGuiTargets.cmake"
)
