#ifndef _NetworkInterfaceStructs_h_
#define _NetworkInterfaceStructs_h_

#include <GSTCore/GST_Types.h>
#include <GSTenums.h>
#include <Geometry/IGeometry.h>
#include <Geometry/SRS.h>
#include <Utils/GSTVersion.h>
#include <buildspec.h>
#include <config.h>
#include <transport/JsonFileEncoder.h>

#include <Client/ClientUtils/Network/ColorMap.hpp>
#include <Client/ClientUtils/Network/NetworkInterfaceExceptions.hpp>
#include <Client/ClientUtils/Network/SimplexPropertyDesc.h>
#include <Client/ClientUtils/Network/TableAttributeVal.h>

#include <Parsers/image_data.hpp>

#include <cstdint>
#include <set>
#include <string>

#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>

namespace GST
{

// prototypes:
namespace ClientUtils
{
class IDataTable;
class FeatureClassDetailedDesc;
class GeoColumnDesc;
struct FeatureDesc;
class FeatureClassDesc;
} // namespace ClientUtils
namespace Geometry
{
class ClientGeometry;
}

namespace ClientUtils
{
using GST::GSTCore::GSTbox;

// helpers:
struct GST_API_EXPORT Host
{
	std::string ip;
	long port;
	std::string user, pwd;
	// Empty => Use system certificate chain.
	// Non empty => Use supplied certificate.
	std::string sslCert;
	// True => Use proxy, see proxyUrl.
	// False => Don't use proxy, proxyUrl is ignored.
	bool useProxy;
	// Empty => Use system proxy settings.
	// Non empty => Use custom proxy settings.
	//
	// `socks5://user:password@proxy-host:1234` (user, password, port optional)
	// `socks4://proxy-host:1234` (port is optional)
	// `http[s]://user:password@proxy-host:1234` (user, password, port optional)
	std::string proxyUrl;
	Host(const std::string &_url = "",
		 const long &_port = 0,
		 const std::string &_usr = "",
		 const std::string &_pwd = "",
		 const std::string &_sslCert = "",
		 const bool _useProxy = false,
		 const std::string &_proxyUrl = "")
		: ip(_url)
		, user(_usr)
		, pwd(_pwd)
		, sslCert(_sslCert)
		, useProxy(_useProxy)
		, proxyUrl(_proxyUrl)
	{
		port = _port > 0 ? _port : 80;
	}
	void setParameters(const std::string &_url = "",
					   const long &_port = 0,
					   const std::string &_usr = "",
					   const std::string &_pwd = "",
					   const std::string &_sslCert = "",
					   const bool _useProxy = false,
					   const std::string &_proxyUrl = "")
	{
		ip = _url;
		port = _port;
		user = _usr;
		pwd = _pwd;
		sslCert = _sslCert;
		useProxy = _useProxy;
		proxyUrl = _proxyUrl;
	}
	bool operator==(const Host &other) const;
	bool operator!=(const Host &other) const;
	bool isAuth() const
	{
		return !user.empty();
	}
}; // struct Host
typedef boost::shared_ptr<Host> HostPtr;

struct GST_API_EXPORT KeyValueList
{
	typedef std::map<std::string, std::string> KVL;
	KVL list;
	const std::string &getKey(const KVL::const_iterator &itr)
	{
		return itr->first;
	}
	const std::string &getValue(const KVL::const_iterator &itr)
	{
		return itr->second;
	}
};
typedef boost::shared_ptr<KeyValueList> KeyValueListPtr;

struct GST_API_EXPORT ServerInfo : public KeyValueList
{
	typedef KeyValueList::KVL::const_iterator const_iterator;

	ServerInfo()
	{
	}
	ServerInfo(const std::string &field, const std::string &value)
	{
		list[field] = value;
	}
	void push_back(const std::string &field, const std::string &value)
	{
		list[field] = value;
	}
	const_iterator begin() const
	{
		return this->list.begin();
	}
	const_iterator end() const
	{
		return this->list.end();
	}
	size_t size() const
	{
		return this->list.size();
	}
	static std::string getField(const const_iterator &i)
	{
		return i->first;
	}
	static std::string getValue(const const_iterator &i)
	{
		return i->second;
	}
};
typedef boost::shared_ptr<ServerInfo> ServerInfoPtr;

enum class ZAxisDomain
{
	// The z-axis is height (unit=m), positive direction is up (elevation)
	Height,
	// The z-axis is time (unit=ms), positive direction is down (depth)
	Time,
};

enum class FeatureClassTag
{
	// no special tagging
	Default,
	// A geometry with texture coordinates and texture.
	TexturedGeometry,
	// A collective shapefile
	SHPCollection,
	// A unknown feature class tag from a future rust version
	Unknown,
};

enum class ColorMapOutputFormat
{
	XCMap,
	StratMap,
	// gmt color palette tables (*.cpt)
	CPMap
};

enum class Unit
{
	Feet,
	Meters,
	Kilometers,
	Miliseconds,
	Seconds,
};

// see SEGY standard page 7
// https://seg.org/Portals/0/SEG/News%20and%20Resources/Technical%20Standards/seg_y_rev2_0-mar2017.pdf
enum class NumberFormat
{
	IBM4B = 1,
	COMP4B,
	COMP2B,
	FIX4B,
	IEEE4B,
	IEEE8B,
	COMP3B,
	COMP1B,
	COMP8B,
	UINT4,
	UINT2,
	UINT8,
	UINT3,
	UINT1,
};

// This enum exists to make `SEGYInfo` dimensionality less prone to error.
enum class Dimensionality
{
	TwoD = 2,
	ThreeD,
	FourD,
};

// This enum exists to import `GSTOrderTraceBy` into this part of GST3.
enum class GSTOrderTraceBy
{
	Default = 1,
	TraceSequenceOnLine,
	TraceSequenceInFile,
	FieldRecordNo,
	TraceNo,
	TraceNoInEnsemble,
};

// Trace header as a binary struct, here for performance and import reasons.
class GST_API_EXPORT SEGYTraceHeader
{
public:
	SEGYTraceHeader();
	std::string StringifyByteOrder() const;

	int32_t trace_sequence_on_line, trace_sequence_in_file, field_record_no,
		trace_no, energy_source_point_no, ensemble_no, trace_no_in_ensemble,
		trace_identification_code, no_v_summed_traces, no_h_stacked_traces,
		data_use, source_to_receiver_distance, elevation_of_receiver_group,
		surface_elevation_of_source, source_depth,
		datum_elevation_of_receiver_group, datum_elevation_of_source,
		water_column_height_at_source, water_column_height_at_group,
		elevation_scalar, coordinate_scalar, source_x, source_y,
		receiver_group_x, receiver_group_y, coordinate_units, weathing_velocity,
		sub_weathering_velocity, uphole_time_at_source, uphole_time_at_group,
		source_static_correction, group_static_correction, total_static_applied,
		lag_time_a, lag_time_b, delay_recording_time, mute_time_start,
		mute_time_end, no_samples_in_trace, sample_interval_of_trace, gain_type,
		instrument_gain_constant, instrument_initial_gain, correlated,
		sweep_frequency_at_start, sweep_frequency_at_end, sweep_length,
		sweep_type, sweep_trace_taper_length_at_start,
		sweep_trace_taper_length_at_end, taper_type, alias_filter_frequency,
		alias_filter_slope, notch_filter_frequency, notch_filter_slope,
		low_cut_frequency, high_cut_frequency, low_cut_slope, high_cut_slope,
		year_recorded, day_of_year, hour_of_day, minute_of_hour,
		second_of_minute, time_base_code, trace_weighting_factor,
		geophone_group_number_roll_pos1,
		geophone_group_number_first_trace_orig_field,
		geophone_group_number_last_trace_orig_field, gap_size, over_travel,
		x_ensemble, y_ensemble, inline_no, crossline_no, shot_point_no,
		shot_point_scalar, trace_value_measurement_unit,
		transduction_constant_mantissa, transduction_constant_power,
		transduction_units, trace_identifier, time_scalar_trace_header,
		source_type, source_energy_direction_v, source_energy_direction_il,
		source_energy_direction_xl, source_measurement_mantissa,
		source_measurement_exponent, source_measurement_unit;
};
typedef boost::shared_ptr<SEGYTraceHeader> SEGYTraceHeaderPtr;

// TODO: may move this to network structs
class GST_API_EXPORT SEGYInfo
{
public:
	SEGYInfo();

	int32_t samplesZ, inlines, crosslines;
	double originX, originY, originZ, inlineStepX, inlineStepY, crosslineStepX,
		crosslineStepY, inlineExtremityX, inlineExtremityY, crosslineExtremityX,
		crosslineExtremityY, stepZ;

	ZAxisDomain domain;
	Unit areaUnit, depthUnit;

	uint32_t lineByteLocation, traceByteLocation, currentTraceHeader;
	int32_t inlineOrigin, inlineEnd, crosslineOrigin, crosslineEnd;
	uint32_t CDPX, CDPY;

	NumberFormat sampleFormat, coordinateFormat;
	bool trwf, propIsSigned, missingTraces, littleEndian;
	double scalco;

	std::string textHeader;
	std::string binHeader;
	std::vector<SEGYTraceHeaderPtr> traces;

	std::string filePath;
	std::string defaultPropName;
	std::string navigation_file_path;

	Dimensionality dimensionality;
	GSTOrderTraceBy order_trace_by;
	bool override_to_le, override_trace_format, override_coordinate_format,
		override_coordinate_scaling, override_grid_min_max, override_dim_x,
		override_dim_y, override_dim_z, use_navigation_file, override_o_u_v_w,
		override_units;
};

typedef boost::shared_ptr<SEGYInfo> SEGYInfoPtr;
static const std::string S_M_TRACE_MAX_LENGTH = "m_trace_max_length";
static const std::string S_M_SAMPLE_INTERVAL = "m_sample_interval";
static const std::string S_M_TEXT_HEADER = "m_text_header";
static const std::string S_M_BIN_HEADER = "m_binary_header";
static const std::string S_M_SEGY_SETTINGS = "m_segy_settings";
static const std::string S_TRACE_DATA = "trace_data";
static const std::string S_TEX_U = "tex_u";
static const std::string S_TEX_V = "tex_v";
static const std::string S_M_CONSTRAINED_COLOR = "m_coc";
static const std::string S_M_CONSTRAINED_COLOR_VALUE = "m_coc_c";
static const std::string S_M_SUBFEATURE_KIND = "m_subfeature_kind";
static const std::string S_GEOLOGICAL_PROFILE_KIND_HORIZON = "Horizon";
static const std::string S_GEOLOGICAL_PROFILE_KIND_FAULT = "Fault";
static const std::string S_GEOLOGICAL_PROFILE_KIND_POSITON_LINE
	= "Position Line";
static const std::string S_GEOLOGICAL_PROFILE_KIND_MISC = "Misc";
static const std::string S_SHAPEFILE_COLLECTION_KIND = "shp-subfeature";
static const std::string S_M_SUBFEATURE_IMAGE_METADATA
	= "m_subfeature_image_metadata";

class GST_API_EXPORT ParsedFeatureHeader
{
public:
	ParsedFeatureHeader()
		: name(std::string())
		, color()
		, transparency(0.f)
		, feature_type(GST::Geometry::GeometryTypes::unkown)
		, attributes(boost::make_shared<TableAttributeValList>())
		, properties()
		, startPos(-1)
		, endPos(-1)
		, srsEpsgCode(0)
		, srsProj4Def()
		, subfeatureId()
	{
	}

	std::string name;
	Geometry::IGeometry::Color color;
	float transparency;
	GST::Geometry::GeometryTypes feature_type;
	TableAttributeValListPtr attributes;
	std::vector<SimplexPropertyDescPtr> properties;
	int64_t startPos;
	int64_t endPos;
	uint32_t srsEpsgCode;
	std::string srsProj4Def;
	std::string subfeatureId;
	std::string texturePath;
};
typedef boost::shared_ptr<ParsedFeatureHeader> ParsedFeatureHeaderPtr;
typedef std::vector<ParsedFeatureHeaderPtr> ParsedFeatureHeaderPtrList;
typedef boost::shared_ptr<ParsedFeatureHeaderPtrList>
	ParsedFeatureHeaderPtrListPtr;
struct GST_API_EXPORT IfcParserSettings
{
	double h_relative_deviation, h_absolute_deviation, v_relative_deviation,
		v_absolute_deviation, ifc_step_constant;
};
typedef boost::shared_ptr<IfcParserSettings> IfcParserSettingsPtr;

class GST_API_EXPORT SubfeatureKind
{
	friend class boost::serialization::access;

public:
	SubfeatureKind(std::string name,
				   Geometry::GeometryTypes geomtype,
				   bool isRequired,
				   bool isPositionLine,
				   bool allowsImageData);
	const std::string &name() const;
	Geometry::GeometryTypes geomtype() const;
	bool isRequired() const;
	bool isPositionLine() const;
	bool allowsImageData() const;

private:
	std::string m_name;
	Geometry::GeometryTypes m_geomtype;
	bool m_isRequired;
	bool m_isPositionLine;
	bool m_allowsImageData;

private:
	// Default constructor required for boost serialization.
	SubfeatureKind();
	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", m_name);
		ar &boost::serialization::make_nvp("geomtype", m_geomtype);
		ar &boost::serialization::make_nvp("isRequired", m_isRequired);
		ar &boost::serialization::make_nvp("isPositionLine", m_isPositionLine);
		if(version > 1)
		{
			ar &boost::serialization::make_nvp("allowsImageData",
											   m_allowsImageData);
		}
	}
};

class GST_API_EXPORT FeatureClassDesc
{
protected:
	std::string name;
	std::string owner;
	std::string geometryColumn;
	Geometry::IGeometry::GeometryType geomtype;
	Geometry::SRSPtr srs;
	int numberOfFeatures;
	long long id;
	ZAxisDomain zAxisDomain;
	std::set<FeatureClassTag> tags;
	bool protected_;
	std::vector<SubfeatureKind> subfeatureKinds;

public:
	FeatureClassDesc();
	FeatureClassDesc(const std::string &fullClassName,
					 const std::string &geometryColumn,
					 const Geometry::IGeometry::GeometryType &geomtype,
					 Geometry::SRSPtr srs = Geometry::SRSPtr(),
					 int numberOfFeatures = -1,
					 const long long id = -1,
					 ZAxisDomain zAxisDomain = ZAxisDomain::Height,
					 std::set<FeatureClassTag> tags
					 = {FeatureClassTag::Default},
					 bool protected_ = false,
					 std::vector<SubfeatureKind> subFeatureKinds
					 = std::vector<SubfeatureKind>());
	FeatureClassDesc(const std::string &name,
					 const std::string &owner,
					 const std::string &geometryColumn,
					 const Geometry::IGeometry::GeometryType &geomtype,
					 Geometry::SRSPtr srs = Geometry::SRSPtr(),
					 int numberOfFeatures = -1,
					 const long long id = -1,
					 ZAxisDomain zAxisDomain = ZAxisDomain::Height,
					 std::set<FeatureClassTag> tags
					 = {FeatureClassTag::Default},
					 bool protected_ = false,
					 std::vector<SubfeatureKind> subFeatureKinds
					 = std::vector<SubfeatureKind>());

	///@name operators
	//@{
	bool contains(const FeatureDesc &feature) const;
	bool operator==(const FeatureClassDesc &other) const;
	bool operator!=(const FeatureClassDesc &other) const;
	//@}

	///@name getters/setters
	//@{
	bool isPublic() const;
	std::string getFullName() const;
	std::string getFullNameWithoutPoolSuffix() const;
	std::string getGroup() const;
	std::string getGeometryColumn() const;
	void setGeometryColumn(std::string val);
	Geometry::IGeometry::GeometryType getGeomtype() const;
	void setGeomtype(Geometry::IGeometry::GeometryType val);
	std::string getOwner() const;
	std::string getOwnerWithoutPoolSuffix() const;
	void setOwner(std::string val);
	std::string getName() const;
	void setName(std::string val);
	GST::Geometry::SRSPtr getSrs() const;
	void setSrs(GST::Geometry::SRSPtr val);
	/**
	 * @returns optional member FeatureClassDesc::numberOfFeatures that counts
	 * the features in a feature class. The counter is set by
	 * NetworkInterface::ListFeatureClasses(). You can use
	 * FeatureClassDesc::isNumberOfFeaturesFetched() to check whether the
	 * counter is valid or not
	 */
	int getNumberOfFeatures() const;
	void setNumberOfFeatures(int val);
	/**
	 * @returns true if the counter numberOfFeatures is fetched from the
	 * database
	 */
	bool isNumberOfFeaturesFetched() const;
	void setID(const long long &val);
	long long getID() const;
	ZAxisDomain getZAxisDomain() const;
	void setZAxisDomain(ZAxisDomain zAxisDomain);
	const std::set<FeatureClassTag> &getTags() const;
	void setTags(std::set<FeatureClassTag> tags);
	bool isProtected() const;
	void setProtected(bool value);
	const std::vector<SubfeatureKind> &getSubfeatureKinds() const;
	void setSubfeatureKinds(std::vector<SubfeatureKind> subfeatureKinds);
	//@}
};
typedef boost::shared_ptr<FeatureClassDesc> FeatureClassDescPtr;
typedef boost::ptr_vector<FeatureClassDesc> FeatureClassDescList;
typedef boost::shared_ptr<FeatureClassDescList> FeatureClassDescListPtr;

struct GST_API_EXPORT LockState
{
	enum LockType
	{
		FREE = 2,
		OBJECT = 4,
		PART = 8,
		UNKNOWN = 16
	};
	LockType state;

	LockState(const LockType &state) : state(state)
	{
	}
};
typedef boost::shared_ptr<LockState> LockStatePtr;

struct GST_API_EXPORT IndexState
{
	enum IndexStateType
	{
		IndexInvalid = -1,
		IndexUnavailable = 0,
		IndexAvailable = 1
	};
	IndexStateType state;

	IndexState(const IndexStateType &state) : state(state)
	{
	}
};
typedef boost::shared_ptr<IndexState> IndexStatePtr;

struct GST_API_EXPORT AccessLevel
{
	friend class boost::serialization::access;

	enum AccessLevelVal
	{
		Public = 0,
		Partner,
		Private,
		None = 999
	};
	AccessLevelVal level;
	std::string desc;

	AccessLevel(const long &lvl)
	{
		switch(lvl)
		{
		case 0:
			this->desc = "Public";
			break;
		case 1:
			this->desc = "Partner";
			break;
		case 2:
			this->desc = "Private";
			break;
		case 999:
			this->desc = "None";
			break;
		default:
			throw GST::exceptions::BadParameter(
				__METHOD_NAME__, "Unknown Access Level", "lvl");
		}
		this->level = (AccessLevelVal)lvl;
	}

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("desc", desc);
		ar &boost::serialization::make_nvp("level", level);
	}
};

typedef boost::shared_ptr<AccessLevel> AccessLevelPtr;
typedef std::vector<AccessLevelPtr> AccessLevelList;
typedef boost::shared_ptr<AccessLevelList> AccessLevelListPtr;

enum class GeometryHullState
{
	Unknown,
	Set,
	NotSet
};

enum class TextureState
{
	Unknown,
	Set,
	NotSet
};

struct GST_API_EXPORT FeatureDesc
{
	std::string name;
	int levelsAvaiable;
	long geometryId;
	FeatureClassDesc fclass;
	///@name optional information
	//@{
	LockStatePtr lockstate;
	GSTbox bbox;
	IndexStatePtr indexstate;
	GeometryHullState hullstate;
	TextureState texturestate;
	//@}

	FeatureDesc()
	{
	}
	FeatureDesc(const std::string &name,
				const int &levelsAvaiable,
				const long &geometryId,
				const FeatureClassDesc &fclass,
				const GSTbox &bbox);

	///@name operators
	//@{
	bool operator==(const FeatureDesc &other) const;
	bool operator!=(const FeatureDesc &other) const;
	//@}

	// typedef boost::shared_ptr<ICondition> ConditionPtr;
	// std::vector<ConditionPtr> conditions;
};
typedef boost::shared_ptr<FeatureDesc> FeatureDescPtr;
typedef boost::ptr_vector<FeatureDesc> FeatureDescList;
typedef boost::shared_ptr<FeatureDescList> FeatureDescListPtr;

/**
 * Wrapper for the resulting subfeature data (get requests).
 */
struct GST_API_EXPORT CrudeSubfeature
{
	std::string geometry;
	std::string propertyDesc;
	std::string propertyVals;
	TableAttributeValListPtr attributes;
	std::string subfeatureKind;
	Geometry::RequestFormats geometryformat = Geometry::SFSP;
	boost::optional<Parsers::ImageData> imageData;

	Geometry::RequestFormats GetGeometryformat() const
	{
		return geometryformat;
	}
	const std::string &GetGeometry() const
	{
		return geometry;
	}
	const std::string &GetPropertyDesc() const
	{
		return propertyDesc;
	}
	const std::string &GetPropertyVals() const
	{
		return propertyVals;
	}
	TableAttributeValListPtr GetObjProperties() const
	{
		return attributes;
	}
	const std::string &GetSubfeatureKind() const
	{
		return subfeatureKind;
	}
	const boost::optional<Parsers::ImageData> &GetImageData() const
	{
		return imageData;
	}
};

/**
 * Wrapper for the resulting data (get requests).
 */
struct GST_API_EXPORT CrudeFeature
{
	FeatureDescPtr desc;
	Geometry::SRSPtr srs;
	std::string geometry;
	std::string propertyDesc;
	std::string propertyVals;
	std::string lockid;
	TableAttributeValListPtr attributes;
	std::vector<CrudeSubfeature> subfeatures;
	Geometry::RequestFormats geometryformat = Geometry::SFSP;
	[[deprecated("Always empty. Will be removed in a future update.")]]
	boost::shared_array<unsigned char> binGeo;
	[[deprecated("Always empty. Will be removed in a future update.")]]
	Transport::GeometryData metaData
		= Transport::GeometryData{};

	Geometry::RequestFormats GetGeometryformat() const
	{
		return geometryformat;
	}
	const std::string &GetGeometry() const
	{
		return geometry;
	}
	const std::string &GetPropertyDesc() const
	{
		return propertyDesc;
	}
	const std::string &GetPropertyVals() const
	{
		return propertyVals;
	}
	const std::string &GetLockId() const
	{
		return lockid;
	}
	TableAttributeValListPtr GetObjProperties() const
	{
		return attributes;
	}
	const std::vector<CrudeSubfeature> GetSubfeatures() const
	{
		return subfeatures;
	}
	[[deprecated(
		"Result is always empty. Will be removed in a future update.")]]
	virtual Transport::GeometryData GetMetaData() const
	{
		return Transport::GeometryData();
	}
	[[deprecated("Unused. Will be removed in a future update.")]]
	virtual void parseMetaData(const std::string input)
	{
	}
	[[deprecated(
		"Result is always empty. Will be removed in a future update.")]]
	virtual boost::shared_array<unsigned char> GetBinaryGeometry()
	{
		return boost::shared_array<unsigned char>();
	}
};
typedef boost::shared_ptr<CrudeFeature> CrudeFeaturePtr;

struct GST_API_EXPORT QueryBox
{
	GSTCore::GSTbox box;
	double borderSize;
	Geometry::SRSPtr srs;

	QueryBox(const GSTCore::GSTbox &box,
			 const double &borderSize,
			 Geometry::SRSPtr srs)
		: box(box)
		, borderSize(borderSize)
		, srs(srs)
	{
	}

	std::string GetCommaSeparatedMinMaxList() const;
	std::string GetBorderSize() const;
	Geometry::SRSPtr GetSRS() const;
};
typedef boost::shared_ptr<QueryBox> QueryBoxPtr;

struct GST_API_EXPORT EndPoint
{
	HostPtr host;
	Protocol protocol;
	std::string database;

	bool operator==(const EndPoint &other) const;
	bool operator!=(const EndPoint &other) const;
};
typedef boost::shared_ptr<EndPoint> EndPointPtr;
// Creates a deep copy of ep, that doesn't share host/dbconfig ptrs of ep.
EndPoint deepCopy(const EndPoint &ep);

struct GST_API_EXPORT LockInfo
{
	std::string lockId;
	std::string user;
	std::string checkedOut;
	GST::LockType ltype;
};
typedef boost::shared_ptr<LockInfo> LockInfoPtr;
typedef std::vector<LockInfoPtr> LockInfoList;
typedef boost::shared_ptr<LockInfoList> LockInfoListPtr;

struct GST_API_EXPORT SurfacePoint
{
	double x;
	double y;
	bool valid;

	SurfacePoint();
	SurfacePoint(const double &px, const double &py);

	SurfacePoint &operator=(const SurfacePoint &other);
};

struct GST_API_EXPORT SurfaceLine
{
	SurfacePoint p1;
	SurfacePoint p2;

	SurfaceLine();
	SurfaceLine(const SurfacePoint &p1, const SurfacePoint &p2);

	SurfaceLine &operator=(const SurfaceLine &other);
};

//-----------------------------------------------------------------------------------------------------------
/**
 * @brief	stores result of one of the intersection function
 *
 * @param	intersecionImageFileName	file name including path
 *                                     to resulting intersection image
 *
 * @param	legendImageFileName			file name including path
 *                                     to resulting legend image
 *										(optional) only if separate legend image
 *										was requested, empty otherwise
 *
 * @param	legendInfoJson				legend info in json format
 *
 * @see		NetworkInterface::SaveBoreholeImage
 * @see		NetworkInterface::SaveSectionImage
 * @see		NetworkInterface::SaveMapImage
 */
struct GST_API_EXPORT IntersectionInfo
{
	std::string intersecionImageFileName;
	std::string legendImageFileName;
	std::string legendInfoJson;
};
typedef boost::shared_ptr<IntersectionInfo> IntersectionInfoPtr;

struct GST_API_EXPORT PropertyAlias
{
	friend class boost::serialization::access;

public:
	std::string aliasName;
	AccessLevel accessLevel;
	bool isConstrained;

	PropertyAlias(const std::string &aliasName,
				  AccessLevel accessLevel,
				  const bool &isConstrained)
		: aliasName(aliasName)
		, accessLevel(accessLevel)
		, isConstrained(isConstrained)
	{
	}

	/// default constructor for boost serialization support
	PropertyAlias()
		: aliasName("undefined")
		, accessLevel(AccessLevel::Public)
		, isConstrained(false)
	{
	}

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("aliasName", aliasName);
		ar &boost::serialization::make_nvp("accessLevel", accessLevel);
		ar &boost::serialization::make_nvp("isConstrained", isConstrained);
	}
};
typedef boost::shared_ptr<PropertyAlias> PropertyAliasPtr;
// key: property name; value: alias
typedef std::
	map<std::string, std::map<int, PropertyAliasPtr>, Utils::UpperCaseCompare>
		PropertyAliasMap;
typedef boost::shared_ptr<PropertyAliasMap> PropertyAliasMapPtr;
typedef std::map<std::string, PropertyAliasMapPtr>
	PropertyAliasMapBySubFeatureKind;

struct GST_API_EXPORT WebUserDesc
{
	long id;
	std::string login;
	std::string linkedGstUser;
	std::string allowedActionsJson;
	long accessLevel;
	WebUserDesc(long id,
				const std::string &login,
				const std::string &linkedGstUser,
				const std::string &allowedActionsJson,
				long accessLevel)
		: id(id)
		, login(login)
		, linkedGstUser(linkedGstUser)
		, allowedActionsJson(allowedActionsJson)
		, accessLevel(accessLevel)
	{
	}
};
typedef std::vector<WebUserDesc> WebuserDescList;
typedef boost::shared_ptr<WebuserDescList> WebuserDescListPtr;

struct GST_API_EXPORT FeatureData
{
	FeatureDescPtr featureDesc;
	LockInfoListPtr lockInfos;
	TableAttributeValListPtr objectPropertyValues;
	bool hasGeometryHull;
};
typedef std::vector<FeatureData> FeatureDataList;

// Stores information about an object property value version
//
// Any time an object property value changes, one version is created. The
// initial value creation and any update to the value create a version.
struct GST_API_EXPORT VersionedObjectPropertyValue
{
	// The id of the object property value version.
	int64_t id;
	// The id of the corresponding feature.
	int64_t featureId;
	// The id of the corresponding object property.
	int64_t objectPropertyId;
	// The id of the user creating this version.
	int32_t userId;
	// The timestamp of this version.
	//
	// Encoded as a string in [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt)
	// format.
	// "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
	std::string timestamp;
	// The value set in this version.
	//
	// Note: The description will only have the correct type, isNull and id
	// information, name and tableName will be empty.
	TableAttributeValPtr value;
};
typedef std::vector<VersionedObjectPropertyValue>
	VersionedObjectPropertyValueList;

struct GST_API_EXPORT Point3
{
	double x = 0.;
	double y = 0.;
	double z = 0.;
	Point3(double x, double y, double z);
};

struct GST_API_EXPORT ServerLicense
{
	std::string name;
	bool valid;
	std::string error;
};
typedef std::vector<ServerLicense> ServerLicenseList;
typedef boost::shared_ptr<ServerLicenseList> ServerLicenseListPtr;

struct GST_API_EXPORT ColumnDescription
{
	std::string name;
	DataType type;
	bool notNull;
};

// Additional info for the interpretation of constrained columns
enum class ConstrainedInterpretation
{
	// column value itself without any interpretation
	Default = 0,
	// column describes a colors red value
	ColorR = 1,
	// column describes a colors green value
	ColorG = 2,
	// column describes a colors blue value
	ColorB = 3,
	// column describes an colors alpha value
	ColorA = 4,
	// column contains a hex value representing a color
	ColorHex = 5,
	// Unknown info from a future gst version
	Unknown = 6,
};

// Describes a component column of a constrained
struct GST_API_EXPORT ConstrainedColumnDescription
{
	std::string name;
	DataType type;
	bool notNull;
	ConstrainedInterpretation interpretation;

	ConstrainedColumnDescription(const ColumnDescription &columnDescription);
	ConstrainedColumnDescription(const ColumnDescription &columnDescription,
								 ConstrainedInterpretation interpretation);
	ConstrainedColumnDescription(const std::string &name,
								 DataType type,
								 bool notNull,
								 ConstrainedInterpretation interpretation);
};

// Identifies an external table (not managed by GST)
struct GST_API_EXPORT ExternalTableIdentifier
{
	int32_t databaseId;
	std::string schemaName;
	std::string tableName;

	// "databaseId.schemaName.tableName"
	std::string fullTableName() const;
	static ExternalTableIdentifier fromFullTableName(
		const std::string &fullTableName);
};

// Describes a table available as constrained table
struct GST_API_EXPORT TableDescription
{
	ExternalTableIdentifier identifier;
	ColumnDescription keyColumn;
};
typedef std::vector<TableDescription> TableDescriptionList;
typedef boost::shared_ptr<TableDescriptionList> TableDescriptionListPtr;

enum class SortOrder
{
	Ascending,
	Descending,
};

struct GST_API_EXPORT FeatureMoMaParentLabel
{
	int64_t featureId;
	std::string momaLabel;
};

enum class AutoSortCriteriaKind
{
	AttributeName,
	DynamicColorScale,
};

class GST_API_EXPORT AutoSortCriteria
{
public:
	AutoSortCriteria(std::string attributeName, SortOrder order);
	AutoSortCriteria(long dynamicColorScaleId, SortOrder order);
	AutoSortCriteriaKind kind() const;
	const std::string &attributeName() const;
	long dynamicColorScaleId() const;
	SortOrder sortOrder() const;

private:
	std::string m_attributeName;
	long m_dynamicColorScaleId;
	AutoSortCriteriaKind m_kind;
	SortOrder m_sortOrder;
};

enum class AccessRight
{
	Deny,
	Read,
	ReadWrite,
	Admin,
};

enum class LicenseKind
{
	Desktop,
	Python,
	Web,
};

} // namespace ClientUtils
} // namespace GST

BOOST_CLASS_EXPORT_KEY(GST::ClientUtils::PropertyAlias);
BOOST_CLASS_VERSION(GST::ClientUtils::PropertyAlias, 3)

BOOST_CLASS_EXPORT_KEY(GST::ClientUtils::AccessLevel);
BOOST_CLASS_VERSION(GST::ClientUtils::AccessLevel, 2)

BOOST_CLASS_EXPORT_KEY(GST::ClientUtils::SubfeatureKind);
BOOST_CLASS_VERSION(GST::ClientUtils::SubfeatureKind, 2)

#endif // _NetworkInterfaceStructs_h_
