#ifndef _TABLE_ATTRIBUTE_DESC_H_
#define _TABLE_ATTRIBUTE_DESC_H_

#include <GSTenums.h>
#include <Geometry/boost_serialize_includes.hpp>
#include <Utils/Converter.h>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <buildspec.h>
#include <exceptions/GSTRuntimeException.h>
#include <map>
#include <string>

namespace GST
{

// exceptions:
// see below class!

namespace Geometry
{
class SimplexProperty;
}

namespace ClientUtils
{

// prototype:
class TableAttributeVal;
class FeatureClassDesc;
typedef boost::shared_ptr<TableAttributeVal> TableAttributeValPtr;

/**
 * A Description of a table attribute (without its value).
 */
class GST_API_EXPORT TableAttributeDesc
{
	friend class boost::serialization::access;

public:
	typedef GST::DataType DType;

	/**
	 * DType to data model string (as used in table constraints)
	 */
	static std::string DTypeToDMString(DType dtype);
	/**
	 * Data model string (used in table constraints) to DType
	 */
	static DType DMStringToDType(const std::string &type);

	// TableAttributeDesc(const std::string& name, const std::string& tablename,
	// DType type, int dimension, bool notNull = false);
	TableAttributeDesc(const std::string &name,
					   const std::string &tablename,
					   DType type,
					   int dimension,
					   bool notNull = false,
					   const std::string &alternativeType = "",
					   const int &colIndex = -1,
					   const long &id = -1);
	TableAttributeDesc();
	TableAttributeDesc(const TableAttributeDesc &other);
	TableAttributeDesc &operator=(const TableAttributeDesc &src);
	virtual ~TableAttributeDesc()
	{ ///@todo: implement me!
	}

	///@name setters/getters
	//@{
	virtual std::string getName() const;
	virtual void setName(const std::string &name);
	virtual std::string getTableName() const;
	virtual void setTableName(const std::string &tname);
	virtual DType getType() const;
	void setType(DType dtype);
	virtual int getDimension() const;
	virtual void setAlternativeType(const std::string &typeStr);
	virtual std::string getAlternativeType() const
	{
		return this->alternativeTypeString;
	}
	virtual int getColIndex() const
	{
		return this->colIndex;
	}
	virtual long getId() const
	{
		return this->id;
	}
	virtual void setId(const long &id)
	{
		this->id = id;
	}
	virtual void setNotNull(bool notNull);
	virtual bool isNotNull() const;
	virtual TableAttributeDesc *clone() const;
	//@}

	virtual bool operator==(const TableAttributeDesc &other) const;
	bool compareDtype(const DType &datatype,
					  const std::string alternativeDType = "") const;
	bool compareNames(const std::string &name,
					  const std::string &othername) const;

protected:
	std::string tablename;
	std::string name;
	int dimension;
	DType datatype;
	std::string alternativeTypeString;
	bool notNull;
	int colIndex;
	long id;

private:
	template<typename Archive>
	void serialize(Archive &ar, const unsigned int version)
	{
		// If you change members here do not forget to increment object version
		// (see bottom of this file)
		ar &boost::serialization::make_nvp("name", this->name);
		ar &boost::serialization::make_nvp("parentTable", this->tablename);
		ar &boost::serialization::make_nvp("dimension", this->dimension);
		ar &boost::serialization::make_nvp("datatype", this->datatype);
		ar &boost::serialization::make_nvp("alternativeDType",
										   this->alternativeTypeString);
		ar &boost::serialization::make_nvp("notNull", this->notNull);
	}
};
typedef boost::shared_ptr<TableAttributeDesc> TableAttributeDescPtr;
// typedef boost::ptr_map<std::string, TableAttributeDesc>
// TableAttributeDescList;

typedef std::map<std::string, TableAttributeDescPtr, Utils::UpperCaseCompare>
	TableAttributeDescList;
typedef boost::shared_ptr<TableAttributeDescList> TableAttributeDescListPtr;

//-----------------------------------------------------------------------------------------------------------

class GST_API_EXPORT TableAttributeKeyDesc : public TableAttributeDesc
{
	friend class boost::serialization::access;

public:
	TableAttributeKeyDesc(const std::string &name,
						  const std::string &tablename,
						  DType type,
						  int dimension,
						  bool primaryKey,
						  const std::string &alternativeType = "");
	// TableAttributeKeyDesc(const Geometry::SimplexProperty & geomProperty,
	// const FeatureClassDesc & target, bool primaryKey );
	TableAttributeKeyDesc();
	TableAttributeKeyDesc(const TableAttributeDesc &parent, bool primaryKey);

	bool isPrimaryKey() const;
	void setIsPrimaryKey(bool val);

	bool operator==(const TableAttributeKeyDesc &other) const;

protected:
	bool primaryKey;

private:
	template<typename Archive>
	void serialize(Archive &ar, const unsigned int version)
	{
		// If you change members here do not forget to increment object version
		// (see bottom of this file)
		ar &boost::serialization::make_nvp(
			"TableAttributeDesc",
			boost::serialization::base_object<TableAttributeDesc>(*this));
		ar &boost::serialization::make_nvp("primaryKey", this->primaryKey);
	}
};
typedef boost::shared_ptr<TableAttributeKeyDesc> TableAttributeKeyDescPtr;
typedef std::vector<TableAttributeKeyDescPtr> TableAttributeKeyDescList;
typedef boost::shared_ptr<TableAttributeKeyDescList>
	TableAttributeKeyDescListPtr;

//-----------------------------------------------------------------------------------------------------------
} // namespace ClientUtils
} // namespace GST
BOOST_CLASS_EXPORT_KEY(GST::ClientUtils::TableAttributeDesc);
BOOST_CLASS_EXPORT_KEY(GST::ClientUtils::TableAttributeKeyDesc);

BOOST_CLASS_VERSION(GST::ClientUtils::TableAttributeDesc, 1)
BOOST_CLASS_VERSION(GST::ClientUtils::TableAttributeKeyDesc, 1)

#endif //_TABLE_ATTRIBUTE_DESC_H_
