#pragma once

#ifndef WMC_ASSERT_H_INCLUDED
#define WMC_ASSERT_H_INCLUDED

#include <string>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <exception>

#include <util/string/cast.h>

namespace NWebmaster {
namespace Assertions {

template <class Exception>
void exc_helper(bool condition = false, const std::string &msg = "") {
    if (!condition && !std::uncaught_exception()) {
        throw Exception(msg);
    }
}

} // namespace Assertion
} // namespace NWebmaster

/*! Rationale:
 *      wmc_require mapped to std::runtime_error and supposed to be fatal runtime error (aka force majeur:
 *          environment, hardware or configuration problem, etc)
 *      assert, in contrast, is logic_error and shall be considered as internal programming error or inconsistency
 */
#define __STRING_IT_0__(x) #x
#define __STRING_IT__(x) __STRING_IT_0__(x)
#define S__LINE__ __STRING_IT__(__LINE__)
#define S__func__ __STRING_IT__(__func__)

#ifdef NDEBUG
#define WMC_REQUIRE(cond, msg)   NWebmaster::Assertions::exc_helper<std::runtime_error>(cond, msg)
#else
#define WMC_REQUIRE(cond, msg)   NWebmaster::Assertions::exc_helper<std::runtime_error>(cond, std::string(__FILE__"#" S__LINE__ "@" S__func__ " | Condition '"#cond"' failed> ") + msg)
#endif

#ifdef NDEBUG
#define WMC_ASSERT(cond, msg)   NWebmaster::Assertions::exc_helper<std::logic_error>(cond, msg)
#else
#define WMC_ASSERT(cond, msg)   NWebmaster::Assertions::exc_helper<std::logic_error>(cond, std::string(__FILE__"#" S__LINE__ "@" S__func__ " | Condition '"#cond"' failed> ") + msg)
#endif

#define Failure WMC_ASSERT

#define WMC_CHECK(___cond, ___msg)                                  \
{                                                                   \
    bool ___res = (___cond);                                        \
    if (!___res)                                                    \
    {                                                               \
        WMC_ASSERT(___res, ___msg);                                 \
    }                                                               \
}

#endif // WMC_ASSERT_H_INCLUDED
