//==============================================================================
/*! \file
 * OpenMesh Toolkit for mesh analysis    \n
 * Copyright (c) 2010 by Rostislav Hulik     \n
 *
 * Author:  Rostislav Hulik, rosta.hulik@gmail.com  \n
 * Date:    2010/10/20                          \n
 *
 * Copyright (C) Brno University of Technology
 *
 * This file is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Description:
 * - Class specifiing used unified datatypes
 */

#ifndef _OM_TYPES_H_
#define _OM_TYPES_H_

#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <MDSTk\Math\mdsMatrix.h>
#include <OMToolkit\OMSerializableMatrix.h>
#include <OMToolkit\OMSerializableVector.h>
#include <Eigen/QR>
#include <Eigen/Geometry>


namespace OMToolkit
{
	namespace Types
	{
		struct Traits : public OpenMesh::DefaultTraits
		{
			//typedef OpenMesh::Vec3d Point; // use double-values points
			//typedef OpenMesh::Vec3d Normal; // use double-values points
		};

		/**
		 * Default mesh type mased on TriMesh with Array kernel (OpenMesh)
		 */
		typedef OpenMesh::TriMesh_ArrayKernelT<Traits> DefaultMesh;

		/**
		 * Type of mesh used in modules - necessary for maintain compatibility
		 * For each property is necessary to define following:
		 *		PropHandleT<T> property handle
		 *		Accessing methods are advised
		 *		In constructor, add property and set it to be persistent
		 * @tparam AttributeScalar Is scalar type used for all added attributes (matrices, vectors, curvature etc)
		 */
		template <typename AScalar>
		class ModuleMesh : public DefaultMesh
		{
			public:
				typedef AScalar AttributeScalar;
				typedef OMSerializableMatrix<AttributeScalar> VertexMatrix;
				typedef OMSerializableVector<AttributeScalar> VertexAttributeVector;	
				
				/**
				 * In constructor, we must add new property with unique name and set it to be persistent
				 */
				ModuleMesh() : DefaultMesh()
				{
					add_property(m_curvature, "<vertexCurvature>");
					property(m_curvature).set_persistent(true);

					add_property(m_curvature_mag, "<vCurvatureMag>");
					property(m_curvature_mag).set_persistent(true);

					add_property(m_vertexAttributes, "<vertexAttributes>");
					property(m_vertexAttributes).set_persistent(true);

					request_vertex_colors();
					
					add_property(m_matrix, "<vertexMatrix>");
					property(m_matrix).set_persistent(true);

					add_property(m_flag, "<vertexFlag>");
					property(m_flag).set_persistent(true);
				}

				/**
				 * Access method for curvature direction
				 * @param vertex handle
				 * @return Curvature direction
				 */
				Normal &curvature(VertexHandle vertex) { return property(m_curvature, vertex); }
				
				/**
				 * Access method for curvature magnitude
				 * @param vertex handle
				 * @return Curvature magnitude
				 */
				AttributeScalar &curvatureMagnitude(VertexHandle vertex) { return property(m_curvature_mag, vertex);}

				/**
				 * Method returns a handle to curvature magnitude property
				 * @return Desired handle
				 */
				OpenMesh::VPropHandleT<AttributeScalar> getCurvatureMagHandle() { return m_curvature_mag; }

				/**
				 * Method returns a handle to curvature vector property
				 * @return Desired handle
				 */
				OpenMesh::VPropHandleT<Normal> getCurvatureHandle() { return m_curvature; }

				/**
				 * Method returns a Vertex matrix
				 * @return Desired matrix
				 */
				VertexMatrix &getMatrix(VertexHandle vertex) { return property(m_matrix, vertex);}

				/**
				 * Method returns a Vertex attributes vector
				 * @return Desired vector
				 */
				VertexAttributeVector &getAttributes(VertexHandle vertex) { return property(m_vertexAttributes, vertex);}

				/**
				 * Method returns a handle to Vertex matrix
				 * @return Desired handle
				 */
				OpenMesh::VPropHandleT<VertexMatrix> getMatrixHandle() {return m_matrix;}

				/**
				 * 
				 */
				OpenMesh::VPropHandleT<int> m_flag;

				/**
				 * 
				 */
				OpenMesh::VPropHandleT<int> getFlagHandle() {return m_flag;}

				/**
				 * Method returns a handle to Vertex attribute vector
				 * @return Desired handle
				 */
				OpenMesh::VPropHandleT<VertexAttributeVector> getVertexAttributeHandle() {return m_vertexAttributes;}

			private:

				/**
				 * Handle to a measured curvature normal vector
				 */
				OpenMesh::VPropHandleT<Normal> m_curvature;

				/**
				 * Handle to a measured curvature magnitude
				 */
				OpenMesh::VPropHandleT<AttributeScalar> m_curvature_mag;

				/**
				 * Handle to a matrix attached to a vertex
				 */
				OpenMesh::VPropHandleT<VertexMatrix> m_matrix;
				
				/**
				 * Handle to a vector attached to a vertex
				 */
				OpenMesh::VPropHandleT<VertexAttributeVector> m_vertexAttributes;
		};


		typedef ModuleMesh<float> ModuleMeshd;
	} // namespace Types
} // namespace OMToolkit

#endif