/*---------------------------------------------------------------
	FILE: CPose3DPDFParticles.h

   Part of the MRPT Library
   ISA - Universidad de Malaga - http://www.isa.uma.es
  ---------------------------------------------------------------*/
#ifndef CPose3DPDFParticles_H
#define CPose3DPDFParticles_H

#include <MRPT/MRML/CPose3DPDF.h>
#include <MRPT/MRML/CMultiMetricMap.h>
#include <MRPT/UTILS/CProbabilityParticle.h>
#include <MRPT/UTILS/CParticleFilterCapable.h>
#include <MRPT/UTILS/CParticleFilterData.h>

namespace MRML
{
	class COccupancyGridMap2D;
	class CSensorialFrame;

	/** \typedef CProbabilityParticle<CPose3D> CPose3DParticle
	 *  A type definition for m_particles containing a 3D pose.
	 */
	typedef CProbabilityParticle<CPose3D> CPose3DParticle;


	/** Declares a class that represents a Probability Density function (PDF) of a 3D pose
	 *   This class implements that PDF using a set of m_particles
	 *    (for using particle filter methods), where M weighted
	 *    m_particles represent the PDF.
     *
	 * \sa CPose3D, CPose3DPDF, CPoseGaussianPDF
	 */
	class CPose3DPDFParticles : public CPose3DPDF, public CParticleFilterData<CPose3D>
	{
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE( CPose3DPDFParticles )

		// This uses CParticleFilterData to implement some methods required for CParticleFilterCapable:
		IMPLEMENT_PARTICLE_FILTER_CAPABLE(CPose3D)

	 public:
		/** Constructor
		  * \param M The number of m_particles.
		  */
		CPose3DPDFParticles( size_t M = 1 );

		/** Copy constructor:
		  */
		CPose3DPDFParticles( const CPose3DPDFParticles& obj ) :
            CPose3DPDF(),
            CParticleFilterData<CPose3D>()
		{
			copyFrom( obj );
		}

		/** Destructor
		 */
		virtual ~CPose3DPDFParticles();


		/** Copy operator, translating if necesary (for example, between m_particles and gaussian representations)
		  */
		void  copyFrom(const CPose3DPDF &o);

		/** Reset the PDF to a single point: All m_particles will be set exactly to the supplied pose.
		  * \param location The location to set all the m_particles.
		  * \param particlesCount If this is set to -1 the number of m_particles remains unchanged.
		  *  \sa resetUniform, resetUniformFreeSpace
		  */
		void  resetDeterministic( CPose3D &location,
											int	particlesCount = -1);

		 /** Returns an estimate of the pose, (the mean, or mathematical expectation of the PDF), computed
		  *   as a weighted average over all m_particles.
		  */
		CPose3D  getEstimatedPose() const;

		/** Returns an estimate of the pose covariance matrix (6x6 cov.matrix)
		  */
		CMatrix  getEstimatedCovariance() const;

		/** Returns the pose of the i'th particle.
		  */
		CPose3D	 getParticlePose(int i) const;

		/** Save PDF's m_particles to a text file. In each line it will go: "x y z"
		 */
		void  saveToTextFile(char *file) const;

		/** Get the m_particles count (equivalent to "particlesCount")
		 */
		size_t  size() const { return m_particles.size(); }

		/** This can be used to convert a PDF from local coordinates to global, providing the point (newReferenceBase) from which
		  *   "to project" the current pdf. Result PDF substituted the currently stored one in the object.
		  */
		void  changeCoordinatesReference( const CPose3D &newReferenceBase );

		/** Draws a single sample from the distribution (WARNING: weights are assumed to be normalized!)
		  */
		void  drawSingleSample( CPose3D &outPart ) const;

		/** Draws a number of samples from the distribution, and saves as a list of 1x6 vectors, where each row contains a (x,y,phi) datum.
		  */
		void  drawManySamples( size_t N, std::vector<vector_float> & outSamples ) const;

		/** Appends (pose-composition) a given pose "p" to each particle
		  */
		void  operator += ( CPose3D Ap);

		/** Appends (add to the list) a set of m_particles to the existing ones, and then normalize weights.
		  */
		void append( CPose3DPDFParticles &o );

		/** Returns a new PDF such as: NEW_PDF = (0,0,0) - THIS_PDF
		  */
		void inverse(CPose3DPDF &o) const;

		/** Returns the particle with the highest weight.
		  */
		CPose3D	 getMostLikelyParticle() const;

		/** Bayesian fusion.
		  */
		void  bayesianFusion( CPose3DPDF &p1, CPose3DPDF &p2 );

	}; // End of class def.

} // End of namespace

#endif
