/* +---------------------------------------------------------------------------+
   |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
   |                                                                           |
   |                   http://mrpt.sourceforge.net/                            |
   |                                                                           |
   |   Copyright (C) 2005-2008  University of Malaga                           |
   |                                                                           |
   |    This software was written by the Perception and Robotics               |
   |      research group, University of Malaga (Spain).                        |
   |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
   |                                                                           |
   |  This file is part of the MRPT project.                                   |
   |                                                                           |
   |     MRPT is free software: you can redistribute it and/or modify          |
   |     it under the terms of the GNU General Public License as published by  |
   |     the Free Software Foundation, either version 3 of the License, or     |
   |     (at your option) any later version.                                   |
   |                                                                           |
   |   MRPT 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 General Public License for more details.                          |
   |                                                                           |
   |     You should have received a copy of the GNU General Public License     |
   |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
   |                                                                           |
   +---------------------------------------------------------------------------+ */
#ifndef  CSTREAM_H
#define  CSTREAM_H

#include <MRPT/UTILS/utils_defs.h>

/*---------------------------------------------------------------
	Class
  ---------------------------------------------------------------*/
namespace UTILS
{
	class	CSerializable;
	struct	TRuntimeClassId;

	/** This base class is used to provide a unified interface to
	 *    files,memory buffers,..Please see the derived classes. This class is
	 *    largely inspired by Borland VCL "TStream" class. <br><br>
	 *  Apart of the "VCL like" methods, operators ">>" and "<<" have been
	 *    defined so that simple types (int,bool,char,float,char *,std::string,...)
	 *    can be directly written and read to and from any CStream easily.
	 *  Please, it is recomendable to read CSerializable documentation also.
	 *
	 * \sa CFileStream, CMemoryStream,CSerializable
	 */
	class CStream
	{
	public:
		/** Used in CStream::Seek
		  */
		enum TSeekOrigin
		{
			sFromBeginning = 0,
			sFromCurrent = 1,
			sFromEnd = 2
		};

	protected:
		/** Introduces a pure virtual method responsible for reading from the stream.
		 */
		virtual size_t  Read(void *Buffer, size_t Count) = 0;

		/** Introduces a pure virtual method responsible for writing to the stream.
		 *  Write attempts to write up to Count bytes to Buffer, and returns the number of bytes actually written.
		 */
		virtual size_t  Write(const void *Buffer, size_t Count) = 0;
	public:
		/* Constructor
		 */
		CStream() { }

		/* Destructor
		 */
		virtual ~CStream();

		/** Reads a block of bytes from the stream into Buffer, and returns the amound of bytes actually read.
		 *	\exception std::exception On any error, or if ZERO bytes are read.
		 */
		size_t  ReadBuffer(void *Buffer, size_t Count);

		/** Writes a block of bytes to the stream from Buffer.
		 *	\exception std::exception On any error
		 */
		void  WriteBuffer (const void *Buffer, size_t Count);

		/** Copies a specified number of bytes from one stream to another.
		 */
		size_t  CopyFrom(CStream* Source, size_t Count);

		/** Introduces a pure virtual method for moving to a specified position in the streamed resource.
		 *   he Origin parameter indicates how to interpret the Offset parameter. Origin should be one of the following values:
		 *	- sFromBeginning	(Default) Offset is from the beginning of the resource. Seek moves to the position Offset. Offset must be >= 0.
		 *	- sFromCurrent		Offset is from the current position in the resource. Seek moves to Position + Offset.
		 *	- sFromEnd			Offset is from the end of the resource. Offset must be <= 0 to indicate a number of bytes before the end of the file.
		 * \return Seek returns the new value of the Position property.
		 */
		virtual size_t Seek(long Offset, CStream::TSeekOrigin Origin = sFromBeginning) = 0;

		/** Returns the total amount of bytes in the stream.
		 */
		virtual size_t getTotalBytesCount() = 0;

		/** Method for getting the current cursor position, where 0 is the first byte and TotalBytesCount-1 the last one.
		 */
		virtual size_t getPosition()=0;


		/** Write operator for objects
		  */
		CStream& operator << (const CSerializable *pObj);
		/** Write operator for objects
		  */
		CStream& operator << (const CSerializable &obj);

		/** Read operator for objects
		  */
		CStream& operator >> (CSerializable* &pObj);
		/** Read operator for objects
		  */
		CStream& operator >> (CSerializable &obj);


		/** Writes an object to the stream.
		 */
		void WriteObject( const CSerializable *o );

		/** Reads an object from stream, where its class is determined
		 *   at runtime.
		 * \exception std::exception On I/O error or undefined class.
		 */
		CSerializable *ReadObject();

		/** Reads an object from stream, where its class must be the same
		 *    as the supplied object, where the loaded object will be stored in.
		 * \exception std::exception On I/O error or different class found.
		 */
		void ReadObject(CSerializable *existingObj);

		/** Writes a string to the stream in a textual form.
		  * \sa CStdOutStream
		  */
		virtual void printf(const char *fmt,...) MRPT_printf_format_check(2,3);  // The first argument (1) is "this" !!!

		/** Prints a vector in the format [A,B,C,...] using CStream::printf, and the fmt string for <b>each</b> vector element. */
		template <typename T>
		void printf_vector(const char *fmt, const std::vector<T> &V )
		{
			this->printf("[");
			size_t N = V.size();
			for (size_t i=0;i<N;i++)
			{
				this->printf(fmt,V[i]);
				if (i!=(N-1)) this->printf(",");
			}
			this->printf("]");
		}

	}; // End of class def.



#define DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( T ) \
	CStream& operator<<(CStream&out, const T &a); \
	CStream& operator>>(CStream&in, T &a);

#define IMPLEMENT_CSTREAM_READ_WRITE_SIMPLE_TYPE( T ) \
	CStream& UTILS::operator<<(CStream&out, const T &a) \
	{ \
		out.WriteBuffer( (void*)&a, sizeof(a) ); \
		return out; \
	} \
	CStream& UTILS::operator>>(CStream&in, T &a) \
	{ \
		in.ReadBuffer( (void*)&a, sizeof(a) ); \
		return in; \
	}

	// Definitions:
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( bool )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( uint8_t )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( int8_t )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( uint16_t )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( int16_t )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( uint32_t )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( int32_t )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( uint64_t )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( int64_t )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( float )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( double )
	DECLARE_CSTREAM_READ_WRITE_SIMPLE_TYPE( long double )


	CStream& operator << (CStream&, const char *a);
	CStream& operator << (CStream&, const vector_int &a);
	CStream& operator << (CStream&, const vector_uint &a);
	CStream& operator << (CStream&, const vector_word &a);
	CStream& operator << (CStream&, const vector_long &a);
	CStream& operator << (CStream&, const vector_float &a);
	CStream& operator << (CStream&, const vector_double &a);
	CStream& operator << (CStream&, const vector_byte &a);
	CStream& operator << (CStream&, const vector_bool &a);
	CStream& operator << (CStream&, const std::string &str);

	CStream& operator>>(CStream&in, char *a);
	CStream& operator>>(CStream&in, vector_int &a);
	CStream& operator>>(CStream&in, vector_uint &a);
	CStream& operator>>(CStream&in, vector_word &a);
	CStream& operator>>(CStream&in, vector_long &a);
	CStream& operator>>(CStream&in, vector_double &a);
	CStream& operator>>(CStream&in, vector_float &a);
	CStream& operator>>(CStream&in, vector_byte &a);
	CStream& operator>>(CStream&in, vector_bool &a);
	CStream& operator>>(CStream&in, std::string &str);

} // End of namespace

#endif
