/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmSDKAPI.h"
#include "glmSmartPointer.h"
#include "glmVector3.h"
#include "glmAngle.h"
#include "glmPODArray.h"
#include "glmRTTI.h"

namespace glm
{
	/**
	* \brief The Formation class contains slots
	*
	* \ingroup simulation
	* \author Golaem <dev@golaem.com>
	*/
	class GLM_SDK_API Formation: public ReferenceCounter
	{
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		/**
		* \brief Smartpointer on a formation.
		*/
		typedef SmartPointer<Formation> SP;

		/**
		* \brief Slot
		*/
		class Slot
		{
		public:
			Vector3 position;
			Quaternion orientation;
		};

		/**
		* \name Construction / Destruction
		*/
		//@{
		/**
		* \brief default constructor.
		*/
		Formation();

		/**
		* \brief Constructor from several slots.
		*/
		Formation(const glm::Array<Slot>& slots, Angle deltaAngleToX = Angle(0) );

		/**
		* \brief Copy constructor.
		*/
		Formation(const Formation& formation);

		/**
		* \brief Destructor
		*/
		~Formation();

		/**
		* \brief Assignment operator.
		*/
		Formation& operator=(const Formation& formation);
		//@}

		/**
		* \name Accessors
		*/
		//@{
		unsigned int countSlots() const;

		const Slot& getSlot(unsigned int index) const;

		void setSlot(unsigned int index, const Slot& slot);

		const glm::Array<Slot>& getSlots() const;

		void setSlots(const glm::Array<Slot>& slots, Angle deltaAngleToX);
		void setSlots(const glm::Array<Slot>& slots); // required by serialization
		//@}
		
		bool		_isStatic;

	private:

		/**
		* \brief Recompute the slots position, centering them at their COM.
		*/
		void recomputeSlotPositions();

		/**
		* \brief slots can be given as absolute values + angle to X delta, this method put them back in "orientation relative to X" referential
		*/
		void offsetSlotsBy( Angle angle );


		/**
		* \brief the formations' slots.
		*/ 
		glm::Array<Slot> _slots;
	};

	//*****************************************************************************
	// Formation inline definitions
	//*****************************************************************************

	//-------------------------------------------------------------------------
	// countSlots
	//-------------------------------------------------------------------------
	inline unsigned int Formation::countSlots() const
	{
		return static_cast<unsigned int>(_slots.size());
	}

	//-------------------------------------------------------------------------
	// getSlot
	//-------------------------------------------------------------------------
	inline const Formation::Slot& Formation::getSlot(unsigned int index) const
	{
		GLM_DEBUG_ASSERT_MSG(index < _slots.size(),"THe formation doesn't have a slot #%lu", index );
		return _slots[index];
	}

	//-------------------------------------------------------------------------
	// setSlot
	//-------------------------------------------------------------------------
	inline void Formation::setSlot(unsigned int index, const Formation::Slot& slot)
	{
		GLM_DEBUG_ASSERT_MSG(index < _slots.size(),"The formation doesn't have a slot #%lu", index );
		_slots[index] = slot;
	}

	//-------------------------------------------------------------------------
	// getSlots
	//-------------------------------------------------------------------------
	inline const glm::Array<Formation::Slot>& Formation::getSlots() const
	{
		return _slots;
	}
}

