#include "doctest/parts/private/prelude.h"
#include "doctest/parts/private/context_state.h"
#include "doctest/parts/private/context_scope.h"

DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH

namespace doctest {

DOCTEST_DEFINE_INTERFACE(IContextScope)

#ifndef DOCTEST_CONFIG_DISABLE
namespace detail {
DOCTEST_THREAD_LOCAL std::vector<IContextScope *> g_infoContexts; // for logging with INFO()

ContextScopeBase::ContextScopeBase() {
    g_infoContexts.push_back(this);
}

ContextScopeBase::ContextScopeBase(ContextScopeBase &&other) noexcept {
    if (other.need_to_destroy) {
        other.destroy();
    }
    other.need_to_destroy = false;
    g_infoContexts.push_back(this);
}

DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17
DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
// destroy cannot be inlined into the destructor because that would mean calling stringify after
// ContextScope has been destroyed (base class destructors run after derived class destructors).
// Instead, ContextScope calls this method directly from its destructor.
void ContextScopeBase::destroy() {
#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L &&                              \
    (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
    if (std::uncaught_exceptions() > 0) {
#else
    if (std::uncaught_exception()) {
#endif
        std::ostringstream s;
        this->stringify(&s);
        g_cs->stringifiedContexts.emplace_back(s.str().c_str());
    }
    g_infoContexts.pop_back();
}
DOCTEST_CLANG_SUPPRESS_WARNING_POP
DOCTEST_GCC_SUPPRESS_WARNING_POP
DOCTEST_MSVC_SUPPRESS_WARNING_POP
} // namespace detail
#endif // DOCTEST_CONFIG_DISABLE

} // namespace doctest

DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP
