#ifndef _UTILS_H_
#define _UTILS_H_

#include <Client/ClientUtils/MoMaStructs.h>
#include <Client/ClientUtils/Network/FeatureClassDetailedDesc.h>
#include <Client/ClientUtils/Network/ObjectPropertyDesc.h>
#include <Client/ClientUtils/Network/SimplexPropertyDesc.h>
#include <Client/ClientUtils/Network/TableAttributeDesc.h>
#include <Geometry/IFileSerialisable.h>
#include <Utils/Color.h>
#include <buildspec.h>
#include <sstream>
#include <string>
#include <vector>

#include <boost/optional.hpp>

namespace GST
{
namespace ClientUtils
{

GST_API_EXPORT std::string &strreplace(std::string &in,
									   const std::string &from,
									   const std::string &to);
GST_API_EXPORT bool stringInVector(const std::string &toFind,
								   const std::vector<std::string> &findin,
								   bool case_sensitive = true);
GST_API_EXPORT std::vector<std::string>::iterator getStringInVector(
	const std::string &toFind,
	std::vector<std::string> &findin,
	bool case_sensitive = true);

GST_API_EXPORT bool IsDefaultProperty(const std::string &name);

GST_API_EXPORT ClientUtils::OwnerList::const_iterator GetOwnerById(
	const OwnerList &from,
	Owner::OwnerId id);
GST_API_EXPORT ClientUtils::ColorScaleList::iterator GetColorScaleById(
	ColorScaleList &from,
	ColorScale::ColorScaleId id);
GST_API_EXPORT ClientUtils::ColorValueList::const_iterator GetColorValueById(
	const ColorValueList &from,
	ColorValue::ColorValueId id);
/**
 * @returns A TableAttributeDescListPtr from ObjectPropertyList
 * when corresponding object property is called "id", TableAttributekeyDesc with
 * primary key flag will be created instead of TableAttributeDesc.    */

GST_API_EXPORT ClientUtils::TableAttributeDescListPtr
ObjectPropertyDescListPtrToTableAttributeDescListPtr(
	ObjectPropertyDescListPtr objectProperties);
GST_API_EXPORT ClientUtils::TableAttributeDescListPtr
SimplexPropertyDescListPtrToTableAttributeDescListPtr(
	SimplexPropertyDescListPtr simplexProperties);

GST_API_EXPORT ClientUtils::ObjectPropertyDescListPtr
TableAttributeDescListPtrToObjectPropertyDescListPtr(
	TableAttributeDescListPtr properties);
GST_API_EXPORT ClientUtils::SimplexPropertyDescListPtr
TableAttributeDescListPtrToSimplexPropertyDescListPtr(
	TableAttributeDescListPtr properties,
	GST::Geometry::PropertyAlignments alignment
	= GST::Geometry::VERTEX_ALIGNED);

GST_API_EXPORT ClientUtils::ObjectPropertyDescArrayPtr
ObjectPropertyDescListPtrToObjectPropertyDescArrayPtr(
	ObjectPropertyDescListPtr objProperties);
GST_API_EXPORT ClientUtils::SimplexPropertyDescArrayPtr
SimplexPropertyDescListPtrToSimplexPropertyDescArrayPtr(
	SimplexPropertyDescListPtr simplexProperties);

GST_API_EXPORT TableAttributeKeyDescListPtr
TableAttributeDescList2TableAttributeKeyDescList(
	const TableAttributeDescList &descList);
GST_API_EXPORT TableAttributeDescListPtr
TableAttributeKeyDescList2TableAttributeDescList(
	const TableAttributeKeyDescList &keyList);

GST_API_EXPORT void ParseTablename(const std::string &tablename,
								   std::string &table,
								   std::string &schema,
								   std::string &db,
								   bool removeQuotes = true);
GST_API_EXPORT void ParseColumnname(const std::string &columnname,
									std::string &column,
									std::string &table,
									std::string &schema,
									std::string &db,
									bool removeQuotes = true);
GST_API_EXPORT std::string RemoveQuotes(const std::string &identifer);
GST_API_EXPORT std::string ReplaceSchema(const std::string &fulltableName,
										 const std::string &newSchemaname);

/**
 * @returns A TableAttributeValWithKeyPtr from cp_values where the given primary
 * key (keyValues) are matching This is similar to the where clause of statement
 * (in pseudo code): select cp_values.* from cp_values where cp_values.pk1 =
 * keyValues.pk1 AND cp_values.pk2 = keyValues.2
 *
 * @throws exceptions::GSTRuntimeException		If no matching key pair found
 * @throws exceptions::KeyIsNull				If a key value in keyValues is a
 * NULL value (thrown from TableAttributeValWithKey::compareKeyValues)
 */
GST_API_EXPORT ConstrainedTableAttributeValPtr GetConstrainedValueByKey(
	ClientUtils::ConstrainedTableAttributeValArrayPtr cp_values,
	const ClientUtils::TableAttributeValueArray &keyValues);
GST_API_EXPORT bool IsInvalidUserName(const std::string &name);
GST_API_EXPORT bool IsInvalidGroupName(const std::string &name);

// Returns the name, if it is present and not NULL and not empty.
GST_API_EXPORT boost::optional<std::string> GetNameFromObjectPropertyValues(
	const TableAttributeValList &values);
// Returns the color, if it is present and not NULL.
GST_API_EXPORT boost::optional<Utils::ColorRGBA>
GetColorFromObjectPropertyValues(const TableAttributeValList &values);
// Returns the alias, if it is present and not NULL and not empty.
GST_API_EXPORT boost::optional<std::string> GetAliasFromObjectPropertyValues(
	const TableAttributeValList &values);

// Convertsion between `PropertyTypes` and `TableAttributeDesc::DType`
GST_API_EXPORT TableAttributeDesc::DType attributeTypeFromPropertyType(
	Geometry::PropertyTypes propertyType);
GST_API_EXPORT Geometry::PropertyTypes propertyTypeFromAttributeType(
	TableAttributeDesc::DType propertyType);

// Returns the next free name in the given list of names
//
// The name is generated using the pattern "<left><counter><right>", where
// counter is a increasing integer, starting from 1.
//
// This function will find the next free gap given the input pattern.
//
// Example:
//
// nextFreeName("test(", ")", {"test(1)", "ok", "test(3)"}) == "test(2)"
// nextFreeName("test(", ")", {}) == "test(1)"
// nextFreeName("test(", ")", {"ok"}) == "test(1)"
// nextFreeName("test(", ")", {"test(1)"}) == "test(2)"
GST_API_EXPORT std::string nextFreeName(const std::string &left,
										const std::string &right,
										const std::vector<std::string> &names);

GST_API_EXPORT bool hasConstrainedColor(
	const ObjectPropertyDescList &objectProperties);

// remaps aliasMap from column index of cop to column id of newCop
//
// pre: newCop and cop map the same columns
// post: result has an entry for each alias in aliasMap, where key is the
//       constrained column id instead of the local column index.
GST_API_EXPORT std::map<int, PropertyAliasPtr> remapCopAliasMap(
	const ConstrainedObjectPropertyDesc &newCop,
	const ConstrainedObjectPropertyDesc &cop,
	const std::map<int, PropertyAliasPtr> &aliasMap);

// Determine the access right for the current user from the given assigned
// rights.
//
// Note: No handling of special rights (e.g. owner, admin user).
GST_API_EXPORT AccessRight
determineAccessRight(const User &currentUser,
					 GroupList groupsOfCurrentUser,
					 const std::vector<AssignedAccessRight> &assignedRights);

} // namespace ClientUtils
} // namespace GST

#endif
