// This file is part of the FidelityFX SDK.
//
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#pragma once

#include "ffx_types.h"
#include "ffx_util.h"

namespace Fsr3
{
#ifdef __cplusplus
extern "C"
{
#endif // #ifdef __cplusplus

    /// @defgroup Asserts Asserts
    /// Asserts used by FidelityFX SDK functions
    ///
    /// @ingroup ffxHost

#ifdef _DEBUG
#ifdef _WIN32

#ifdef DISABLE_FFX_DEBUG_BREAK
#define FFX_DEBUG_BREAK                                                                                                \
    {                                                                                                                  \
    }
#else
/// Macro to force the debugger to break at this point in the code.
///
/// @ingroup Asserts
#define FFX_DEBUG_BREAK __debugbreak();
#endif
#else
#define FFX_DEBUG_BREAK                                                                                                \
    {                                                                                                                  \
    }
#endif
#else
// don't allow debug break in release builds.
#define FFX_DEBUG_BREAK
#endif

    /// A typedef for the callback function for assert printing.
    ///
    /// This can be used to re-route printing of assert messages from the FFX backend
    /// to another destination. For example instead of the default behaviour of printing
    /// the assert messages to the debugger's TTY the message can be re-routed to a
    /// MessageBox in a GUI application.
    ///
    /// @param [in] message                 The message generated by the assert.
    ///
    /// @ingroup Asserts
    typedef void (*FfxAssertCallback)(const char* message);

    /// Function to report an assert.
    ///
    /// @param [in] file                    The name of the file as a string.
    /// @param [in] line                    The index of the line in the file.
    /// @param [in] condition               The boolean condition that was tested.
    /// @param [in] msg                     The optional message to print.
    ///
    /// @returns
    /// Always returns true.
    ///
    /// @ingroup Asserts
    FFX_API bool ffxAssertReport(const char* file, int32_t line, const char* condition, const char* msg);

    /// Provides the ability to set a callback for assert messages.
    ///
    /// @param [in] callback                The callback function that will receive assert messages.
    ///
    /// @ingroup Asserts
    FFX_API void ffxAssertSetPrintingCallback(FfxAssertCallback callback);

#ifdef _DEBUG
    /// Standard assert macro.
    ///
    /// @ingroup Asserts
#define FFX_ASSERT(condition)                                                                                          \
    do                                                                                                                 \
    {                                                                                                                  \
        if (!(condition) && ffxAssertReport(__FILE__, __LINE__, #condition, NULL))                                     \
            FFX_DEBUG_BREAK                                                                                            \
    } while (0)

/// Assert macro with message.
///
/// @ingroup Asserts
#define FFX_ASSERT_MESSAGE(condition, msg)                                                                             \
    do                                                                                                                 \
    {                                                                                                                  \
        if (!(condition) && ffxAssertReport(__FILE__, __LINE__, #condition, msg))                                      \
            FFX_DEBUG_BREAK                                                                                            \
    } while (0)

/// Assert macro that always fails.
///
/// @ingroup Asserts
#define FFX_ASSERT_FAIL(message)                                                                                       \
    do                                                                                                                 \
    {                                                                                                                  \
        ffxAssertReport(__FILE__, __LINE__, NULL, message);                                                            \
        FFX_DEBUG_BREAK                                                                                                \
    } while (0)
#else
// asserts disabled
#define FFX_ASSERT(condition)                                                                                          \
    do                                                                                                                 \
    {                                                                                                                  \
        FFX_UNUSED(condition);                                                                                         \
    } while (0)

#define FFX_ASSERT_MESSAGE(condition, message)                                                                         \
    do                                                                                                                 \
    {                                                                                                                  \
        FFX_UNUSED(condition);                                                                                         \
        FFX_UNUSED(message);                                                                                           \
    } while (0)

#define FFX_ASSERT_FAIL(message)                                                                                       \
    do                                                                                                                 \
    {                                                                                                                  \
        FFX_UNUSED(message);                                                                                           \
    } while (0)
#endif // #if _DEBUG

/// Simple static assert.
///
/// @ingroup Asserts
#define FFX_STATIC_ASSERT(condition) static_assert(condition, #condition)

#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
} // namespace Fsr3