#ifndef _MSG_QUEUE_H
#define _MSG_QUEUE_H

#include "mytypes.h"
#include "list.h"
#include "move.h"

// server commands
enum { GET_PLAYER_INFO, CHANGE_ROUTE, SYNCH, CONNECT, RECONNECT };

struct Msg
{
  Msg() {}
  Msg(char *b, int l) { buf = b; len = l; }
  int operator==(Msg &m) { return buf == m.buf && len == m.len; }
  int operator!=(Msg &m) { return buf != m.buf || len != m.len; }
  char *buf;
  ushort len;
};

class MsgQ;

// destructively send's a queue to the server which will decide what
// to do with it
void SendQ(MsgQ *q);

// destructive send to a socket
void SendQ(int sock, MsgQ *q);

// non destructive send to a socket
void NonDestructiveSendQ(int sock, MsgQ *q);

// Message Q's are never received explicitly by the user
// the system will construct them when it gets data and
// hand them to you

class MsgQ
{
public:
  // creates empty queue
  MsgQ() : mesgl(mesgs) { count = 0; }
  ~MsgQ(); // deletes all remaining messages

  int Count() { return count; }

  void InsertHead(Msg m) {
    mesgs.Insert(m); ++count;
    if (count == 1) mesgl.Next();
  }
  int PeekHead(Msg &m) {
    return count == 0 ? 0 : (m = mesgs.First(), 1);
  }
  friend void operator<<(MsgQ &q, Msg m); // insert at tail
  // fails if empty queue, otherwise will remove the head
  friend int operator>>(MsgQ &q, Msg &m);

  friend int operator>>(MsgQ &q, long &n); // get long
  friend int operator>>(MsgQ &q, int &n); // get int
  friend void operator<<(MsgQ &q, long n); // send int

  friend int operator>>(MsgQ &q, char *(&str)); // get string
  friend void operator<<(MsgQ &q, char *str); // send string

  friend int operator>>(MsgQ &q, PieceMove &move); // get move
  friend void operator<<(MsgQ &q, PieceMove move); // send move

  friend void operator<<(MsgQ &q, MsgQ &q1); // destructive concat

  void AddCmd(long cmd, long arg = 0);
  int IsCmd(long &cmd, long &arg);

  friend void NonDestructiveSendQ(int sock, MsgQ *);

  MsgQ *Copy(); // create an identical new message queue

  // don't use this, I just put it here to make it easier for the
  // windows routines to access it
  List<Msg> mesgs;

private:
  int count;
  Lister<Msg> mesgl;
};

inline void operator<<(MsgQ &q, Msg m) {
  q.mesgl.Insert(m); q.mesgl.Next(); ++q.count;
};

inline int operator>>(MsgQ &q, Msg &m) {
  if (q.count == 0) return 0;
  --q.count;
  m = q.mesgs.RemoveHead();
  if (q.count == 0) q.mesgl = q.mesgs;
  return 1;
}

#endif
