/*---------------------------------------------------------------
	FILE: CStream.h
	USE: See description below.

   Part of the MRPT Library
   ISA - Universidad de Malaga - http://www.isa.uma.es
  ---------------------------------------------------------------*/
#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 unsigned long  Seek(long Offset, CStream::TSeekOrigin Origin = sFromBeginning) = 0;

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

		/** Method for getting the current cursor position, where 0 is the first byte and TotalBytesCount-1 the last one.
		 */
		virtual unsigned long  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 *formatStr, ... );

	}; // 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
