#ifndef _Serializer_h__
#define _Serializer_h__

#include <buildspec.h>

#include <Client/ClientUtils/Network/NetworkInterface.h>

namespace GST
{

namespace exceptions
{
/**
 * Base class for test's performed by Serializer::TestInsertIsValid()
 */
class FeatureClassInsertIsInvalid : public GSTRuntimeException
{
public:
	FeatureClassInsertIsInvalid(const std::string &throwLocation,
								const std::string &msg)
		: GSTRuntimeException(throwLocation, msg)
	{
	}

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

/**
 * if owner specified in the class is not available for the current logged on
 *user.
 *
 *	Potential reasons this check failed:
 *	<ol>
 *		<li> User is different
 *		<li> User is not in the group
 * </ol>
 */
class OwnerNotAvailable : public FeatureClassInsertIsInvalid
{
public:
	std::string ownerStr;
	bool ownerIsGroup;

	OwnerNotAvailable(const std::string &throwLocation,
					  const std::string &ownerStr,
					  bool ownerIsGroup)
		: FeatureClassInsertIsInvalid(throwLocation, "OwnerNotAvailable")
		, ownerStr(ownerStr)
		, ownerIsGroup(ownerIsGroup)
	{
	}

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

/**
 * if feature class is still in use
 */
class FeatureClassInUse : public FeatureClassInsertIsInvalid
{
public:
	std::string featureClassName;

	FeatureClassInUse(const std::string &throwLocation,
					  const std::string &featureClassName)
		: FeatureClassInsertIsInvalid(throwLocation, "FeatureClassInUse")
		, featureClassName(featureClassName)
	{
	}

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

/**
 * if the srs specified in class is not available at the current connection
 */
class SRSNotAvailable : public FeatureClassInsertIsInvalid
{
public:
	std::string srsIdentifier;

	SRSNotAvailable(const std::string &throwLocation,
					const std::string &message,
					const std::string &srsIdentifier)
		: FeatureClassInsertIsInvalid(throwLocation, message)
		, srsIdentifier(srsIdentifier)
	{
	}

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

/**
 *  if the feature class as constrained object properties, but the linked table
 * is not available
 */
class SourceTableNotAvailable : public FeatureClassInsertIsInvalid
{
public:
	std::string sourceTableName;
	std::string errorReport;

	SourceTableNotAvailable(const std::string &throwLocation,
							const std::string &sourceTableName,
							const std::string &errorReport)
		: FeatureClassInsertIsInvalid(throwLocation, "SourceTableNotAvailable")
		, sourceTableName(sourceTableName)
		, errorReport(errorReport)
	{
	}

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

/**
 * if the feature class as constrained object properties, linked table exists
 * but some columns are not available
 */
class SourceColumnNotAvailable : public FeatureClassInsertIsInvalid
{
public:
	std::string sourceTableName;
	std::string columnName;
	std::string errorReport;

	SourceColumnNotAvailable(const std::string &throwLocation,
							 const std::string &sourceTableName,
							 const std::string &columnName,
							 const std::string &errorReport)
		: FeatureClassInsertIsInvalid(throwLocation, "SourceTableNotAvailable")
		, sourceTableName(sourceTableName)
		, columnName(columnName)
		, errorReport(errorReport)
	{
	}

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

} // namespace exceptions

namespace ClientUtils
{

class GST_API_EXPORT Serializer
{
public:
	static void FeatureClassDescsToFile(
		const std::string &fileName,
		FeatureClassDetailedDescListPtr featureClasses);
	static FeatureClassDetailedDescListPtr FeatureClassDescsFromFile(
		const std::string &fileName);

	/**
	  * Performs checks if featureClass can be inserted to the database.
	  * @throws FeatureClassInsertIsInvalid		if a check failed (this is the
	  base class. catch the subclasses to identify which check fails) *	@throws
	  OwnerNotAvailable				if owner specified in the class is not
	  available for the current logged on user.
	  * @throws FeatureClassInUse				if feature class is still in use
	  * @throws SRSNotAvailable					if the srs specified in class is
	  not available at the current connection
	  * @throws SourceTableNotAvailable			if the feature class as
	  constrained object properties, but the linked table is not available
	  * @throws SourceColumnNotAvailable		if the feature class as
	  constrained object properties, linked table exists but some columns are
	  not available
	  *
	  * Pass the parameters owners, featureClasses, srsList if you call this
	  method multiple time. This prevents from querying them on each call.
	  *
	  * \code
	  OwnerListPtr owners = connection->GetOwners();
	  FeatureClassDescListPtr featureClasses = connection->ListFeatureClasses();
	  SRSItemDescListPtr srsList = connection->ListAllSRS();
	  TestInsertIsValid(featureClass, connection, owners, featureClasses,
	  srsList);
	  * \endcode
	  */
	static void TestInsertIsValid(FeatureClassDetailedDescPtr featureClass,
								  NetworkPtr connection,
								  OwnerListPtr owners = OwnerListPtr(),
								  FeatureClassDescListPtr featureClasses
								  = FeatureClassDescListPtr(),
								  Geometry::SRSItemDescListPtr srsList
								  = Geometry::SRSItemDescListPtr());

protected:
	static void TestConstrainedProperty(TableConstrainedAttributeDescPtr cp,
										NetworkPtr connection);
};

} // namespace ClientUtils
} // namespace GST

#endif // _Serializer_h__
