/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework 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 as in version 2 of the License.

 * 
 * The iWear Framework 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
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWREMOTE_XDRSTREAM_H
#define __IWREMOTE_XDRSTREAM_H

#ifndef __IWREMOTE_RPCSTREAM_H
#include <iwremote/rpcstream.h>
#endif

namespace iwear
{
    namespace net
    {
/**
 * This class implements the interface for RPCStream objects.
 * @todo TODO FIXME reimplement a clean buffer setting, receiving, creating and
 * interchange with the xdr functions.
 */
class XDRStream : public RPCStream
{
private:
protected:
    /**
     * This is the saved buffer when the buffer belongs to us
     */
    char * buf_;

    /**
     * This is the buffer we currently work on
     */
    char * buffer;

    /**
     * This is the size of the work-buffer (in octets)
     */
    size_t bufsize;

    /**
     * This is the current position in the buffer (in octets)
     */
    size_t bufpos;

    /**
     * This is the maximum position we have written so far, so reading beyond
     * it should be avoided.
     */
    size_t maxbufpos;

public:
    /**
     * Create the stream passing it a buffer. The buffer will only be used by
     * the stream, not deleted if the stream ends its life.
     */
    XDRStream( char *, size_t );

    /**
     * Create the stream with its own internal buffer. The buffer belongs to
     * the stream and is deleted if the stream ends.
     */
    XDRStream( size_t );

    virtual ~XDRStream();

    /**
     * This returns the buffer and the amount of data that is already in the
     * buffer. The real size of the buffer might be bigger, but the number says
     * which bytes are already filled and ready for transmission.
     * @see max_size
     */
    virtual std::pair<char *, uint32_t> get_buffer( void );

    virtual std::pair<const char *, uint32_t> get_buffer( void ) const;
    
    virtual void set_buffer( char*, uint32_t );

    virtual void replace_buffer( char*, uint32_t );

    virtual void replace( RPCStream& );

    /**
     * Parses the next stream object and returns it as bool. Throws exception
     * when failing.
     */
    virtual bool get_bool( const char* );
    virtual long double get_long_double( const char* );
    virtual double get_double( const char* );
    virtual float get_float( const char* );
    virtual string get_string( const char* );
    virtual uid get_uid( const char* );

    virtual void put_bool( bool, const char* );
    virtual void put_long_double( long double, const char* );
    virtual void put_double( double, const char* );
    virtual void put_float( float, const char* );
    virtual void put_string( const string&, const char* );
    virtual void put_uid( const uid&, const char* );

    virtual uint32_t data( void ) { return bufsize - bufpos; }


    /**
     * This returns the real size of the internal buffer in bytes, i.e. how
     * many bytes can be filled into the stream.
     */
    virtual size_t max_size( void );

    /**
     * This asks for resizing the buffer. If the new size is bigger, the
     * resulting buffer is either now bigger or this throws an exception.
     * If the new size is smaller, the resulting buffer may be smaller, but
     * must not be. An exception is not thrown in this case. This is for
     * efficiency.
     * @note If this stream uses an external set buffer, this buffer is not
     * resized, but instead replaced by an internal buffer of the new size.
     */
    virtual void resize( size_t );

    virtual int8_t get_int8_t( const char* );
    virtual uint8_t get_uint8_t( const char* );

    virtual int16_t get_int16_t( const char* );
    virtual uint16_t get_uint16_t( const char* );

    virtual int32_t get_int32_t( const char* );
    virtual uint32_t get_uint32_t( const char* );

    virtual int64_t get_int64_t( const char* );
    virtual uint64_t get_uint64_t( const char* );

    virtual void put_int8_t( int8_t, const char* );
    virtual void put_uint8_t( uint8_t, const char* );

    virtual void put_int16_t( int16_t, const char* );
    virtual void put_uint16_t( uint16_t, const char* );

    virtual void put_int32_t( int32_t, const char* );
    virtual void put_uint32_t( uint32_t, const char* );

    virtual void put_int64_t( int64_t, const char* );
    virtual void put_uint64_t( uint64_t, const char* );

    virtual void rewind( void ) { bufpos = 0; }
    virtual void to_end( void ) { bufpos = maxbufpos; }

PH2 virtual void set_flags( uint8_t );
PH2 virtual uint8_t get_flags( void );

PH2 virtual void finalize( void );

    virtual void set_sequence( uint32_t );
    virtual void set_deferr_id( uint32_t );

    virtual uint32_t get_sequence( void );
    virtual uint32_t get_deferr_id( void );

    virtual void skip_header( );

    virtual uint8_t get_type( void );

    virtual uint16_t get_channel( void );

    virtual void dump( void ) const;
};

}
}
#endif
