/*************************************************************************
*  Copyright (C) 2013 by Burak ER                                 	 *
*									 *
*                                                                        *
*  This program is free software; it is licensed under the terms of the  *
*  GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/

#pragma once

#include <lib/base/Logging.hpp>
#include <lib/base/Math.hpp>
#include <core/Body.hpp>
#include <core/PartialEngine.hpp>
#include <core/Shape.hpp>

//#include <yade/trunk/pkg/fem/Node.hpp> //Node shape

/* Before starting the implementation of the deformable element, I am really dissappointed that deformableelement's algorithm relies on its shape.
Shape means "shape" and I think it should not contain any other physical meaning or anything else.

With respect to this view; The deformable element class is derived from the body and knows the information of 
its members that are node shaped bodies.

*/

namespace yade { // Cannot have #include directive inside.


class NewtonIntegrator;
class InternalForceFunctor;

class DeformableElement : public Shape {
public:
	typedef std::map<shared_ptr<Body>, Se3r> NodeMap;   //Node id's with initial positions first node is selected as the reference node
	typedef std::vector<Vector3r>            Triangles; // Used for drawing the element

	unsigned int maxNodeCount;   //Maximum number of nodes of this element
	Se3r         referenceCoord; //Reference node position in global coordinates

	virtual ~DeformableElement();
	void             addNode(const shared_ptr<Body>& subBody);
	shared_ptr<Body> getNode(int id) const;

	void                  delNode(const shared_ptr<Body>& subBody);
	std::vector<Vector3r> getDisplacements(void) const;

	void addFace(Vector3r&);
	void removeLastFace(void);
	//! Recalculate physical properties of DeformableElement.
	//virtual void getMassMatrix()=0 const;

	Se3r frame_get() const
	{
		const shared_ptr<Body>& member = localmap.begin()->first;
		return member->state->se3;
	}

	void frame_set(Se3r) const { return; }

	boost::python::dict localmap_get();

	virtual Real getVolume() const { return -1; }
	// clang-format off
		YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(DeformableElement,Shape,"Deformable aggregate of nodes",
		((NodeMap,localmap,,,"Ids and relative positions+orientations of members of the deformable element (should not be accessed directly)"))
		((Se3r,elementframe,,,"Position and orientation of the element frame"))
		((Triangles,faces,,,"Faces of the element for drawing"))
		,
		,
		createIndex(); /*ctor*/
		//init();
		,
		/*py*/
		.add_property("elementframe",&DeformableElement::frame_get)
		.def("addNode",&DeformableElement::addNode,"Add a node shared_pt<:yref:'Body'>& as into the element")
		.def("getNode",&DeformableElement::getNode,"Get a node shared_pt<:yref:'Body'>& as into the element")
		.def("delNode",&DeformableElement::delNode,"Remove a node shared_pt<:yref:'Body'>& from the element")
		.def("addFace",&DeformableElement::addFace,"Add a face into the element")
		.def("removeLastFace",&DeformableElement::removeLastFace,"Remove a face from the element")
		.def("getVolume",&DeformableElement::getVolume,"Get volume of the element")

	);
	// clang-format on
	REGISTER_CLASS_INDEX(DeformableElement, Shape);
	DECLARE_LOGGER;
};

REGISTER_SERIALIZABLE(DeformableElement);

} // namespace yade
