/*******************************************************************************
***  This file is part of Dux Rei Nummariae.                                 ***
***                                                                          ***
***  Copyright (C) 2017, 2018, 2019, 2020, 2021                              ***
***  John Schneiderman <Licensing _AT_ Schneiderman _DOT_ me>                ***
***                                                                          ***
***  This program is free software: you can redistribute it and/or modify it ***
***  under the terms of the GNU Affero General Public License as published   ***
***  by the Free Software Foundation, either version 3 of the License, or    ***
***  (at your option) any later version.                                     ***
***                                                                          ***
***  This program is distributed in the hope that it will be useful, but     ***
***  WITHOUT ANY WARRANTY; without even the implied warranty of              ***
***  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                    ***
***  See the GNU Affero General Public License for more details.             ***
***                                                                          ***
***  You should have received a copy of the GNU Affero General Public License***
***  along with this program. If not, see <http://www.gnu.org/licenses/>.    ***
*******************************************************************************/
#ifndef DRN_FOUNDATION_ENUMERATIONMACROS_HPP
#define DRN_FOUNDATION_ENUMERATIONMACROS_HPP

#include <QString>

#include <stdexcept>
#include <typeinfo>
#include <type_traits>


#define BEGIN_WEAK_TO_ENUMERATION(enumType)  \
	if ( ! std::is_enum<enumType>::value)  \
		throw std::logic_error{  \
			QStringLiteral(  \
				"Cannot convert to an enumeration from a weak type. The supplied strong type "  \
					"'%1' is not an enumeration."  \
			).arg(typeid(enumType).name()).toStdString()  \
		}

#define MAP_WEAK_TO_ENUMERATION(weakValue, enumType, enumValue)  \
	else if (weakValue == static_cast<std::underlying_type_t<enumType>>(enumValue))  \
		return enumValue

#define END_WEAK_TO_ENUMERATION(weakValue, enumType)  \
	else  \
		throw std::logic_error{  \
			QStringLiteral(  \
				"Failed to convert from the weak value '%1' to the strong type for '%2'."  \
			).arg(QString::number(weakValue)).arg(typeid(enumType).name()).toStdString()  \
		}

#define BEGIN_ENUMERATION_TO_WEAK(strongValue)  \
	switch (strong)  \
	{  \

#define MAP_ENUMERATION_TO_WEAK(enumValue)  \
	case enumValue:  \
		return static_cast<std::underlying_type_t<decltype(enumValue)>>(enumValue)

#define END_ENUMERATION_TO_WEAK(strongValue)  \
	default:  \
		throw std::logic_error{  \
			QStringLiteral(  \
				"Failed to convert from the strong value '%1' to the weak type for '%2'."  \
			)  \
				.arg(  \
					QString::number(  \
						static_cast<std::underlying_type_t<decltype(strongValue)>>(strongValue)  \
					)  \
				)  \
				.arg(typeid(decltype(strongValue)).name())  \
				.toStdString()  \
		};  \
	}

#define BEGIN_ENUMERATION_TO_OTHER(otherValue)  \
	switch (otherValue)  \
	{  \

#define MAP_ENUMERATION_TO_OTHER(enumValue, otherValue)  \
	case enumValue:  \
		return otherValue;

#define END_ENUMERATION_TO_OTHER(otherValue, enumType)  \
	default:  \
		throw std::logic_error{  \
			QStringLiteral(  \
				"Failed to convert from the strong value '%1' to the another type for '%2'."  \
			)  \
				.arg(  \
					QString::number(  \
						static_cast<std::underlying_type_t<enumType>>(otherValue)  \
					)  \
				)  \
				.arg(typeid(decltype(otherValue)).name())  \
				.toStdString()  \
		};  \
	}

#define BEGIN_OTHER_TO_ENUMERATION(enumType)  \
	if ( ! std::is_enum<enumType>::value)  \
		throw std::logic_error{  \
			QStringLiteral(  \
				"Cannot convert to an enumeration from another type. The supplied other "  \
					"type '%1' is not an enumeration."  \
			).arg(typeid(enumType).name()).toStdString()  \
		}

#define MAP_OTHER_TO_ENUMERATION(weakValue, otherValue, enumValue)  \
	else if (weakValue == otherValue)  \
		return enumValue

#define END_OTHER_TO_ENUMERATION(weakValue, enumType)  \
	else  \
		throw std::logic_error{  \
			QStringLiteral(  \
				"Failed to convert from the weak value '%1' to another type for '%2'."  \
			).arg(weakValue).arg(typeid(enumType).name()).toStdString()  \
		}

#endif
