# Copyright 2020 The Dawn & Tint Authors
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
#    list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
#    contributors may be used to endorse or promote products derived from
#    this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Check for Jinja2
if (NOT DAWN_JINJA2_DIR)
    message(STATUS "Dawn: Using system jinja2")
    execute_process(
        COMMAND ${Python3_EXECUTABLE} -c "import jinja2"
        RESULT_VARIABLE RET
    )
    if (NOT RET EQUAL 0)
        message(FATAL_ERROR "Dawn: Missing dependencies for code generation, please ensure you have python-jinja2 installed.")
    endif()
else()
    message(STATUS "Dawn: using jinja2 at ${DAWN_JINJA2_DIR}")
    message(STATUS "Dawn: using markupsafe at ${DAWN_MARKUPSAFE_DIR}")
endif()

# Function to invoke a generator_lib.py generator.
#  - SCRIPT is the name of the script to call
#  - ARGS are the extra arguments to pass to the script in addition to the base generator_lib.py arguments
#  - PRINT_NAME is the name to use when outputting status or errors
#  - RESULT_VARIABLE will be modified to contain the list of files generated by this generator
function(DawnGenerator)
    set(oneValueArgs SCRIPT RESULT_VARIABLE PRINT_NAME)
    set(multiValueArgs ARGS)
    cmake_parse_arguments(G "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    # Build the set of args common to all invocation of that generator.
    set(BASE_ARGS
        ${Python3_EXECUTABLE}
        ${G_SCRIPT}
        --template-dir
        "${DAWN_TEMPLATE_DIR}"
        --root-dir
        "${Dawn_SOURCE_DIR}"
        --output-dir
        "${DAWN_BUILD_GEN_DIR}"
        ${G_ARGS}
    )
    if (DAWN_JINJA2_DIR)
        list(APPEND BASE_ARGS --jinja2-path ${DAWN_JINJA2_DIR})
    endif()
    if (DAWN_MARKUPSAFE_DIR)
        list(APPEND BASE_ARGS --markupsafe-path ${DAWN_MARKUPSAFE_DIR})
    endif()

    # Call the generator to get the list of its dependencies.
    execute_process(
        COMMAND ${BASE_ARGS} --print-cmake-dependencies
        OUTPUT_VARIABLE DEPENDENCIES
        RESULT_VARIABLE RET
    )
    if (NOT RET EQUAL 0)
        message(FATAL_ERROR "Dawn: Failed to get the dependencies for ${G_PRINT_NAME}. Base args are '${BASE_ARGS}'.")
    endif()

    # Ask CMake to re-run if any of the dependencies changed as it might modify the build graph.
    set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${DEPENDENCIES})

    # Call the generator to get the list of its outputs.
    execute_process(
        COMMAND ${BASE_ARGS} --print-cmake-outputs
        OUTPUT_VARIABLE OUTPUTS
        RESULT_VARIABLE RET
    )
    if (NOT RET EQUAL 0)
        message(FATAL_ERROR "Dawn: Failed to get the outputs for ${G_PRINT_NAME}. Base args are '${BASE_ARGS}'.")
    endif()

    # Add the custom command that calls the generator.
    add_custom_command(
        COMMAND ${BASE_ARGS}
        DEPENDS ${DEPENDENCIES}
        OUTPUT ${OUTPUTS}
        COMMENT "Dawn: Generating files for ${G_PRINT_NAME}."
    )

    # Return the list of outputs.
    set(${G_RESULT_VARIABLE} ${OUTPUTS} PARENT_SCOPE)

    # Prior to CMake 3.20 the GENERATED property is local to a directory which means that putting
    # generated headers in INTERFACE properties causes dependent targets to complain that they
    # cannot find the file. (because they don't see it as generated and want to check is is
    # actually on the filesystem).
    # Work around this by generating the files once if they aren't present at configuration time.
    set(needToGenerate OFF)
    foreach(path ${OUTPUTS})
        if (NOT EXISTS ${path})
            set(needToGenerate ON)
        endif()
    endforeach()

    if (${needToGenerate})
        message(STATUS "Dawn: Generating initial versions of files for ${G_PRINT_NAME}.")
        execute_process(COMMAND ${BASE_ARGS} RESULT_VARIABLE RET)
        if (NOT RET EQUAL 0)
            message(FATAL_ERROR "Dawn: Failed to generate the initial version of files for ${G_PRINT_NAME}. Base args are '${BASE_ARGS}'.")
        endif()
    endif()
endfunction()

# Helper function to call dawn_generator.py:
#  - TARGET is the generator target to build
#  - PRINT_NAME and RESULT_VARIABLE are like for DawnGenerator
function(DawnJSONGenerator)
    set(oneValueArgs TARGET RESULT_VARIABLE)
    cmake_parse_arguments(G "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    DawnGenerator(
        SCRIPT "${Dawn_SOURCE_DIR}/generator/dawn_json_generator.py"
        ARGS --dawn-json
             "${Dawn_SOURCE_DIR}/src/dawn/dawn.json"
             --wire-json
             "${Dawn_SOURCE_DIR}/src/dawn/dawn_wire.json"
             --kotlin-json
             "${Dawn_SOURCE_DIR}/src/dawn/dawn_kotlin.json"
             --targets
             ${G_TARGET}
        RESULT_VARIABLE RET
        ${G_UNPARSED_ARGUMENTS}
    )

    # Forward the result up one more scope
    set(${G_RESULT_VARIABLE} ${RET} PARENT_SCOPE)
endfunction()
