// -*- c++ -*-
//------------------------------------------------------------------------------
//                          xdrIOBuffer.h
//------------------------------------------------------------------------------
//  Copyright (c) 2000 by Vladislav Grinchenko
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//------------------------------------------------------------------------------
//  Created: 04/03/2000
//------------------------------------------------------------------------------

#ifndef XDR_IO_BUFFER_H
#define XDR_IO_BUFFER_H

#include "assa/Assert.h"
#include "assa/Socket.h"

#include <string> 

namespace ASSA {

/** @file xdrIOBuffer.h
 *
 * This class allows to read XDR-encoded data from Socket stream asynchronously
 * and then read from it as if from a stream of intermixed strings, integers 
 * and floats. Data are XDR-decoded on a fly.
 *
 * Testing xdrIOBuffer object in conditional statement will produce
 * false if:
 *
 *     - Not entire buffer has been read yet. 
 *     - Socket stream exceptional condition occured.
 *
 * Thus, data accumulation and data decoding functions are separated.
 * 
 * Initially, buffer is in waiting state. In this state, 
 * xdrIOBuffer object waits for bytes from the Socket stream. 
 *
 * When buffer object becomes full, the state is switched to 
 * xmitted. Now, an application code can read data
 * from the buffer. The data will be XDR-decoded.
 *
 * xdrIOBuffer object yields TRUE in conditional statements only 
 * in xmitted state. In other words, buffer is TRUE if
 * it is full, and FALSE otherwise.
 *
 * xdrIOBuffer can be used only once. You cannot "rewind", and therefore
 * reuse it.
 */

class xdrIOBuffer
{
public:
	/** @enum state_t 
	 */
	enum state_t { 
		waiting, 
		xmitted, 
		parsed, 
		error 
	};

	/** Constructor. 
	 */
	xdrIOBuffer (u_int len_);

	/** Destructor.
         */
	~xdrIOBuffer ();

	/** Copy constructor
	 */
	xdrIOBuffer (const xdrIOBuffer& rhs_);

	/** Assign operator.
	 */
	xdrIOBuffer& operator= (const xdrIOBuffer& rhs_);

	/** Read raw data from <TT>Socket</TT> nonblocking and 
	    store into internal buffer.
	*/
	friend Socket& operator>>(Socket&, xdrIOBuffer&);

	/** Read and XDR-decode STL string from the buffer.
	 */
	xdrIOBuffer& operator>>(std::string&);

	/** Read and XDR-decode an integer from the buffer.
	 */
	xdrIOBuffer& operator>>(int&);

	/** Read and XDR-decode a float from the buffer.
	 */
	xdrIOBuffer& operator>>(float&);

	/** Convertion to void* (for testing where bool is required).
	 */
	operator void*() const;

	/** Give verbal interpretation of object's state.
	 */
	string get_state () const;

	/** Return number of bytes in xdrIOBuffer. In <b>waiting</b>
	    state it's bytes transmitted so far. In <b>xmitted</b> state,
	    number of bytes left to decode.
	 */
	int size () const;

	/** Return buffer (maximum expected/allowable) size.
	 */
	int buffer_size () const;

	/** Return pointer to the first byte of xdrIOBuffer.
	 */
	const char* str () const;

	/** Dump object's internal state to the log file
	 */
	void dump () const;

protected:
	/// Copy object from argument
	void copy (const xdrIOBuffer&);

private:
	/// Buffer
	char* m_buf;

	/// Buffer size and maximum expected size
	int m_sz;

	/// Pointer for next I/O operation into the buffer	
	char* m_ptr;

	/// Object state
	state_t m_state;
};

inline
xdrIOBuffer::
xdrIOBuffer (const xdrIOBuffer& rhs_) 
{
	trace_with_mask("xdrIOBuffer::xdrIOBuffer(xdrIOBuffer&)", XDRBUFTRACE);

	copy (rhs_);
}

inline
xdrIOBuffer::
operator void*() const
{
	trace_with_mask("xdrIOBuffer::opt void*()", XDRBUFTRACE);

	return (m_state == waiting || m_state == parsed)  
		? (void *)0	// bad state
		: (void *)(-1); // good state
}

inline int
xdrIOBuffer::
size () const
{
	return (m_ptr - m_buf);
}

inline int
xdrIOBuffer::
buffer_size () const
{
	return (m_sz);
}

inline const char*
xdrIOBuffer::
str () const
{
	return ((const char*) m_buf);
}

} // end namespace ASSA

#endif /* XDR_IO_BUFFER_H */  
