
#ifndef _RECEIVER_H
#define _RECEIVER_H

#include "converse.h"
#include "receiver.decl.h"

typedef void (* recvCallBack)(void *);

#define CMPI_DOUBLE_PRECISION 0
#define CMPI_INTEGER 1
#define CMPI_REAL 2
#define CMPI_COMPLEX 3
#define CMPI_LOGICAL 4
#define CMPI_CHARACTER 5
#define CMPI_BYTE 6
#define CMPI_PACKED 7

class receiverMsg: public CMessage_receiverMsg, public ArrayMessage
{
public:
  int tag;
  int sendFrom;
  int refno;
  int size;
  char *buf;

  static void *alloc(int mnum, size_t size, int *sizes, int pbits)
  {
    int stmp = sizes[0]*sizeof(char);
    receiverMsg *m = (receiverMsg *) CkAllocMsg(mnum, size+stmp, pbits);
    m->size = sizes[0];
    m->buf = (char *)((char *)m + size);
    return (void *)m;
  }

  static void *pack(receiverMsg *m)
  {
//    return (void *)m;
    m->buf = (char *)((char *)m->buf - (char *)&m->buf);
    return (void *)m;
  }

  static receiverMsg *unpack(void *buf)
  {
    receiverMsg *m = (receiverMsg *) buf;
//    m->buf = (char *)((char *)m+sizeof(receiverMsg));
    m->buf = (char *)((char*)&(m->buf) + (size_t)(m->buf));
    return m;
  }
};


class receiver: public ArrayElement
{
private:
  CmmTable  msgTbl;
  CmmTable  reqTbl;
  int counter;

  recvCallBack callback;
  void *cb_data;

  typedef struct _tblEntry {
    char *buf;
    int size;
  } tblEntry;

  void recvAlready();

public:
  receiver(ArrayElementCreateMessage *);
  receiver(ArrayElementMigrateMessage *);
  ~receiver();

  // entry
  void generic(receiverMsg *);
  void ready2go();

  void send(void *buf, int size, int dest, int tag, int refno);
  void irecv(void *buf, int size, int source, int tag, int refno);   
  void iwaitAll(recvCallBack f, void *data, int refno);

private:
  void sendTo(int tag, char *pointer, int size, int from, int refno);
};

#endif
