#ifndef __TRIANGLEMESH__FOR_MT__
#define __TRIANGLEMESH__FOR_MT__

#include <vector>
#include <i3d/image3d.h>
#include "params.h"

struct mesh_t {
	std::vector<Vector3FC> Pos;        //list of mesh vertices
	std::vector<int> color; //DEBUG TODO REMOVE

	std::vector<long unsigned int> ID; //list of triangles organized in tripplets of indices into the Pos array of vertices;
                                      //the array length should be 3x the number of triangles in the mesh
	std::vector<Vector3F> norm;        //list of vectors that are normal/orthogonal to the planes given by the individual triangles

	///metadata to keep the skeleton information
	std::vector<Vector3FC> fPoints;         //skel. vertex coordinates
	std::vector<unsigned int> segFromPoint; //indices of starting points of all segments
	std::vector<unsigned int> segToPoint;   //...of ending points
	std::vector<float> segFromRadius;       //radii at starting points for all segments

	int parent;                        //index of the "parent" filopodium-branch,
	                                   //-1 if the parent is the cell body itself
};

/**
 * This is simple, minimalistically compatible (somewhat at the syntax level (*))
 * class alternative to the main MotionTracking class ActiveMesh.
 *
 * (*) It uses standard container (std::vector) instead of those of MotionTracking (MArray).
 * Data from both containers, however, can be accessed in a syntactically the same fashion,
 * i.e., with pointers and []. Modifying lengths of the containers differ.
 *
 * (*) Also the Vector3F is different from the MotionTracking one, yet they are similar.
 *
 * It is meant for rapid trying/debugging of basic "mesh-processing" mesh-not-modifying algorithms.
 */
class ActiveMesh
{
  public:
	///(only!) cell body mesh stuff
	std::vector<Vector3FC> Pos;        //list of mesh vertices
	std::vector<long unsigned int> ID; //list of triangles organized in tripplets of indices into the Pos array of vertices;
                                      //the array length should be 3x the number of triangles in the mesh
	std::vector<Vector3F> norm;        //list of vectors that are normal/orthogonal to the planes given by the individual triangles

	std::vector<Vector3FC> oldVolPos;  //list of volumetric mesh vertices, previous situation
	std::vector<Vector3FC> newVolPos;  //list of volumetric mesh vertices, new situation
	std::vector<long unsigned int> VolID; //list of tetrahedra (topology definition), this one is filled only with this->ImportVTK_Volumetric()

	///this one only manages data required for the ConstructFF_T() function
	void RotateVolPos(void)
	{
		oldVolPos=newVolPos;
		newVolPos=Pos;
	}

	///filopodia mesh stuff
	std::vector<struct mesh_t> Ftree;

	///use this one before loading a new set of filopodia
	void DiscardAllFilopodiaObjects(void)
	{ Ftree.clear(); }

	///use this one after loading a new set of filopodia
	void DiscardLastEmptyFilopodiumObject(void)
	{ if (Ftree.size() > 0 && Ftree.back().fPoints.size() == 0)
		Ftree.pop_back(); }

	///returns the number of filopodia whose geometry data is stored
	size_t GetFilopodiaNumber(void)
	{ return(Ftree.size()); }

	///constructs FlowFields using the \e this::oldVolPos and \e this::newVolPos
	void ConstructFF_T(FlowField<float> &FF); //based on interpolation of tetrahedra
	size_t GetVolIDsize(void)
	{ return (VolID.size()); }

	///input is filename
	///returns 0 on success, otherwise non-zero
	int ImportSTL(const char* filename);
	int ExportSTL(const char* filename);
	int ImportVTK(const char* filename);
	int ImportVTK_Volumetric(const char* filename,bool saveAlsoTetrahedra=false);

	/**
	 * Import filopodium from file, and save it at specific index (replacing what was there);
	 * if the index is 999999, just append (to the ActiveMesh::Ftree array).
	 * 
	 * This one saves the skeleton information (fPoints,segFrom/ToPoint,segFromRadius attributes)
	 * and calls PopulateSurfTriangles_Ftree() to obtain a mesh.
	 */
	int ImportVTK_Ftree(const char* filename,unsigned int idx,const float stretch=1.f,bool resetMesh=true);

	/**
	 * Blows up the skeleton to a surface mesh (Pos,ID,norm attributes).
	 *
	 * If \e enforce is false, use current skeleton starting vertex (default).
	 * If \e enforce is true, use original skeleton starting vertex.
	 * The original vertex is saved right before the current vertex in the list
	 * of vertices (the fPoints array).
	 */
	void PopulateSurfTriangles_Ftree(const unsigned int idx,const bool enforce=false);

	///renders filopodium first aside, then overlays the given mask
	void RenderMask_filo(i3d::Image3d<i3d::GRAY16>& mask,const unsigned int idx,const bool showTriangles=false);
	/// render directly into mask using volumetric mesh
	void RenderMask_bodyVol(i3d::Image3d<i3d::GRAY16>& mask,const bool showTriangles=false);

	///one-shot texture renderer meant for testing
	void RenderOneTimeTexture(const i3d::Image3d<i3d::GRAY16>& mask,
	                          i3d::Image3d<i3d::GRAY16>& texture);

	///time-lapse (coherent) manipulation with fluorescent dots,
	///always with the given mask
	void InitDots_body(const i3d::Image3d<i3d::GRAY16>& mask);
	void InitDots_filo(const i3d::Image3d<i3d::GRAY16>& mask,const unsigned int idx);

	///displace randomly the dots positions a little
	///but not further away than half pixel
	void BrownDots(const i3d::Image3d<i3d::GRAY16>& mask);

	///displace dots positions according to the FlowField
	void FFDots(const i3d::Image3d<i3d::GRAY16>& mask,
	            const FlowField<float> &FF);

	///project dots into the output \e texture image
	///the \e mask is here only to initate the metadata of
	///the \e texture image
	void RenderDots(const i3d::Image3d<i3d::GRAY16>& mask,
	                i3d::Image3d<i3d::GRAY16>& texture);

	void PhaseII(const i3d::Image3d<i3d::GRAY16>& texture,
	             i3d::Image3d<float>& blurred_texture);
	void PhaseIII(i3d::Image3d<float>& blurred,
	              i3d::Image3d<i3d::GRAY16>& texture);

	///stores simulated fl. dots of the cell body
	std::vector<Vector3F> dots;
	///stores simulated fl. dots of the cell filopodia (of all of them)
	std::vector<Vector3F> dots_filo;

	///indiciator function to tell if we have some dots stored
	///from a previous similation run
	bool DotsFirstRun(void)
	{ return (dots.size() == 0); }

	///mesh rigid-manipulation functions to convert it from
	///Dima's world into real microns-floating-point coordinates
	///such that the cell appears approx. in the middle of the output images
	void ScaleMesh(const Vector3F& scale);
	void TranslateMesh(const Vector3F& shift);

	/**
	 * sets the optimal size and translation vectors (defined below),
	 * it does not alter the mesh
	 *
	 * to determine scene size, we assume that
	 * the filopodia length will be max diameter of the cell body,
	 * and multiply with certain "safe" constant (=1.0);
	 * all of it integrated into one constant:
	 */
	void CenterMesh(const float safeConstant=3.f);
	///optimal output image size in microns
	Vector3F meshPlaygroundSize;
	///default mesh translation to appear approx. in the output image centre
	Vector3F meshShift;

	//the following functions are all defined in graphics.cpp
	void displayMesh(void);

	//these are not used in this project, related only to the OpenGL vizualization
	void displayMeshEdges(void);
};

#endif
