
#  flatbuffers_generate_cpp
#  --------------------------
#
#   Add custom commands to process ``.fbs`` files to C++ using flatc compiler
#
#     flatbuffers_generate_cpp ( <ptr_type> <target> <*.proto files> )
#
#   ``ARGN``
#     ``.fbs`` files
#
macro(flatbuffers_generate_cpp _ptr_type _target)
    message(STATUS "inside flatbuffers_generate_cpp")
    if(NOT TARGET ${_target})
        message(SEND_ERROR "flatbuffers_generate_cpp requires target as first argument")
        return()
    endif()
    if(NOT ${ARGC} GREATER 1)
        message(SEND_ERROR "Error: flatbuffers_generate_cpp() called without any files as arguments")
        return()
    endif()
    if(NOT _generated_headers)
        set(_generated_headers)
    endif()
    foreach(FIL ${ARGN})
        get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
        message(STATUS "flatbuffers_generate_cpp: processing ${ABS_FIL}")
        get_filename_component(FIL_WE ${FIL} NAME_WE)
        file(RELATIVE_PATH REL_FIL ${CMAKE_CURRENT_SOURCE_DIR}/flatbuffers ${ABS_FIL})
        get_filename_component(REL_DIR ${REL_FIL} DIRECTORY)
        if (REL_DIR)
            set(RELFIL_WE "${REL_DIR}/${FIL_WE}")
        else()
            set(RELFIL_WE ${FIL_WE})
        endif ()

        set(_GEN_GENERATED_HDR ${_flatbuffers_gen_dir}/${RELFIL_WE}_generated.h)

        file(STRINGS ${FIL} _has_rpc_service REGEX rpc_service)
        if (_has_rpc_service)
            set(_GEN_SOURCES
                ${_flatbuffers_gen_dir}/${RELFIL_WE}.grpc.fb.cc
            )
            set(_GEN_HEADERS
                ${_flatbuffers_gen_dir}/${RELFIL_WE}.grpc.fb.h
                ${_flatbuffers_gen_dir}/${RELFIL_WE}_generated.h
            )    
        else()
            set(_GEN_SOURCES)
            set(_GEN_HEADERS
                ${_flatbuffers_gen_dir}/${RELFIL_WE}_generated.h
            )
        endif ()
        list(APPEND _generated_headers "${_GEN_HEADERS}") 
        set(_GEN_REFLECTION_SRC ${_flatbuffers_gen_dir}/${RELFIL_WE}_reflection.cpp)

        #add generated sources to the sources of _target
        target_sources(${_target} PRIVATE ${_GEN_SOURCES} ${_GEN_HEADERS} ${_GEN_REFLECTION_SRC})
        set_source_files_properties(${_GEN_SOURCES} ${_GEN_HEADERS} ${_GEN_REFLECTION_SRC} PROPERTIES GENERATED TRUE)

        add_custom_command(
            OUTPUT ${_GEN_SOURCES} ${_GEN_HEADERS}
            COMMAND ${deps_prefix}/bin/flatc
            ARGS -c -s -o ${_flatbuffers_gen_dir}/${REL_DIR}
            -I ${_FLATBUFFERS_IMPORT_DIR}
            --no-prefix
            --scoped-enums
            --gen-mutable
            --gen-object-api
            --gen-name-strings
            --grpc
            --bfbs-comments
            --reflect-types
            --reflect-names
            --cpp-ptr-type ${_ptr_type}
            --keep-prefix
            ${FIL} && echo "extern const char ${FIL_WE}_fbs[];" >> ${_GEN_GENERATED_HDR}
            DEPENDS ${FIL}
            WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
            COMMENT "Running flatc compiler on ${FIL}"
            VERBATIM
        )
        add_custom_command(
            OUTPUT ${_GEN_REFLECTION_SRC}
            COMMAND sed -e '/^include/d' < ${FIL} | sed -e '1s/^/extern const char ${FIL_WE}_fbs[]=R\"CXXRSTR_DELIM\(/' -e '$$s/$$/\)CXXRSTR_DELIM\"\;/' > ${_GEN_REFLECTION_SRC}
            WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
            DEPENDS ${FIL} ${_GEN_GENERATED_HDR}
            COMMENT "generate flatbuffer reflection file ${_GEN_REFLECTION_SRC} of ${FIL}"
        )

        #since some of the headers generated by this command are also included in hand-written sources make this command run before the _target
        get_property(_sources TARGET ${_target} PROPERTY SOURCES)
        set_source_files_properties(${_sources} PROPERTIES OBJECT_DEPENDS "${_GEN_HEADERS}")
    endforeach()
endmacro()
