#pragma once

#ifndef __gxframework_exception_h__
	#define __gxframework_exception_h__

#include "foundation.h"
#include <exception>
#include <string>
#include <sstream>

namespace Gx
{
	class Exception : public std::exception
	{
	public:
		Exception(const std::string& message, const std::string& file, const std::string& function, GxU32 line, GxI32 errorCode = 0)
			: m_message(message), m_function(function), m_line(line), m_errorCode(errorCode), std::exception(message.c_str())
		{
			size_t found = file.find_last_of("/\\");
			if ( found != std::string::npos )
				m_file = file.substr(found + 1);
			else
				m_file = file;
		}

		virtual ~Exception() throw()
		{
		}

		std::string getWhat() const
		{
			std::stringstream stream;
			stream
				<< "-------------------------------------------------------" << std::endl
				<< "Exception Caught" << std::endl
				<< "-------------------------------------------------------" << std::endl
				<< "Build: " << __DATE__ << "(" << __TIME__ << ")" << std::endl
				<< "ErrorCode: " << m_errorCode << std::endl
				<< "Message: " << m_message.c_str() << std::endl
				<< "-------------------------------------------------------" << std::endl
				<< "Function: " << m_function.c_str() << std::endl
				<< "File: " << m_file.c_str() << std::endl
				<< "Line: " << m_line << std::endl
				<< "-------------------------------------------------------\n" << std::endl;

			return stream.str();
		}

	private:
		std::string m_message;
		std::string m_function;
		std::string m_file;
		GxU32 m_line;
		GxI32 m_errorCode;
	};
}

#define GX_EXCEPTION(msg) Gx::Exception(msg, __FILE__, __FUNCTION__, __LINE__);
#define GX_EXCEPTION_LAST_ERROR(msg) Gx::Exception(msg, __FILE__, __FUNCTION__, __LINE__, GetLastError());
#define GX_EXCEPTION_ERROR_CODE(msg, ec) Gx::Exception(msg, __FILE__, __FUNCTION__, __LINE__, ec);


#endif /* __gxframework_exception_h__ */