# List of subdirectory names
set(SUBDIRECTORIES "analysis" "buffer" "common" "formalism" "datalog" "planning")
# set(SUBDIRECTORIES "analysis" "buffer" "common" "formalism" "datalog" "planning")

# Initialize empty lists for source and header files
set(TYR_SRC_FILES "")
set(TYR_PRIVATE_HEADER_FILES "")
set(TYR_PUBLIC_HEADER_FILES "")

# Loop over the subdirectories for source files
foreach(subdir ${SUBDIRECTORIES})
    file(GLOB_RECURSE TMP_PRIVATE_HEADER_FILES "${subdir}/*.hpp" "${subdir}/**/*.hpp")
    list(APPEND TYR_PRIVATE_HEADER_FILES ${TMP_PRIVATE_HEADER_FILES})

    file(GLOB_RECURSE TMP_PUBLIC_HEADER_FILES 
        "../include/tyr/${subdir}/*.hpp" "../include/tyr/${subdir}/**/*.hpp")
    list(APPEND TYR_PUBLIC_HEADER_FILES ${TMP_PUBLIC_HEADER_FILES})
endforeach()

list(APPEND TYR_PUBLIC_HEADER_FILES "../include/tyr/tyr.hpp")

if("${TYR_STATE_STORAGE_POLICY}" STREQUAL "Hashset")
    set(TYR_STATE_STORAGE_SRC_FILES
        planning/state_storage/hash_set/numeric.cpp
        planning/ground_task/state_storage/hash_set/atom.cpp
        planning/ground_task/state_storage/hash_set/fact.cpp
        planning/ground_task/state_storage/hash_set/context.cpp
        planning/lifted_task/state_storage/hash_set/atom.cpp
        planning/lifted_task/state_storage/hash_set/fact.cpp
    )
elseif("${TYR_STATE_STORAGE_POLICY}" STREQUAL "Tree")
    set(TYR_STATE_STORAGE_SRC_FILES
        planning/state_storage/tree_compression/numeric.cpp
        planning/ground_task/state_storage/tree_compression/atom.cpp
        planning/ground_task/state_storage/tree_compression/fact.cpp
        planning/ground_task/state_storage/tree_compression/context.cpp
        planning/lifted_task/state_storage/tree_compression/atom.cpp
        planning/lifted_task/state_storage/tree_compression/fact.cpp
    )
endif()

if(TYR_BUILD_SHARED)
    set(TYR_CORE_LIBRARY_TYPE SHARED)
else()
    set(TYR_CORE_LIBRARY_TYPE STATIC)
endif()

add_library(core ${TYR_CORE_LIBRARY_TYPE} ${TYR_PRIVATE_HEADER_FILES} ${TYR_PUBLIC_HEADER_FILES}
    analysis/listeners.cpp
    analysis/program_domains.cpp
    analysis/stratification.cpp
    analysis/task_domains.cpp
    analysis/domains_translation.cpp

    formalism/datalog/builder.cpp
    formalism/datalog/grounder.cpp
    formalism/datalog/merge.cpp
    formalism/datalog/repository.cpp
    formalism/datalog/views.cpp
    formalism/datalog/variable_dependency_graph.cpp


    formalism/planning/invariants/constraints.cpp
    formalism/planning/invariants/matching.cpp
    formalism/planning/invariants/matcher.cpp
    formalism/planning/invariants/mutexes.cpp
    formalism/planning/invariants/normalization.cpp
    formalism/planning/invariants/proof.cpp
    formalism/planning/invariants/refinement.cpp
    formalism/planning/invariants/synthesis.cpp
    formalism/planning/builder.cpp
    formalism/planning/fdr_context.cpp
    formalism/planning/grounder.cpp
    formalism/planning/merge_datalog.cpp
    formalism/planning/merge_planning.cpp
    formalism/planning/merge.cpp
    formalism/planning/repository.cpp
    formalism/planning/views.cpp
    formalism/planning/loki_to_tyr.cpp
    formalism/planning/parser.cpp
    formalism/planning/planning_task.cpp

    datalog/policies/annotation.cpp
    datalog/policies/numeric_support.cpp
    datalog/policies/termination.cpp
    datalog/workspaces/facts.cpp
    datalog/workspaces/program.cpp
    datalog/workspaces/rule.cpp
    datalog/applicability.cpp
    datalog/assignment_sets.cpp
    datalog/bottom_up.cpp
    datalog/consistency_graph.cpp
    datalog/delta_kpkc_graph.cpp
    datalog/delta_kpkc.cpp
    datalog/fact_set.cpp
    datalog/rule_scheduler.cpp

    ${TYR_STATE_STORAGE_SRC_FILES}

    planning/heuristics/goal_count.cpp

    planning/ground_task/axiom_evaluator.cpp
    planning/ground_task/axiom_stratification.cpp
    planning/ground_task/match_tree.cpp
    planning/ground_task/node.cpp
    planning/ground_task/state_repository.cpp
    planning/ground_task/state.cpp
    planning/ground_task/successor_generator.cpp

    planning/lifted_task/heuristics/rpg_add.cpp
    planning/lifted_task/heuristics/rpg_max.cpp
    planning/lifted_task/heuristics/rpg_ff.cpp
    planning/lifted_task/axiom_evaluator.cpp
    planning/lifted_task/node.cpp
    planning/lifted_task/state_repository.cpp
    planning/lifted_task/state.cpp
    planning/lifted_task/successor_generator.cpp
    planning/lifted_task/task_grounder.cpp

    planning/programs/action.cpp
    planning/programs/axiom.cpp
    planning/programs/common.cpp
    planning/programs/rpg.cpp
    planning/programs/ground.cpp

    planning/algorithms/astar_eager.cpp
    planning/algorithms/astar_eager/event_handler.cpp
    planning/algorithms/brfs.cpp
    planning/algorithms/brfs/event_handler.cpp
    planning/algorithms/gbfs_lazy.cpp
    planning/algorithms/gbfs_lazy/event_handler.cpp
    planning/algorithms/iw.cpp

    planning/applicability.cpp
    planning/applicability_lifted.cpp
    planning/action_executor.cpp
    planning/ground_task.cpp
    planning/lifted_task.cpp
    planning/plan.cpp
    planning/task_utils.cpp
)
set_target_properties(core PROPERTIES OUTPUT_NAME tyr_core)

if(TYR_BUILD_SHARED)
    if(APPLE)
        set(TYR_LIBRARY_ORIGIN "@loader_path")
    elseif(UNIX)
        set(TYR_LIBRARY_ORIGIN "$ORIGIN")
    endif()

    foreach(prefix IN LISTS CMAKE_PREFIX_PATH)
        if(EXISTS "${prefix}/${CMAKE_INSTALL_LIBDIR}")
            list(APPEND TYR_CORE_BUILD_RPATHS "${prefix}/${CMAKE_INSTALL_LIBDIR}")
        endif()
    endforeach()

    set_target_properties(core PROPERTIES
        BUILD_RPATH "${TYR_CORE_BUILD_RPATHS}"
        INSTALL_RPATH "${TYR_LIBRARY_ORIGIN}")
endif()

# Create an alias for simpler reference
add_library(tyr::core ALIAS core)

target_compile_features(core PUBLIC cxx_std_20)

target_link_libraries(core
  PUBLIC
    TBB::tbb
    valla::core
    fmt::fmt-header-only
    gtl::gtl
  PRIVATE
    loki::parsers
    Threads::Threads
)

target_compile_definitions(core
    PUBLIC
        FMT_HEADER_ONLY
        BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
        BOOST_MPL_LIMIT_LIST_SIZE=50
)

if("${TYR_STATE_STORAGE_POLICY}" STREQUAL "Hashset")
    target_compile_definitions(core PUBLIC TYR_STATE_STORAGE_HASHSET)
elseif("${TYR_STATE_STORAGE_POLICY}" STREQUAL "Tree")
    target_compile_definitions(core PUBLIC TYR_STATE_STORAGE_TREE)
endif()

# Use include depending on building or using from installed location
target_include_directories(core
    PUBLIC
        "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>"
        "$<BUILD_INTERFACE:${TYR_NATIVE_DEPENDENCY_INCLUDE_DIRECTORIES}>"
        "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)

foreach(prefix IN LISTS CMAKE_PREFIX_PATH)
    if(EXISTS "${prefix}/include")
        target_include_directories(core PUBLIC "$<BUILD_INTERFACE:${prefix}/include>")
    endif()
endforeach()

# Install the target and create export-set
install(
    TARGETS core
    EXPORT tyrcoreTargets
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

# Generate and install export file
install(EXPORT tyrcoreTargets
    NAMESPACE tyr::
    COMPONENT core
    FILE "tyrcoreTargets.cmake"
    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tyr"
)

# Generate build tree export file
export(EXPORT tyrcoreTargets
    FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/tyrcoreTargets.cmake"
    NAMESPACE tyr::
)
