/*---------------------------------------------------------------
	FILE: CObservationGPS.h
	USE: See doc above

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

#include <MRPT/UTILS/CSerializable.h>
#include <MRPT/MRML/CObservation.h>
#include <MRPT/MRML/CPose3D.h>
#include <MRPT/MRML/CPose2D.h>

namespace MRML
{

	/** Declares a class derived from "CObservation" that represents a Global Positioning System (GPS) reading.
	 *
	 * \sa CObservation
	 */
	class CObservationGPS : public CObservation
	{
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE( CObservationGPS )

	 public:
		/** Constructor.
		 */
		CObservationGPS(  );

		/** Dumps the contents of the observation in a human-readable form to a given output stream
		  */
		void  dumpToStream( CStream &out );

		/** Dumps the contents of the observation in a human-readable form to the console
		  */
		void  dumpToConsole( );

		/** Coordinates transformation from longitude/latitude/height to X/Y/Z coordinates
		  *  The WGS84 ellipsoid is used for the transformation. The coordinates are in 3D
		  *   where the reference is the intersection of the equator and the Greenwich Meridian.
		  *  NOTE: It will be usually more useful in robotics applications to specify the longitude/latitude and
		  *   height of a given reference point to obtain rectangular coordinates (approximately) on a flat plane
		  *   over the working area. Elsewhere, XYZ coordinates will be geocentric!
		  *  See for an explanation: http://en.wikipedia.org/wiki/Reference_ellipsoid
		  */
		static void  coordinatesTransformation_WGS84(
			double		in_longitude_degrees,
			double		in_latitude_degrees,
			double		in_height_meters,
			double		&out_x_meters,
			double		&out_y_meters,
			double		&out_z_meters,
			double		in_longitude_reference_degrees = 0,
			double		in_latitude_reference_degrees = 0,
			double		in_height_reference_meters = 0
			);

		 /** The sensor pose on the robot.
		  */
		CPose3D			sensorPose;

		/** A UTC time-stamp structure for GPS messages
		  */
		struct TUTCTime
		{
			unsigned char	hour;
			unsigned char	minute;
			double			sec;
		};

		/** The GPS datum for GGA commands
		  */
		struct TGPSDatum_GGA
		{
			/** The GPS sensor measured timestamp (in UTC time)
			*/
			TUTCTime	UTCTime;

			/** The measured latitude, in degrees (North:+ , South:-)
			*/
			double			latitude_degrees;

			/** The measured longitude, in degrees (East:+ , West:-)
			*/
			double			longitude_degrees;

			/** The values defined in the NMEA standard are the following:
			  *
			  *	0 = invalid
              *	1 = GPS fix (SPS)
			  *	2 = DGPS fix
              * 3 = PPS fix
			  * 4 = Real Time Kinematic
			  * 5 = Float RTK
			  * 6 = estimated (dead reckoning) (2.3 feature)
			  * 7 = Manual input mode
			  * 8 = Simulation mode
			  */
			unsigned char	fix_quality;

			/** The measured altitude, in meters.
			*/
			double			altitude_meters;

			/** The number of satelites used to compute this estimation.
			*/
			int				satellitesUsed;

			/** This states whether to take into account the value in the HDOP field.
			*/
			bool			thereis_HDOP;

			/** The HDOP (Horizontal Dilution of Precision) as returned by the sensor.
			*/
			float			HDOP;
		};

		/** The GPS datum for RMC commands
		  */
		struct TGPSDatum_RMC
		{
			/** The GPS sensor measured timestamp (in UTC time)
			*/
			TUTCTime	UTCTime;

			/** This will be: 'A'=OK or 'V'=void
			 */
			char		validity_char;

			/** The measured latitude, in degrees (North:+ , South:-)
			  */
			double		latitude_degrees;

			/** The measured longitude, in degrees (East:+ , West:-)
			  */
			double		longitude_degrees;

			/** The measured speed (in knots)
			  */
			double		speed_knots;

			/** The measured speed direction (in degrees)
			  */
			double		direction_degrees;
		};

		/** Will be true if the corresponding field contains data read from the sensor, or false if it is not available.
		  * \sa GGA_datum
		  */
		bool				has_GGA_datum;

		/** Will be true if the corresponding field contains data read from the sensor, or false if it is not available.
		  * \sa RMC_datum
		  */
		bool				has_RMC_datum;

		/** If "has_GGA_datum" is true, this contains the read GGA datum.
		  */
		TGPSDatum_GGA		GGA_datum;

		/** If "has_RMC_datum" is true, this contains the read GGA datum.
		  */
		TGPSDatum_RMC		RMC_datum;

		 /** Implements the virtual method in charge of finding the likelihood between this
		  *   and another observation, probably only of the same derived class. The operator
		  *   may be asymmetric.
		  *
		  * \param anotherObs The other observation to compute likelihood with.
		  * \param anotherObsPose If known, the belief about the robot pose when the other observation was taken can be supplied here, or NULL if it is unknown.
		  *
		  * \return Returns a likelihood measurement, in the range [0,1].
		  *	\exception std::exception On any error, as another observation being of an invalid class.
		  */
		 float  likelihoodWith( CObservation *anotherObs, CPosePDF *anotherObsPose = NULL );


	}; // End of class def.

} // End of namespace

#endif
