/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2014 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <exception>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines the three arguments for a code location.
/// </summary>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define __CODE__ \
	__FILE__, __FUNCTION__, __LINE__

// Only allow C++11 implementation if compiler is at least Visual Studio 2013
#if (_MSC_VER >= 1800 || defined(LINUX))

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines throw.
/// </summary>
///
/// <param name="theType"> Type of the. </param>
/// <param name="theMsg">  Message describing the. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	#define RX_THROW(theType, theMsg, ...) \
		throw theType::CreateFirst(theMsg, __FILE__, __FUNCTION__, __LINE__,##__VA_ARGS__)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines rethrow.
/// </summary>
///
/// <param name="theType">    Type of the. </param>
/// <param name="theMsg">	  Message describing the. </param>
/// <param name="theInnerEx"> the inner ex. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	#define RX_RETHROW(theType, theMsg, theInnerEx, ...) \
		throw theType::Create(theMsg, __FILE__, __FUNCTION__, __LINE__, theInnerEx,##__VA_ARGS__)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines the catch block for C++ exceptions. It catches std::exception, Rx::CRxException and '...'. It
/// 	rethrows a Rx::CRxException.
/// </summary>
///
/// <param name="theMsg"> The exception message. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	#define RX_CATCH_RETRHOW_CPP(theMsg) \
		catch (std::exception& ex) \
		{ \
			RX_THROW(Rx::CRxException, RX_S theMsg << ". " << ex.what()); \
		} \
		catch (Rx::CRxException& ex) \
		{ \
			RX_RETHROW(Rx::CRxException, RX_S theMsg, ex); \
		} \
		catch (...) \
		{ \
			RX_THROW(Rx::CRxException, RX_S theMsg << ". Unknown exception"); \
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines exception base implementation.</summary>
///
/// <param name="theType">	Type of the.</param>
/// <param name="theName">	Name of the.</param>
/// <param name="theGUID">	Unique identifier for the.</param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	#define RX_EXCEPTION_CPP11_IMPLEMENTATION(theType) \
	public: \
		template<typename ... TArgs> \
		static theType CreateFirst(const Rx::CRxString & sxMsg, const char* pcFile, const char* pcFunc, int iLine, TArgs ... args) \
		{ \
			theType xException(sxMsg, pcFile, pcFunc, iLine); \
			xException.SetExceptionData(args ...); \
			return xException; \
		} \
		template<typename ... TArgs> \
		static theType Create(const Rx::CRxString & sxMsg, const char* pcFile, const char* pcFunc, int iLine, const Rx::IException30 & xEx, TArgs ... args) \
		{ \
			theType xException(sxMsg, pcFile, pcFunc, iLine, xEx); \
			xException.SetExceptionData(args ...); \
			return xException; \
		} \
		template<typename ... TArgs> \
		static theType Create(const Rx::CRxString & sxMsg, const char* pcFile, const char* pcFunc, int iLine, const Rx::IException31 & xEx, TArgs ... args) \
		{ \
			theType xException(sxMsg, pcFile, pcFunc, iLine, xEx); \
			xException.SetExceptionData(args ...); \
			return xException; \
		} \

#else
	#define RX_THROW(theType, theMsg, ...)
	#define RX_RETHROW(theType, theMsg, theInnerEx, ...)
	#define RX_EXCEPTION_CPP11_IMPLEMENTATION(theType)
#endif

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines exception base implementation.</summary>
///
/// <param name="theType">	Type of the.</param>
/// <param name="theName">	Name of the.</param>
/// <param name="theGUID">	Unique identifier for the.</param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define RX_EXCEPTION_BASE_IMPLEMENTATION(theType, theName, theGUID) \
public: \
	RX_EXCEPTION_CPP11_IMPLEMENTATION(theType) \
	static Rx::CGuid30 GetTypeGUID() \
	{ \
		return theGUID; \
	} \
	static const char* GetTypeName() \
	{ \
		return theName; \
	} \
	virtual Rx::IException31* Clone() const \
	{ \
		return (Rx::IException31*) new theType(*this); \
	} \

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines exception inherit implementation.
/// </summary>
///
/// <param name="theType"> Type of the. </param>
/// <param name="theBase"> the base. </param>
/// <param name="theName"> Name of the. </param>
/// <param name="theGUID"> Unique identifier for the. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define RX_EXCEPTION_INHERIT_IMPLEMENTATION(theType, theBase, theName, theGUID) \
	RX_EXCEPTION_BASE_IMPLEMENTATION(theType, theName, theGUID) \
public: \
	theType(const Rx::CRxString & sxMsg, const char* pcFile, const char* pcFunc, int iLine) \
		: theBase(sxMsg, pcFile, pcFunc, iLine) \
	{ \
		m_xGUID  = GetTypeGUID(); \
		m_sxName = GetTypeName(); \
	} \
	theType(const Rx::CRxString & sxMsg, const char* pcFile, const char* pcFunc, int iLine, const Rx::IException30 & ex) \
		: theBase(sxMsg, pcFile, pcFunc, iLine, ex) \
	{ \
		m_xGUID  = GetTypeGUID(); \
		m_sxName = GetTypeName(); \
	} \
	theType(const Rx::CRxString & sxMsg, const char* pcFile, const char* pcFunc, int iLine, const Rx::IException31 & ex) \
		: theBase(sxMsg, pcFile, pcFunc, iLine, ex) \
	{ \
		m_xGUID  = GetTypeGUID(); \
		m_sxName = GetTypeName(); \
	} \
	virtual ~theType() { } \

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines exception implementation.
/// </summary>
///
/// <param name="theType"> Type of the. </param>
/// <param name="theName"> Name of the. </param>
/// <param name="theGUID"> Unique identifier for the. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define RX_EXCEPTION_IMPLEMENTATION(theType, theName, theGUID) RX_EXCEPTION_INHERIT_IMPLEMENTATION(theType, Rx::CRxException, theName, theGUID)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines net exception inherit implementation.
/// </summary>
///
/// <param name="theType"> Type of the. </param>
/// <param name="theBase"> the base. </param>
/// <param name="theGUID"> Unique identifier for the. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define RX_NET_EXCEPTION_INHERIT_IMPLEMENTATION(theType, theBase, theGUID) \
public: \
	theType(System::String^ sMessage, System::String^ sFile, System::String^ sFunc, int iLine) \
		: theBase(sMessage, sFile, sFunc, iLine) \
	{ \
		m_xGuid = TypeGUID; \
	} \
	theType(System::String^ sMessage, System::String^ sFile, System::String^ sFunc, int iLine, System::Exception^ xEx) \
		: theBase(sMessage, sFile, sFunc, iLine, xEx) \
	{ \
		m_xGuid = TypeGUID; \
	} \
	theType(System::String^ sMessage, System::String^ sFile, System::String^ sFunc, int iLine, const Rx::IException30 & xEx) \
		: theBase(sMessage, sFile, sFunc, iLine, xEx) \
	{ \
		m_xGuid = TypeGUID; \
	} \
	theType(System::String^ sMessage, System::String^ sFile, System::String^ sFunc, int iLine, const Rx::IException31 & xEx) \
		: theBase(sMessage, sFile, sFunc, iLine, xEx) \
	{ \
		m_xGuid = TypeGUID; \
	} \
	theType(const Rx::IException30 & xEx) \
		: theBase(xEx) \
	{ \
	} \
	theType(const Rx::IException31 & xEx) \
		: theBase(xEx) \
	{ \
	} \
	static property System::Guid TypeGUID \
	{ \
		System::Guid get() \
		{ \
			return System::Guid(theGUID); \
		} \
	} \
	static theType^ CreateFirst(System::String^ sMsg, System::String^ sFile, System::String^ sFunc, int iLine, ... array<System::Object^>^ args) \
	{ \
		theType^ xException = gcnew theType(sMsg, sFile, sFunc, iLine); \
		xException->SetExceptionData(args); \
		return xException; \
	} \
	static theType^ Create(System::String^ sMsg, System::String^ sFile, System::String^ sFunc, int iLine, System::Exception^ xEx, ... array<System::Object^>^ args) \
	{ \
		theType^ xException = gcnew theType(sMsg, sFile, sFunc, iLine, xEx); \
		xException->SetExceptionData(args); \
		return xException; \
	} \
	static theType^ Create(System::String^ sMsg, System::String^ sFile, System::String^ sFunc, int iLine, const Rx::IException30 & xEx, ... array<System::Object^>^ args) \
	{ \
		theType^ xException = gcnew theType(sMsg, sFile, sFunc, iLine, xEx); \
		xException->SetExceptionData(args); \
		return xException; \
	} \
	static theType^ Create(System::String^ sMsg, System::String^ sFile, System::String^ sFunc, int iLine, const Rx::IException31 & xEx, ... array<System::Object^>^ args) \
	{ \
		theType^ xException = gcnew theType(sMsg, sFile, sFunc, iLine, xEx); \
		xException->SetExceptionData(args); \
		return xException; \
	} \

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that defines net exception implementation.
/// </summary>
///
/// <param name="theType"> Type of the. </param>
/// <param name="theGUID"> Unique identifier for the. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define RX_NET_EXCEPTION_IMPLEMENTATION(theType, theGUID) RX_NET_EXCEPTION_INHERIT_IMPLEMENTATION(theType, Rx::Net::RxException, theGUID)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that throws when an assertion failed.
/// </summary>
///
/// <param name="assert_condition">  The assert condition. </param>
/// <param name="exception_message"> Message describing the exception. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define RX_EXCEPTION_ASSERT(assert_condition, exception_message) \
	{ \
		const bool bAssertCondidtion = (assert_condition) ? true : false; \
		if (!(bAssertCondidtion)) \
		{ \
			RX_THROW(Rx::CRxException, exception_message); \
		} \
	}
