#ifndef _GSTRUNTIMEEXCEPTION_H_
#define _GSTRUNTIMEEXCEPTION_H_

#define GSTRUNTIMEERROR 1
#define GSTOUTOFRANGE 2
#define GSTSQLERROR 3
#define GSTCASTERROR 4
#define GSTSQLNULLERROR 5
#define GSTSQLEMPTYERROR 6
#define GSTINCOMPATIBLE 7
#define GSTLICENSEERROR 8
#define GSTTIMEOUT 9
#define GSTSRSINUSE 10
#define GSTINVALIDARG 11
#define GSTTOOFEWARGUMENTS 12
#define GSTINVALIDTYPE 13
#define GSTCOULDNOTCREATEGEO 14
#define GSTINVALIDDATABASE 15
#define GSTUNSUPPORTED 16
#define GSTNOGEOMETRY 17
#define GSTLOGFILEEXCEPTION 18
#define GSTFORMATERROR 19
#define GSTNOTFOUND 20
#define GSTNOTRANSFORM 21
#define BADPARAMETER 22
#define GEOMETRYISLOCKED 23
#define INVALIDFORMATSTRING 24
#define GEOMETRYIDUNKNOWN 25
#define TRANSFORMERROR 26
#define EMPTYGEOMETRY 27
#define GSTINCOMPATIBLEFEATURE 28
#define GEOMETRYISLOCKEDINAREA 29
#define BORDERCONSTRAINTVIOLATED 30
#define FEATUREISLOCKED 31
#define INTERSECTIONNORESULT 32
#define RTREEINDEXALREADYEXISTS 33

#define EXCEPTIONSEPARATOR char(30)

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

#include <boost/current_function.hpp>
#include <boost/lexical_cast.hpp>

namespace GST
{
namespace exceptions
{

inline std::string methodName(const std::string &prettyFunction)
{
	size_t colons = prettyFunction.find("::");
	size_t begin = prettyFunction.substr(0, colons).rfind(" ") + 1;
	size_t end = prettyFunction.rfind("(") - begin;

	return prettyFunction.substr(begin, end) + "()";
}

#define __METHOD_NAME__ GST::exceptions::methodName(BOOST_CURRENT_FUNCTION)

/**
	\brief To be thrown on runtime errors.
	*/
class GSTRuntimeException : public std::runtime_error
{
protected:
	// ### member ###
	std::string _msg;
	const unsigned int _number;
	std::string _GSTprefix;
	std::string callstack;
	std::vector<std::string> attachments;

public:
	// ### public methods ###
	/**
	* exception caller interface (c'tor used by throw'er of exception)
	*
		@param classname	name of the class the exception is thrown
		@param methode		name of the methode the exception is thrown
		@param msg			gives information about the exception (e.g. reason
	why or possible solution text to be read by human.)
		@param number		number of GST Exception */
	GSTRuntimeException(const std::string &throwLocation,
						const std::string &msg,
						const unsigned int &number = GSTRUNTIMEERROR)
		: std::runtime_error(msg.c_str())
		, _msg(msg)
		, _number(number)
	{
		this->preparePrefix();
		// this->callstack = caller;
	}

	// ### public methods ###
	/**
	* exception receiver interface (c'tor used by catch'er of exception)
	*
		@param encodedException string of encoded exception */
	GSTRuntimeException(const std::string &encodedException,
						const unsigned int &number = GSTRUNTIMEERROR)
		: std::runtime_error("")
		, _number(number)
	{
		this->preparePrefix();

		if(!encodedException.empty())
		{
			this->decodeMessage(encodedException);
		}
	}

	virtual ~GSTRuntimeException() throw()
	{
	}

	void preparePrefix()
	{
		std::stringstream str;
		str << "GSTERR-";
		char prev = str.fill();
		str.fill('0');
		std::streamsize previ = str.width();
		str.width(6);
		str << this->_number;
		str.fill(prev);
		str.width(previ);
		str << ": ";
		this->_GSTprefix = str.str();
	}

	/** @return message's text */
	const std::string getMessage() const
	{
		return this->_msg;
	}

	virtual std::string encodeMessage() const
	{
		std::string result;
		// encode: exception header + message
		result = this->_GSTprefix + this->_msg + EXCEPTIONSEPARATOR;
		// encode: attachment
		for(const std::string &attachment : this->attachments)
		{
			result += attachment + EXCEPTIONSEPARATOR;
		}

		return result;
	}

	virtual void decodeMessage(const std::string &db_errormessage)
	{
		size_t pos = db_errormessage.find("GSTERR");
		if(pos != std::string::npos) // let's handle some more specific
									 // exceptions otherwise keep going
		{
			// code number
			std::string gstErr(db_errormessage.substr(pos, 13));

			// message
			size_t endPos = db_errormessage.find(EXCEPTIONSEPARATOR);
			this->_msg = db_errormessage.substr(pos + 14, endPos - pos - 14);

			// attachments
			attachments.clear();
			size_t oldPos = endPos + 1;
			endPos = db_errormessage.find(EXCEPTIONSEPARATOR, oldPos);
			while(oldPos != endPos && endPos != std::string::npos)
			{
				attachments.push_back(
					db_errormessage.substr(oldPos, endPos - oldPos));

				oldPos = endPos + 1;
				endPos = db_errormessage.find(EXCEPTIONSEPARATOR, oldPos);
			}
		}
		else
		{
			this->_msg = db_errormessage;
		}
	}

	static unsigned int getExceptionCode(const std::string &db_errormessage)
	{
		size_t pos = db_errormessage.find("GSTERR");
		if(pos != std::string::npos) // let's handle some more specific
									 // exceptions otherwise keep going
		{
			std::string gstErr(db_errormessage.substr(pos, 13));
			std::stringstream str(gstErr.substr(7));
			unsigned int err;
			str >> err;

			return err;
		}

		return (unsigned int)GSTRUNTIMEERROR;
	}

	/**
		@return to location the exception was thrown like this:<br>
		\verbatim classname::methodename \endverbatim */
	const std::string getThrowLocation() const
	{
		return this->callstack;
	}

	/** overriden std::exception output */
	virtual const char *what() const throw()
	{
		return this->_msg.empty() ? "No message available" : this->_msg.c_str();
	}

	virtual void appendToStack(const std::string &add)
	{
		this->callstack += "\n" + add;
	}

	virtual void appendToMessage(const std::string &msg)
	{
		this->_msg += " " + msg;
	}
}; // class

class GSTOutOfRange : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTOutOfRange(const std::string &encodedMessage)
		: GSTRuntimeException("", GSTOUTOFRANGE)
	{
	}

	/// thrower interface
	GSTOutOfRange(const std::string &throwLocation,
				  const std::string &container)
		: GSTRuntimeException(throwLocation, "", GSTOUTOFRANGE)
	{
		_msg = container + " is out of range.";
	}
};

/**
 * To be thrown on GST Storage side
 */
class GSTSQLError : public GSTRuntimeException
{
public:
	long error_code;

	/// catcher interface
	GSTSQLError(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTSQLERROR)
	{
		this->attachment2ExceptionData();
	}

	// thrower interface
	GSTSQLError(const std::string &throwLocation,
				const std::string &msg,
				const std::string &sql,
				long exec_err_code)
		: GSTRuntimeException(throwLocation, "", GSTSQLERROR)
		, error_code(exec_err_code)
	{
		std::stringstream smsg;
		smsg << "Error in query: \"" << sql
			 << "\" (exec error code: " << exec_err_code << ").";
		if(!msg.empty())
			smsg << " Message: " << msg;

		_msg = smsg.str();

		// append data
		this->attachments.push_back(
			boost::lexical_cast<std::string>(error_code));
	}

	void attachment2ExceptionData()
	{
		if(this->attachments.size() > 0)
		{
			try
			{
				std::string str = this->attachments.back();
				this->error_code = boost::lexical_cast<long>(str);

				return;
			}
			catch(const boost::bad_lexical_cast &)
			{
			}
		}

		this->error_code = -1;
		this->_msg += " (error decoding error_code)";
	}
};

/**
 * Obsolete?
 */
class GSTCastError : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTCastError(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTCASTERROR)
	{
	}

	// thrower interface
	GSTCastError(const std::string &throwLocation,
				 const std::string &from,
				 const std::string &to)
		: GSTRuntimeException(throwLocation, "", GSTCASTERROR)
	{
		std::stringstream smsg;
		smsg << "Cast error from \"" << from << "\" to \"" << to << "\".";
		_msg = smsg.str();
	}
};

/* ClientQueryError -> replace by SQLSyntaxError(RDBDriverInterface.h)
 */

/* ClientConnectionClosed -> replace by
 * ConnectionTerminated(RDBDriverInterface.h)
 */

class GSTSQLNULLException : public GSTSQLError
{
public:
	/// catcher interface
	GSTSQLNULLException(const std::string &encodedMessage)
		: GSTSQLError(encodedMessage)
	{
	}

	// thrower interface
	GSTSQLNULLException(const std::string &throwLocation,
						const std::string &sql,
						int spi_exec_err_code)
		: GSTSQLError(throwLocation, "", sql, spi_exec_err_code)
	{
	}
};

class GSTSQLEmptyResultset : public GSTSQLError
{
public:
	/// catcher interface
	GSTSQLEmptyResultset(const std::string &encodedMessage)
		: GSTSQLError(encodedMessage)
	{
	}

	// thrower interface
	GSTSQLEmptyResultset(const std::string &throwLocation,
						 const std::string &sql,
						 int spi_exec_err_code)
		: GSTSQLError(throwLocation, "", sql, spi_exec_err_code)
	{
	}
};

class GSTIncompatibleInsert : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTIncompatibleInsert(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTINCOMPATIBLE)
	{
	}

	// thrower interface
	GSTIncompatibleInsert(const std::string &throwLocation,
						  const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTINCOMPATIBLE)
	{
	}
};

class GSTFeatureIncompatibleToFeatureclass : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTFeatureIncompatibleToFeatureclass(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTINCOMPATIBLEFEATURE)
	{
	}

	// thrower interface
	GSTFeatureIncompatibleToFeatureclass(const std::string &throwLocation,
										 const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTINCOMPATIBLEFEATURE)
	{
	}
};

class GSTLicenseError : public GSTRuntimeException
{
public:
	long error_code;

	/// catcher interface
	GSTLicenseError(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTLICENSEERROR)
	{
		this->attachment2ExceptionData();
	}

	// thrower interface
	GSTLicenseError(const std::string &throwLocation,
					const std::string &msg,
					long exec_err_code)
		: GSTRuntimeException(throwLocation, msg, GSTLICENSEERROR)
		, error_code(exec_err_code)
	{
		// append error_code to attachment
		this->attachments.push_back(
			boost::lexical_cast<std::string>(error_code));
	}

	void attachment2ExceptionData()
	{
		if(this->attachments.size() > 0)
		{
			try
			{
				std::string atStr = this->attachments.back();
				this->error_code = boost::lexical_cast<long>(atStr);

				return;
			}
			catch(const boost::bad_lexical_cast &)
			{
			}
		}

		this->error_code = -1;
		this->_msg += " (error decoding error_code)";
	}
};

class GSTTransactionTimeout : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTTransactionTimeout(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTTIMEOUT)
	{
	}

	// thrower interface
	explicit GSTTransactionTimeout(const std::string &throwLocation,
								   const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTTIMEOUT)
	{
	}
};

class SRSStillInUseException : public GSTRuntimeException
{
public:
	typedef std::vector<std::string> ClassList;
	ClassList featureClassList;

	/// catcher interface
	SRSStillInUseException(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTSRSINUSE)
	{
		this->attachment2ExceptionData();
	}

	// thrower interface
	SRSStillInUseException(const std::string &throwLocation,
						   const std::string &message,
						   const ClassList &featureClassList)
		: GSTRuntimeException(throwLocation, message, GSTSRSINUSE)
		, featureClassList(featureClassList)
	{
		// append featureClassList to attachments
		for(const std::string &fc : featureClassList)
		{
			this->attachments.push_back(fc);
		}
	}
	virtual ~SRSStillInUseException() throw()
	{
		// needs to be here because of nontrivial destructor of ClassList
		// otherwise we'll have "specification of overriding function
		// is more lax than base version"
	}

	void attachment2ExceptionData()
	{
		if(this->attachments.size() > 0)
		{
			for(const std::string &at : attachments)
			{
				this->featureClassList.push_back(at);
			}

			// stop here
			return;
		}

		// inform in bad case
		this->_msg += " (error decoding featureClassList)";
	}
};

class GSTInvalidArgument : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTInvalidArgument(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTINVALIDARG)
	{
	}

	// thrower interface
	GSTInvalidArgument(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTINVALIDARG)
	{
	}
};

class GSTTooFewArguments : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTTooFewArguments(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTTOOFEWARGUMENTS)
	{
	}

	// thrower interface
	GSTTooFewArguments(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTTOOFEWARGUMENTS)
	{
	}
};

class GSTInvalidType : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTInvalidType(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTINVALIDTYPE)
	{
	}

	// thrower interface
	GSTInvalidType(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTINVALIDTYPE)
	{
	}
};

class GSTCouldNotCreateGeometry : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTCouldNotCreateGeometry(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTCOULDNOTCREATEGEO)
	{
	}

	// thrower interface
	GSTCouldNotCreateGeometry(const std::string &throwLocation,
							  const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTCOULDNOTCREATEGEO)
	{
	}
};

class GSTInvalidDatabase : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTInvalidDatabase(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTINVALIDDATABASE)
	{
	}

	// thrower interface
	GSTInvalidDatabase(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTINVALIDDATABASE)
	{
	}
};

class GSTUnsupported : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTUnsupported(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTUNSUPPORTED)
	{
	}

	// thrower interface
	GSTUnsupported(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTUNSUPPORTED)
	{
	}
};

class GSTNoGeometry : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTNoGeometry(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTNOGEOMETRY)
	{
	}

	// thrower interface
	GSTNoGeometry(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTNOGEOMETRY)
	{
	}
};

class EmptyGeometry : public GSTRuntimeException
{
public:
	/// catcher interface
	EmptyGeometry(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, EMPTYGEOMETRY)
	{
	}

	// thrower interface
	EmptyGeometry(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, EMPTYGEOMETRY)
	{
	}
};

class GSTLogFileException : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTLogFileException(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTLOGFILEEXCEPTION)
	{
	}

	// thrower interface
	GSTLogFileException(const std::string &throwLocation,
						const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTLOGFILEEXCEPTION)
	{
	}
};

class GSTFormatError : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTFormatError(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTFORMATERROR)
	{
	}

	// thrower interface
	GSTFormatError(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTFORMATERROR)
	{
	}
};

class GSTNotFound : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTNotFound(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTNOTFOUND)
	{
	}

	// thrower interface
	GSTNotFound(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTNOTFOUND)
	{
	}
};
class GSTNoTransformAvailable : public GSTRuntimeException
{
public:
	/// catcher interface
	GSTNoTransformAvailable(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GSTNOTRANSFORM)
	{
	}

	// thrower interface
	GSTNoTransformAvailable(const std::string &throwLocation,
							const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GSTNOTRANSFORM)
	{
	}
};

class BadParameter : public GSTRuntimeException
{
public:
	std::string parameterName;

	/// catcher interface
	BadParameter(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, BADPARAMETER)
	{
		this->attachment2ExceptionData();
	}

	// thrower interface
	BadParameter(const std::string &throwLocation,
				 const std::string &msg,
				 const std::string &parameterName)
		: GSTRuntimeException(throwLocation, msg, BADPARAMETER)
		, parameterName(parameterName)
	{
		this->_msg += "(parameter: " + parameterName + ")";

		// append parameterName to attachments
		this->attachments.push_back(parameterName);
	}

	virtual ~BadParameter() throw()
	{
	}

	void attachment2ExceptionData()
	{
		if(this->attachments.size() > 0)
		{
			this->parameterName = this->attachments.back();

			// stop here
			return;
		}

		this->parameterName = "";
		this->_msg += " (error decoding parameterName)";
	}
};

class GeometryIsLocked : public GSTRuntimeException
{
public:
	/// catcher interface
	GeometryIsLocked(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GEOMETRYISLOCKED)
	{
	}

	// thrower interface
	GeometryIsLocked(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GEOMETRYISLOCKED)
	{
	}
	virtual ~GeometryIsLocked() throw()
	{
	}
};

class GeometryIsLockedInArea : public GSTRuntimeException
{
public:
	/// catcher interface
	GeometryIsLockedInArea(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GEOMETRYISLOCKEDINAREA)
	{
	}

	// thrower interface
	GeometryIsLockedInArea(const std::string &throwLocation,
						   const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, GEOMETRYISLOCKEDINAREA)
	{
	}
	virtual ~GeometryIsLockedInArea() throw()
	{
	}
};

class InvalidFormatString : public GSTRuntimeException
{
public:
	/// catcher interface
	InvalidFormatString(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, INVALIDFORMATSTRING)
	{
	}

	// thrower interface
	InvalidFormatString(const std::string &throwLocation,
						const std::string &formatstring)
		: GSTRuntimeException(throwLocation, "", INVALIDFORMATSTRING)
	{
		this->_msg = "Output type " + formatstring + " is not registered.";
	}
};

class GeometryIdUnknown : public GSTRuntimeException
{
public:
	long geometryid;

	/// catcher interface
	GeometryIdUnknown(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, GEOMETRYIDUNKNOWN)
	{
		this->attachment2ExceptionData();
	}

	// thrower interface
	GeometryIdUnknown(const std::string &throwLocation, const long &geometryid)
		: GSTRuntimeException(throwLocation, "", GEOMETRYIDUNKNOWN)
		, geometryid(geometryid)
	{
		this->_msg
			= "geometry with id=" + boost::lexical_cast<std::string>(geometryid)
			  + " does not exists.";

		// append geometryid to attachments
		this->attachments.push_back(
			boost::lexical_cast<std::string>(geometryid));
	}

	void attachment2ExceptionData()
	{
		if(this->attachments.size() > 0)
		{
			try
			{
				std::string geometryIdStr = this->attachments.back();
				this->geometryid = boost::lexical_cast<long>(geometryIdStr);

				// stop here
				return;
			}
			catch(const boost::bad_lexical_cast &)
			{
			}
		}

		// inform in bad case
		this->geometryid = -1;
		this->_msg += " (error decoding geometryId)";
	}
};

class TransformError : public GSTRuntimeException
{
public:
	/// catcher interface
	TransformError(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, TRANSFORMERROR)
	{
	}

	// thrower interface
	TransformError(const std::string &throwLocation, const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, TRANSFORMERROR)
	{
	}
};

class BorderConstraintViolated : public GSTRuntimeException
{
public:
	/// catcher interface
	BorderConstraintViolated(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, BORDERCONSTRAINTVIOLATED)
	{
	}

	// thrower interface
	BorderConstraintViolated(const std::string &throwLocation,
							 const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, BORDERCONSTRAINTVIOLATED)
	{
	}

	virtual ~BorderConstraintViolated() throw()
	{
	}
};

class FeatureIsLocked : public GSTRuntimeException
{
public:
	std::vector<int> lockedGeometryIds;

	/// catcher interface
	FeatureIsLocked(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, FEATUREISLOCKED)
	{
	}

	// thrower interface
	FeatureIsLocked(const std::string &throwLocation,
					const std::string &msg,
					const std::vector<int> &lockedGeometryIds)
		: GSTRuntimeException(throwLocation, msg, FEATUREISLOCKED)
		, lockedGeometryIds(lockedGeometryIds)
	{
	}

	virtual ~FeatureIsLocked() throw()
	{
	}
};

class IntersectionNoResult : public GSTRuntimeException
{
public:
	/// catcher interface
	IntersectionNoResult(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, INTERSECTIONNORESULT)
	{
	}

	// thrower interface
	IntersectionNoResult(const std::string &throwLocation,
						 const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, INTERSECTIONNORESULT)
	{
	}

	virtual ~IntersectionNoResult() throw()
	{
	}
};

class RtreeIndexAlreadyExists : public GSTRuntimeException
{
public:
	/// catcher interface
	RtreeIndexAlreadyExists(const std::string &encodedMessage)
		: GSTRuntimeException(encodedMessage, RTREEINDEXALREADYEXISTS)
	{
	}

	// thrower interface
	RtreeIndexAlreadyExists(const std::string &throwLocation,
							const std::string &msg)
		: GSTRuntimeException(throwLocation, msg, RTREEINDEXALREADYEXISTS)
	{
	}

	virtual ~RtreeIndexAlreadyExists() throw()
	{
	}
};

class GeometryRejectedByAreaLimiter : public GSTRuntimeException
{
public:
	// thrower interface
	GeometryRejectedByAreaLimiter(const std::string &throwLocation,
								  const std::string &msg)
		: GSTRuntimeException(throwLocation, msg)
	{
	}

	virtual ~GeometryRejectedByAreaLimiter() noexcept
	{
	}
};

} // namespace exceptions
} // namespace GST

#endif //_GSTRUNTIMEEXCEPTION_H_
