#ifndef IGeometryActions_H
#define IGeometryActions_H

#include "GrammarRawStructs.h"
#include "IGeometryContainer.h"
#include "buildspec.h"
#include "image_data.hpp"

namespace GST
{
namespace Parsers
{

/**
	The SemanticActions (interface). This defines the interface of a class to be
   called from a grammar.
*/
class GST_API_EXPORT IGeometryActions : public IGeometryContainer
{
public:
	IGeometryActions()
	{
	}
	virtual ~IGeometryActions()
	{
	}

	/**
		Creates a Multipoint (GOCAD: VSet or Pointset):

		calling conventions:
			-# CreateMultipoint3()
				- create an object
				- next call is: newSimplex()
			-# several times: addPoint(p)

		\code
			//example
			CreateMultipoint3();
			addPoint(p);
			addPoint(p);
		\endcode
	*/
	virtual void CreateMultipoint3() = 0;

	/**
		Creates a Multiline (GOCAD: PLine or Curve):

		calling conventions:
			-# CreateMultiline3()
				- create an object
				- next call is: newSimplex()
			-# several times:
				-# addPoint(p)
					- append new point to creating linestring
				-# newSimplex()
					- this means the next call of addPoint creates a point which
	   is not connected to linestring (new part).

		\code
			//example
			CreateMultiline3();

			newSimplex();
			addPoint(p);
			addPoint(p);
			addPoint(p);

			newSimplex();
			addPoint(p);
			addPoint(p);
		\endcode
	*/
	virtual void CreateMultiline3() = 0;

	/**
		Creates a Multipolygonobject. (GOCAD: GSurf or highfield object)
		By meanings of WKT this is an object consisting of polygons
		of varying number of points.

		\code
			//example
			CreateMultiPolygon3();

			newSimplex();
			addPoint(p);
			addPoint(p);
			addPoint(p);
			addPoint(p);
			addPoint(p);

			newSimplex();
			addPoint(p);
			addPoint(p);
			addPoint(p);
			addPoint(p);
		\endcode
	*/
	virtual void CreateMultiPolygon3() = 0;

	/**
		Creates a TIN (trinangulated irregular network object)
		This oject has the same calling convention like CreateMultiPolygon3().

		@warning	It is not secured by WKT, that a TIN consists of triangles!
	   (polygons of 3 points) addPoint(p) could be calling more than 3 a times
	   after newSimplex()

		\code
			//example
			CreateTIN3();

			newSimplex(); //triangle 1
			addPoint(p);
			addPoint(p);
			addPoint(p);

			newSimplex(); //triangle 2
			addPoint(p);
			addPoint(p);
			addPoint(p);

			newSimplex(); //triangle 3
			addPoint(p);
			addPoint(p);
			addPoint(p);
			addPoint(p); //... 4th point: see warning
		\endcode
	*/
	virtual void CreateTIN3() = 0;

	/**
		Creates a TIN (trinangulated irregular network object) with much less
		callings than CreateTIN3().

		First all points are created. After this the triangle are constructed by
		the point indices -- one triangle consists of 3 indices. The indices
	   belongs to the order, the points were created (starting from zero).

		@note	In your implementation increase a counter when the points are
	   added (starting from zero). The parameter t of addTriangle will reference
				this counted index.

		\code
			//example
			CreateTriangleNet3();

			addPoint(p); //index: 0
			addPoint(p); //index: 1
			addPoint(p); //index: 2
			addPoint(p); //index: 3
			addPoint(p); //index: 4
			addPoint(p); //index: 5
			//...
			addTriangle(t); // e.g. t.v1 == 0, t.v2 == 1, t.v3 == 2
			addTriangle(t); // e.g. t.v1 == 1, t.v2 == 2, t.v3 == 3
			addTriangle(t); // e.g. t.v1 == 0, t.v2 == 1, t.v3 == 4
			addTriangle(t); // e.g. t.v1 == 2, t.v2 == 0, t.v3 == 5
			//...
		\endcode
	*/
	virtual void CreateTriangleNet3() = 0;

	/**
		Creates a TetrahedonNet. This is nearly the same like
	   CreateTriangleNet3() with the only difference that instead the call of
	   addTriangle(), the method addTetrahedron() is release. It references the
	   4 points of a tetrahedron.

		\code
			//example
			CreateTriangleNet3();

			addPoint(p); //index: 0
			addPoint(p); //index: 1
			addPoint(p); //index: 2
			addPoint(p); //index: 3
			addPoint(p); //index: 4
			addPoint(p); //index: 5
			//...
			addTetrahedron(t); // e.g. t.v1 == 0, t.v2 == 1, t.v3 == 2, t.v4 ==
	   4 addTetrahedron(t); // e.g. t.v1 == 1, t.v2 == 2, t.v3 == 5, t.v4 == 5
			//...
		\endcode
	*/
	virtual void CreateTetrahedon3() = 0;

	/**
	Creates a Grid:

	calling conventions:
	-# GridDescription
	- this description is needed to create a Grid
	- it needs the following information to be set within:
	- position of the Grid
	- orientation of the Grid (this includes the length of the Grid-axis)
	- size of the Grid (cell-count in each axis direction)
	-# CreateGrid3(grid_desc)
	- create an object
	-# potentially several times:
	-# CreateVertexProperty()
	- this is used to create the properties with their names and types
	-# several times:
	-# PropAddValue(p)
	- append property value. Must add exactly the following amount of
	properties:
	- grid_size_x * grid_size_y * grid_size_z * property_types_added

	\code
		//example
		GridDescription grid_desc;
		grid_desc.setPosition(RawPoint3(4400, 120.55, 312.73));
		grid_desc.setSize(10,10,10);
		grid_desc.setOrientation(RawPoint3(20,0,0), RawPoint3(0,13,0),
	RawPoint3(0,0,10));

		gb.CreateGrid3(grid_desc);
		gb.SetSrs(srs)
		gb.SetName(new_feature_name)
		gb.CreateVertexProperty("property1",
	SimplexProperty::PropertyType::TypeInt, 1);
		gb.CreateVertexProperty("property2",
	SimplexProperty::PropertyType::TypeText, 1);

		PropAddValue(prop_value_type1);
		PropAddValue(prop_value_type2);
		PropAddValue(prop_value_type1);
		PropAddValue(prop_value_type2);
		PropAddValue(prop_value_type1);
		PropAddValue(prop_value_type2);
		//...

		\endcode
	*/
	virtual void CreateGrid3(const GridDescription &grid_description) = 0;
	virtual void CreateSGrid3(
		const GST::Parsers::GridDescription &grid_description)
		= 0;

	/**
		Creates a collection of geometries

		\code
			//example
			CreateCollection();

			CreateMultiPolygon3();	//1st member
			newSimplex();
			addPoint(p);
			//...

			CreateMultiline3();		//2nd member
			//...
									//and so on
		\endcode
	*/
	virtual void CreateCollection() = 0;

	/**
		Creates a geological profile

		TODO: more info

		\code
			//example
			CreateGeologicalProfile();

			CreateMultiline3();	//1st member
			subfeatureKind(1); // specify sub feature kind
			addPoint(p);
			addPoint(p);
			//...

			CreateMultiline3();		//2nd member
			subfeatureKind(2); // specifiy sub feature kind
			//...
			//and so on
		\endcode
	*/
	virtual void CreateGeologicalProfile() = 0;
	/**
		This function sets the subfeature kind of the geological profile part.

		This should best be called right after one of the Create* frunctions
		like `CreateMultiline3`. Omitting this for geological profiles will
		result in an error later on.
	*/
	virtual void setSubfeatureKind(std::string subfeatureKind) = 0;

	/**
		Creates a Point to an geometry. The behavior depends on
		the object which will be build.

		Consult the Create*() functions for specific behavior!
	*/
	virtual void addPoint(const RawPoint3 &d) = 0;

	/**
		Creates a new Simplex on a geometry. The behavior depends on
		the object which will be build.

		Consult the Create*() functions for specific behavior!
	*/
	virtual void newSimplex() = 0;

	/**
		Creates a Triangle of Indices to an geometry. The behavior depends on
		the object which will be build.

		Consult the Create*() functions for specific behavior!
	*/
	virtual void addTriangle(const IdxTriangle &t) = 0;

	/**
		Creates a Tetrahedron of Indices to an geometry. The behavior depends on
		the object which will be build.

		Consult the Create*() functions for specific behavior!
	*/
	virtual void addTetrahedron(const IdxTetrahedron &t) = 0;
	/**
		Attach an image to a line geometry.

		This is currently only supported for a sub-feature of a profile.

		Attaches the image read from the binary buffer to the line.
	*/
	virtual void attachImage(const AttachedImageMetadata &imageMetadata,
							 const std::vector<uint8_t> &imageBinData)
		= 0;

	/**
		This function will be called when parsing is finished sucessfully.
	*/
	virtual void GeometryParsingFinished()
	{
	}

	virtual void newPart(bool oldStyle = true) = 0;

private:
};

/**
	Empty implementation of IGeometryActions

	Useful as a base class, if only some methods of IGeometryActions need to be
   implemented.
*/
class GST_API_EXPORT NoOpGeometryActions : public IGeometryActions
{
public:
	NoOpGeometryActions()
	{
	}
	virtual ~NoOpGeometryActions()
	{
	}
	virtual void CreateMultiline3()
	{
	}
	virtual void newSimplex()
	{
	}
	virtual void CreateMultipoint3()
	{
	}
	virtual void CreateMultiPolygon3()
	{
	}
	virtual void CreateTIN3()
	{
	}
	virtual void CreateTriangleNet3()
	{
	}
	virtual void CreateTetrahedon3()
	{
	}
	virtual void CreateGrid3(const GridDescription &grid_description)
	{
	}
	virtual void CreateSGrid3(const GridDescription &grid_description)
	{
	}
	virtual void CreateCollection()
	{
	}
	virtual void CreateGeologicalProfile()
	{
	}
	virtual void setSubfeatureKind(std::string subfeatureKind)
	{
	}
	virtual void addPoint(const RawPoint3 &d)
	{
	}
	virtual void addTriangle(const IdxTriangle &t)
	{
	}
	virtual void addTetrahedron(const IdxTetrahedron &t)
	{
	}
	virtual void newPart(bool oldStyle = true)
	{
	}
	virtual void attachImage(const AttachedImageMetadata &imageMetadata,
							 const std::vector<uint8_t> &imageBinData)
	{
	}
	virtual GeometryContainer *getGeometries()
	{
		return NULL;
	}
	virtual void clearGeometries()
	{
	}
};

} // namespace Parsers
} // namespace GST

#endif // IGeometryActions_H
