/*
 * Copyright 2015 - 2022 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#if defined(OX_USE_STDLIB)
#include <iostream>
#endif

#include "def.hpp"
#include "defines.hpp"
#include "error.hpp"
#include "realstd.hpp"
#include "stacktrace.hpp"
#include "trace.hpp"
#include "typetraits.hpp"

namespace ox {

void panic(const char *file, int line, const char *panicMsg, const Error &err = OxError(0)) noexcept;

constexpr void constexprPanic(const char *file, int line, const char *panicMsg, const Error &err = OxError(0)) noexcept {
	if (!std::is_constant_evaluated()) {
		panic(file, line, panicMsg, err);
	} else {
		while (true);
	}
}

constexpr void assertFunc(const char *file, int line, bool pass, [[maybe_unused]]const char *assertTxt, [[maybe_unused]]const char *msg) noexcept {
	if (!pass) {
		if (!std::is_constant_evaluated()) {
#ifdef OX_USE_STDLIB
				oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
				printStackTrace(2);
				oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
				std::abort();
#else
				constexprPanic(file, line, msg);
#endif
		} else {
			while (true);
		}
	}
}

constexpr void assertFunc(const char *file, int line, const Error &err, const char*, const char *assertMsg) noexcept {
	if (err) {
		 if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB)
			oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
			if (err.msg) {
				oxErrf("\tError Message:\t{}\n", err.msg);
			}
			oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
			if (err.file != nullptr) {
				oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
			}
			printStackTrace(2);
			oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
			std::abort();
#else
			constexprPanic(file, line, assertMsg);
#endif
		} else {
			while (true);
		}
	}
}

}
