/*
 * message.h
 *
 * Copyright (C) 2001 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
 *
 *
 * This program 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 (version 2 of the License)
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * This finally defines the format of the queue entries for the communication
 * with the network thread
 *
 * Author: Matthias Braun <MatzeBraun@gmx.de>
 */

#ifndef __MSGQUEUE_H__
#define __MSGQUEUE_H__

#include <csutil/refcount.h>
#include <csutil/csendian.h>
#include <csgeom/vector3.h>

#include "util/log.h"
#include "net/packing.h"
#include "net/pstypes.h"
#include "util/genqueue.h"


class csSyncRefCount
{
protected:
  static csRef<csMutex> mutex;

  int ref_count;

  // To avoid a problem with MSVC and multiple DLLs (with separate memory
  // space) we have to use a virtual destructor.
  // @@@ Another alternative is to force this function to be non-inline, as
  // doing so will most likely achieve the same result.
  virtual void Delete ()
  {
    csScopedMutexLock lock(mutex);
    delete this;
  }

  virtual ~csSyncRefCount () {}

public:
  /// Initialize object and set reference to 1.
  csSyncRefCount () : ref_count(1)
  {
      if (!mutex)
          mutex = csMutex::Create(true);
  }

  /// Increase the number of references to this object.
  void IncRef () 
  {
      csScopedMutexLock lock(mutex);
      ref_count++; 
  }
  /// Decrease the number of references to this object.
  void DecRef ()
  {
      csScopedMutexLock lock(mutex);
    ref_count--;
    if (ref_count <= 0)
      Delete ();
  }
  /// Get the reference count (only for debugging).
  int GetRefCount () const
  {
      csScopedMutexLock lock(mutex);
      return ref_count;
  }
};



typedef enum
{
    PRIORITY_LOW  = 0x00,
    PRIORITY_HIGH = 0x01,
    PRIORITY_MASK = 0x01
};

// 8 bit should hopefully be enough
typedef uint8_t msgtype;

/*  To protect the server from a client with ill intent sending a simply HUGE message that requires tons of
 *  memory to reassemble, messages beyond this size will be dropped.
 *  Changing this value requires a NETVERSION change in messages.h.
 */
#define MAX_MESSAGE_SIZE 65535  // Current max

/**
 * this struct represents the data that is sent out through the network (all
 * additional stuff should go into the struct MsgEntry
 */
#pragma pack (1)
struct psMessageBytes
{
    /// Version
    msgtype    type;
    /// the size of the following data
    uint16_t    size;
    /** this can be used as a pointer to the data */
    char    payload[0];

    size_t GetTotalSize() const { return sizeof(psMessageBytes) + csLittleEndian::Convert(size); }
    size_t GetSize() const      { return csLittleEndian::Convert(size); }
    void SetSize(size_t len)      { size = csLittleEndian::Convert((uint16)(len & 0xFFFF)); }
    void SetTotalSize(size_t len) { size = csLittleEndian::Convert((uint16)((len-sizeof(psMessageBytes)) & 0xFFFF)); }
};
// set to default packing
#pragma pack()

/**
 * The structure of 1 queue entry (pointer to a message)
 */
class MsgEntry : public csSyncRefCount
{
public:
    MsgEntry (size_t datasize = 0, uint8_t msgpriority=PRIORITY_HIGH)
        : clientnum(0), priority(msgpriority), msgid(0), overrun(false)
    {
        if (datasize > MAX_MESSAGE_SIZE)
        {
            Debug3(LOG_NET,0,"Call to MsgEntry construction truncated data.  Requested size %u > max size %u.\n",datasize,MAX_MESSAGE_SIZE);
            datasize=MAX_MESSAGE_SIZE;
        }
        bytes = (psMessageBytes*) malloc(sizeof(psMessageBytes) + datasize);
        CS_ASSERT(bytes != NULL);

        current = 0;
        bytes->SetSize(datasize);
    }

    MsgEntry (const psMessageBytes* msg)
        : clientnum(0), priority(PRIORITY_LOW), msgid(0), overrun(false)
    {
        size_t msgsize = msg->GetTotalSize();
        if (msgsize > MAX_MESSAGE_SIZE)
        {
            Debug2(LOG_NET,0,"Call to MsgEntry construction (from network message psMessageBytes) truncated data.  Source data > %u length.\n",MAX_MESSAGE_SIZE);
            msgsize = MAX_MESSAGE_SIZE;
        }

        current = 0;

        bytes = (psMessageBytes*) malloc(msgsize);
        CS_ASSERT(bytes != NULL);

        memcpy (bytes, msg, msgsize);
        // If we truncated the message, make sure the size reflects that
        bytes->SetTotalSize(msgsize);
    }

    MsgEntry (const MsgEntry* me) 
    {
        size_t msgsize = me->bytes->GetTotalSize();
        if (msgsize > MAX_MESSAGE_SIZE)
        {
            Bug2("Call to MsgEntry copy constructor truncated data.  Source data > %u length.\n",MAX_MESSAGE_SIZE);
            msgsize = MAX_MESSAGE_SIZE;
        }
        bytes = (psMessageBytes*) malloc(msgsize);
        CS_ASSERT(bytes != NULL);
        memcpy (bytes, me->bytes, msgsize);

        // If we truncated the message, make sure the size reflects that
        bytes->SetTotalSize(msgsize);

        clientnum = me->clientnum;
        priority = me->priority;
        msgid = me->msgid;
        current = 0;
        overrun = false;
    }

    virtual ~MsgEntry()
    {
        free ((void*) bytes);
    }

    void ClipToCurrentSize()
    {
        bytes->SetSize(current);
    }

    void Reset() { current = 0; }
    /// Add a string to the current psMessageBytes buffer
    void Add(const char *str)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const char *) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        if ( str == 0 )
        {
            // No space left!  Don't overwrite the buffer.
            if (current + 1 > bytes->GetSize())
            {
                Bug3("MsgEntry::Add(const char *) call for msgid=%u len=%u would overflow buffer! str = (null)\n",
                    msgid,0);
                overrun=true;
                return;
            }
            bytes->payload[current] = 0;
            current++;
            return;
        }

        // Not enough space left!  Don't overwrite the buffer.
        if (current + strlen(str)+1 > bytes->GetSize())
        {
            Bug4("MsgEntry::Add(const char *) call for msgid=%u len=%u would overflow buffer! str = %s\n",
                msgid,strlen(str),str);
            overrun=true;
            return;
        }

        strcpy(bytes->payload+current,str);
        current += strlen(str)+1;
    }

    /// Add a float to the current psMessageBytes buffer
    void Add(const float f)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const float) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(uint32) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const float) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        uint32 *pf = (uint32 *)(bytes->payload+current);
        *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(f) );
        current += sizeof(uint32);
    }

    /// Add a double the current psMessageBytes buffer
#if 0
    // disabled for now, because CS has no convert function for double :-(
    void Add(const double d)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const double) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(double) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const double) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        double* p = (double*) (bytes->payload+current);
        *p = csLittleEndian::Convert(d);
        current += sizeof(double);
    }
#endif

    /// Add unsigned 16 bit int to current psMessageBytes buffer
    void Add(const uint16_t s)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const uint16_t) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(uint16_t) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const uint16_t) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        uint16_t *p = (uint16_t*) (bytes->payload+current);
        *p = csLittleEndian::Convert(s);
        current += sizeof(uint16_t);
    }

    /// Add signed 16 bit int to current psMessageBytes buffer
    void Add(const int16_t s)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const int16_t) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(int16_t) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const int16_t) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        int16_t *p = (int16_t *)(bytes->payload+current);
        *p = csLittleEndian::Convert(s);
        current += sizeof(int16_t);
    }
    /// Add unsigned 32Bit Int to current psMessageBytes buffer
    void Add(const int32_t i)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const int32_t) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(int32_t) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const int32_t) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        int32_t *p = (int32_t *)(bytes->payload+current);
        *p = csLittleEndian::Convert((int32) i);
        current += sizeof(int32_t);
    }
    
       /// Add unsigned 4byte int to current psMessageBytes buffer
    
    void Add(const uint32_t i)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const uint32_t) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(uint32_t) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const uint32_t) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        uint32_t *p = (uint32_t *)(bytes->payload+current);
        *p = csLittleEndian::Convert((uint32) i);
        current += sizeof(uint32_t);
    }
          
      /// Add a pointer to the current psMessageBytes buffer. Pointers must never be sent over the network!
    
    void AddPointer(const uintptr_t i)
     {
         if (bytes == NULL)
         {
             Bug1("MsgEntry::Add(const uintptr_t) bytes=NULL!\n");
             CS_ASSERT(false);
             return;
         }

         // If the message is in overrun state, don't add anymore, it's already invalid
         if (overrun)
             return;

        // Not enough space left!  Don't overwrite the buffer.
         if (current + sizeof(uintptr_t) > bytes->GetSize())
         {
             Bug2("MsgEntry::Add(const uintptr_t) call for msgid=%u would overflow buffer!\n",msgid);
             overrun=true;
             return;
         }

         uintptr_t *p = (uintptr_t *)(bytes->payload+current);
         *p = i; // Pointers can only be used locally, and the endian won't change locally!
         current += sizeof(uintptr_t);
     }

       /// Add 8bit unsigned int to current psMessageBytes buffer
    
    void Add(const uint8_t i)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const uint8_t) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(uint8_t) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const uint8_t) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        uint8_t *p = (uint8_t *)(bytes->payload+current);
        *p = i; // no need to endian convert a byte :)
        current += sizeof(uint8_t);
    }

    /// Add 8 bit signed int to buffer
    void Add(const int8_t i)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const int8_t) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(int8_t) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const int8_t) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        int8_t *p = (int8_t*) (bytes->payload+current);
        *p = i; // no need to endian convert a byte :)
        current += sizeof(int8_t);
    }

    /// Add bool to current psMessageBytes buffer
    void Add(const bool b)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const bool) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(uint8_t) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const bool) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        uint8_t t = b ? 1 : 0;
        Add(t);
    }
    
    /// Add an x,y,z vector to the buffer
    void Add(const csVector3& v)
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const csVector3) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + 3*sizeof(uint32) > bytes->GetSize())
        {
            Bug2("MsgEntry::Add(const csVector3) call for msgid=%u would overflow buffer!\n",msgid);
            overrun=true;
            return;
        }

        uint32 *pf = (uint32 *)(bytes->payload+current);
        *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.x) );
        *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.y) );
        *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(v.z) );
        current += 3*sizeof(uint32);
    }


    /// Add a processed buffer of some kind; should only be used by files and the like.
    // NOTE THIS IS NOT ENDIAN-CONVERTED:  YOUR DATA MUST ALREADY BE ENDIAN SAFE.
    void Add(const void *datastream,const uint32_t length) 
    {
        if (bytes == NULL)
        {
            Bug1("MsgEntry::Add(const void *datastream,const uint32_t length) bytes=NULL!\n");
            CS_ASSERT(false);
            return;
        }

        // If the message is in overrun state, don't add anymore, it's already invalid
        if (overrun)
            return;

        // Not enough space left!  Don't overwrite the buffer.
        if (current + sizeof(uint32_t) + length > bytes->GetSize())
        {
            Bug3("MsgEntry::Add(const void *datastream,const uint32_t length) call for msgid=%u len=%u would overflow buffer!\n",
                msgid,length);
            overrun=true;
            return;
        }

        Add(length);

        if (length!=0) 
        {
            void *currentloc = (void *) (bytes->payload+current);
            memcpy(currentloc, datastream, length);
            current += length;
        }
    }

    /// Check if we are at the end of the curretn psMessageBytes buffer
    bool IsEmpty()
    {
        return current >= bytes->GetSize();
    }

    /// Get a null-terminated string from the current psMessageBytes buffer
    const char *GetStr()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return NULL;

        /* Verify that the string ends before the buffer does
         *  When this finishes, current is advanced to the end of the buffer or
         *  a terminating character (0x00) - whichever is reached first.
         */
        size_t position=current;
        while (current < bytes->GetSize() && bytes->payload[current]!=0x00)
            current++;
        if (current>=bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return NULL;
        }

        // Advance 1 past the terminating character
        current++;

        // Return NULL instead of empty string(s)
        if ( bytes->payload[position] == 0 )
            return NULL;

        return bytes->payload+position;
    }

    /// Get a float from the current psMessageBytes buffer
    float GetFloat()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0.0f;

        if (current+sizeof(float) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0.0f;
        }

        uint32 *p = (uint32 *)(bytes->payload+current);
        current += sizeof(uint32);
        return csIEEEfloat::ToNative( csLittleEndian::Convert(*p) );
    }
    /// Get a signed 16bit Integer from the current psMessageBytes buffer
    int16_t GetInt16()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0;

        if (current+sizeof(int16_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0;
        }

        int16_t *p = (int16_t*) (bytes->payload+current);
        current += sizeof(int16_t);
        return csLittleEndian::Convert(*p);
    }
    /// Get a unsigned 16bit Integer from the curren psMessageBytes buffer
    uint16_t GetUInt16()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0;

        if (current+sizeof(uint16_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0;
        }

        uint16_t *p = (uint16_t*) (bytes->payload+current);
        current += sizeof(uint16_t);
        return csLittleEndian::Convert(*p);
    }

    /// Get a signed 32Bit Integer from the current psMessageBytes buffer
    int32_t GetInt32()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0;

        if (current+sizeof(int32_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0;
        }

        int32_t *p = (int32_t*) (bytes->payload+current);
        current += sizeof(int32_t);
        return csLittleEndian::Convert(*p);
    }
    
    /// Get an unsigned 4byte int from the current psMessageBytes buffer
    uint32_t GetUInt32()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0;

        if (current+sizeof(uint32_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0;
        }

        uint32_t *p = (uint32_t *)(bytes->payload+current);
        current += sizeof(uint32_t);
        return csLittleEndian::UInt32(*p);
    }

    /// Get a pointer from the current psMessageBytes buffer. Pointers must never be sent over the network!
    uintptr_t GetPointer()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0;

        if (current+sizeof(uintptr_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0;
        }

        uintptr_t *p = (uintptr_t *)(bytes->payload+current);
        current += sizeof(uintptr_t);
        return *p;
    }

    /// Get a signed 8bit Integer from teh current psMessageBytes buffer
    int8_t GetInt8()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0;

        if (current+sizeof(int8_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0;
        }

        int8_t *p = (int8_t*) (bytes->payload+current);
        current += sizeof(int8_t);
        return *p; // no need to convert bytes
    }
    /// Get an unsigned 8Bit Integer from the current psMessageBytes buffer
    uint8_t GetUInt8()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0;

        if (current+sizeof(uint8_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0;
        }

        uint8_t *p = (uint8_t *)(bytes->payload+current);
        current += sizeof(uint8_t);
        return *p; // no need to convert bytes
    }
    /// Get a bool from the current psMessageBytes buffer
    bool GetBool()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return false;

        if (current+sizeof(uint8_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return false;
        }

        return (GetUInt8() != 0);
    }
    
    csVector3 GetVector()
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return 0;

        if (current+sizeof(csVector3) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            overrun=true;
            return 0;
        }
        
        uint32 *p = (uint32 *)(bytes->payload+current);
        csVector3 v;
        v.x = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
        v.y = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
        v.z = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
        current += 3*sizeof(uint32);
        return v;
    }

    // Get a pre-converted data buffer with recorded length from the current psMessageBytes buffer.
    void * GetData(uint32_t*length)
    {
        // If the message is in overrun state, we know we can't read anymore
        if (overrun)
            return NULL;

        if (current+sizeof(uint32_t) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            *length=0;
            overrun=true;
            return NULL;
        }

        *length = GetUInt32();
        if ((*length)==0) return NULL;

        if (current + (*length) > bytes->GetSize())
        {
            Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
            *length=0;
            overrun=true;
            return NULL;
        }

        void *datastream = bytes->payload+current;
        current += *length;
        return datastream;
    }
    
    void SetType(uint8_t type)
    {
        bytes->type = type;
    }
    uint8_t GetType()
    {
        return bytes->type;
    }
    /////////////////////////////////
    // Dummy functions required by GenericQueue
    ////////////////////////////////////
    void SetPending(bool flag)
    { }
    bool GetPending()
    { return false; }
    
    /// Return the size of the databuffer
    size_t GetSize()
    { return bytes->GetSize();}
    

public:
    /** The Number of the client the Message is from/goes to */
    uint32_t clientnum;

    /** The current position for Pushing and Popping */
    size_t current;

    /** The priority this message should be handled */
    uint8_t priority;

    /** Unique identifier per machine */
    uint32_t msgid;

    /** Indicates wether a read or write overrun has occured */
    bool overrun;


    /** The message itself ie one block of memory with the
     * header and data following
     */
    psMessageBytes *bytes;
};

#endif



