/* LICENSE:
  =========================================================================
    CMPack'04 Source Code Release for OPEN-R SDK 1.1.5-r2 for ERS7
    Copyright (C) 2004 Multirobot Lab [Project Head: Manuela Veloso]
    School of Computer Science, Carnegie Mellon University
    All rights reserved.
  ========================================================================= */

#ifndef EasyNet_macro_h_DEFINED
#define EasyNet_macro_h_DEFINED


#include <ant.h>
#include <antTypes.h>
#include <EndpointTypes.h>
#include <IPAddress.h>

enum NetProtocol {
    NETPROTOCOL_TCP,
    NETPROTOCOL_UDP
};

enum NetCloseMode {
    CLOSE_NONE,
    CLOSE_CLEAN_ONLY,
    CLOSE_CLEAN_ABORT,
    CLOSE_ABORT,
    CLOSE_PASSIVE_CLEAN,
    CLOSE_PASSIVE_ABORT,
};

typedef struct NetConnectionStruct *NetConnection;
typedef struct NetConnectionItemStruct* NetConnectionItem;
typedef NetConnection NetTCPConnection;
typedef NetConnection NetUDPConnection;
typedef int    NetError;

class Net_Class {
public:
    void Block_Dummy_Func(NetConnection Conn, int Bytes) {};
};

typedef void (Net_Class::*netMemberCallback)(NetConnection, int);

// Used to call member functions as callbacks
typedef void (*netCallbackCaller)(netMemberCallback, NetConnection, int);

// External declaration of block constants.
extern const netMemberCallback BLOCK_LISTEN;
extern const netMemberCallback BLOCK_CONNECT;
extern const netMemberCallback BLOCK_SEND;
extern const netMemberCallback BLOCK_RECEIVE;
extern const netMemberCallback BLOCK_CLOSE;

// NetError Constants bases 
const int NETERR_TCP_BASE =  32000;
const int NETERR_UDP_BASE =  64000;

// External declaration of last error variable.
extern NetError NetLastError;


// Forward declaration of error constants
// The actual values are not declared here because they require
// the xxxEndpointMsg.h headers, which I'd rather not include here
// because they cause annoying warning messages when they are included
// from a main object's header (as for behaviors).

extern const int NETERR_CONNECTION_INVALID;

extern const int NETERR_TCP_SUCCESS; 
extern const int NETERR_TCP_FAIL;
extern const int NETERR_TCP_CONNECTION_CLOSED;
extern const int NETERR_TCP_CONNECTION_RESET;
extern const int NETERR_TCP_CONNECTION_TIMEOUT;
extern const int NETERR_TCP_CONNECTION_BUSY;
extern const int NETERR_TCP_ADDRESSINUSE;
extern const int NETERR_TCP_ADDRESSERROR;
extern const int NETERR_TCP_PORT_UNREACHABLE;
extern const int NETERR_TCP_PROTOCOL_UNREACHABLE;
extern const int NETERR_TCP_HOST_UNREACHABLE;
extern const int NETERR_TCP_NETWORK_UNREACHABLE;
extern const int NETERR_TCP_MESSAGE_TOO_LONG;
extern const int NETERR_TCP_TTL_EXCEEDED;
extern const int NETERR_TCP_TIME_EXCEEDED;
extern const int NETERR_TCP_WOULDBLOCK;
extern const int NETERR_TCP_BUFFER_INVALID;
extern const int NETERR_TCP_OPERATION_INVALID;
extern const int NETERR_TCP_OPERATION_UNKNOWN;

extern const int NETERR_UDP_SUCCESS;
extern const int NETERR_UDP_FAIL;
extern const int NETERR_UDP_CONNECTION_CLOSED;
extern const int NETERR_UDP_CONNECTION_BUSY;
extern const int NETERR_UDP_ADDRESSINUSE;
extern const int NETERR_UDP_ADDRESSERROR;
extern const int NETERR_UDP_PORT_UNREACHABLE;
extern const int NETERR_UDP_PROTOCOL_UNREACHABLE;
extern const int NETERR_UDP_HOST_UNREACHABLE;
extern const int NETERR_UDP_NETWORK_UNREACHABLE;
extern const int NETERR_UDP_MESSAGE_TOO_LONG;
extern const int NETERR_UDP_TTL_EXCEEDED;
extern const int NETERR_UDP_TIME_EXCEEDED;
extern const int NETERR_UDP_BUFFER_INVALID;
extern const int NETERR_UDP_OPERATION_INVALID; 
extern const int NETERR_UDP_OPERATION_UNKNOWN;
extern const int NETERR_UDP_WOULDBLOCK;



struct NetConnectionStruct {
    netMemberCallback   ConnectCallback;
    netMemberCallback   SendCallback;
    netMemberCallback   ReceiveCallback;
    netMemberCallback   CloseCallback;

    NetProtocol         Protocol;

    void*               This;             // Stores the class's 'this' pointer
    netCallbackCaller   Call;             // The class's static helper function

    antModuleRef        antEndpoint;
    IPAddress           LocalAddress;
    Port                LocalPort;
    IPAddress           RemoteAddress;
    Port                RemotePort;
    IPAddress           DestAddress;      // For UDP 'Bound' connections
    Port                DestPort;         // For UDP 'Bound' connections
    NetError            Error;
    antSharedBuffer     antSharedSend;    // Structures used to receive shared 
    antSharedBuffer     antSharedRecv;    // buffers from OPEN-R
    char*               SendBuffer;       // Assigned by system,
    char*               ReceiveBuffer;    // will point to shared buffers
    size_t              MinSend;    // Setting this > 0 will enable buffering
    size_t              MinReceive;
    size_t              MaxReceive;
    size_t              SendBufSize;
    size_t              RecvBufSize;

    bool                Listening;
    bool                Connected;
    bool                Sending;
    bool                Receiving;

    byte*               DroppedDataWarningPtr;
    size_t              DroppedDataWarningSize;

    int                 UserData;   // User can put custom index or pointer here

    char*               SendingStart; // |
    char*               SendingStop;  // | Used internally for send buffering
    size_t              SendingSize;  // |
    bool                SendFlush;    // used internally
    NetCloseMode        CloseMode;    // used internally
};


struct NetConnectionItemStruct {
    NetConnection                 Connection;
    struct NetConnectionItemStruct*  next;
};



                              /* Declarations: */


/* Declaration of global functions that will be implemented in EasyNet_defs.h */

NetConnection NetTCPConnect_Class(IPAddress addr, Port port,
                 netMemberCallback ConnectCallback, netMemberCallback SendCallback,
                 netMemberCallback ReceiveCallback, netMemberCallback CloseCallback,
                 size_t SendBufSize, size_t RecvBufSize,
                 void* ThisVoid, netCallbackCaller Call);

NetConnection NetTCPListen_Class(Port port,
                 netMemberCallback ConnectCallback, netMemberCallback SendCallback,
                 netMemberCallback ReceiveCallback, netMemberCallback CloseCallback,
                 size_t SendBufSize, size_t RecvBufSize,
                 void* ThisVoid, netCallbackCaller Call);

NetConnection NetUDPBind_Class(IPAddress addr, Port port,
                 netMemberCallback SendCallback, netMemberCallback ReceiveCallback,
                 size_t SendBufSize, size_t RecvBufSize,
                 void* ThisVoid, netCallbackCaller Call);

NetConnection NetUDPListen_Class(Port port,
                 netMemberCallback SendCallback, netMemberCallback ReceiveCallback,
                 size_t SendBufSize, size_t RecvBufSize,
                 void* ThisVoid, netCallbackCaller Call);

int NetSend(NetConnection Connection, const void *buf, size_t size);
int NetSend(NetConnection Connection, const void *buf);

int NetReceive(NetConnection Connection, void *buf, size_t min, size_t max);
inline int NetReceive(NetConnection Connection, size_t min, size_t max);
inline int NetReceive(NetConnection Connection, void* buf, size_t size);
inline int NetReceive(NetConnection Connection, size_t size);

inline void NetNextReceive(NetConnection Connection, size_t min, size_t max);
inline void NetNextReceive(NetConnection Connection, size_t size);

int NetClose(NetConnection Connection, NetCloseMode mode);
inline int NetClose(NetConnection Connection);





/* Macro for main object's declarations */

#define NET_DECLARATIONS \
public:\
typedef void (NET_OBJECT::*netObjCallback)(NetConnection, int);\
\
private:\
static const netObjCallback BLOCK_CONNECT;\
static const netObjCallback BLOCK_LISTEN;\
static const netObjCallback BLOCK_SEND;\
static const netObjCallback BLOCK_RECEIVE;\
static const netObjCallback BLOCK_CLOSE;\
\
public:\
void Net_ConnectCont(ANTENVMSG msg);\
void Net_SendCont   (ANTENVMSG msg);\
void Net_ReceiveCont(ANTENVMSG msg);\
void Net_CloseCont  (ANTENVMSG msg);\
\
NetConnection NetTCPConnect(IPAddress addr, Port port,\
                 netObjCallback ConnectCallback, netObjCallback SendCallback,\
                 netObjCallback ReceiveCallback, netObjCallback CloseCallback,\
                 size_t SendBufSize, size_t RecvBufSize);\
inline NetConnection NetTCPConnect(IPAddress addr, Port port,\
                 netObjCallback ConnectCallback, netObjCallback SendCallback,\
                 netObjCallback ReceiveCallback, netObjCallback CloseCallback);\
NetConnection NetTCPListen(Port port,\
                 netObjCallback ConnectCallback, netObjCallback SendCallback,\
                 netObjCallback ReceiveCallback, netObjCallback CloseCallback,\
                 size_t SendBufSize, size_t RecvBufSize);\
inline NetConnection NetTCPListen(Port port,\
                 netObjCallback ConnectCallback, netObjCallback SendCallback,\
                 netObjCallback ReceiveCallback, netObjCallback CloseCallback);\
\
NetConnection NetUDPBind(IPAddress addr, Port port,\
                 netObjCallback SendCallback, netObjCallback ReceiveCallback,\
                 size_t SendBufSize, size_t RecvBufSize);\
inline NetConnection NetUDPBind(IPAddress addr, Port port,\
                 netObjCallback SendCallback, netObjCallback ReceiveCallback);\
NetConnection NetUDPListen(Port port,\
                 netObjCallback SendCallback, netObjCallback ReceiveCallback,\
                 size_t SendBufSize, size_t RecvBufSize);\
inline NetConnection NetUDPListen(Port port,\
                 netObjCallback SendCallback, netObjCallback ReceiveCallback);





/* Macro for class support */

#define ADD_NETWORK_SUPPORT(CLASS) \
\
typedef void (CLASS::*LocalCallback)(NetConnection, int);\
\
static const LocalCallback BLOCK_CONNECT = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
static const LocalCallback BLOCK_LISTEN  = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
static const LocalCallback BLOCK_SEND    = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
static const LocalCallback BLOCK_RECEIVE = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
static const LocalCallback BLOCK_CLOSE   = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
\
static void Net_Call(netMemberCallback FuncToCall, NetConnection Conn, int Bytes) {\
    (reinterpret_cast<CLASS*>(Conn->This)->*reinterpret_cast<LocalCallback>(FuncToCall))\
                                                                          (Conn, Bytes);\
}\
\
inline NetConnection NetTCPConnect(IPAddress addr, Port port,\
                 LocalCallback ConnectCallback, LocalCallback SendCallback,\
                 LocalCallback ReceiveCallback, LocalCallback CloseCallback,\
                 size_t SendBufSize, size_t RecvBufSize) {\
\
    return NetTCPConnect_Class(addr, port,\
                               reinterpret_cast<netMemberCallback>(ConnectCallback),\
                               reinterpret_cast<netMemberCallback>(SendCallback),\
                               reinterpret_cast<netMemberCallback>(ReceiveCallback),\
                               reinterpret_cast<netMemberCallback>(CloseCallback),\
                               SendBufSize, RecvBufSize,\
                               reinterpret_cast<void*>(this), &CLASS::Net_Call);\
};\
\
inline NetConnection NetTCPConnect(IPAddress addr, Port port,\
                 LocalCallback ConnectCallback, LocalCallback SendCallback,\
                 LocalCallback ReceiveCallback, LocalCallback CloseCallback) {\
\
    return NetTCPConnect(addr, port, ConnectCallback, SendCallback, ReceiveCallback,\
                         CloseCallback, 8192, 8192);\
};\
\
inline NetConnection NetTCPListen(Port port,\
                 LocalCallback ConnectCallback, LocalCallback SendCallback,\
                 LocalCallback ReceiveCallback, LocalCallback CloseCallback,\
                 size_t SendBufSize, size_t RecvBufSize) {\
\
    return NetTCPListen_Class(port,\
                               reinterpret_cast<netMemberCallback>(ConnectCallback),\
                               reinterpret_cast<netMemberCallback>(SendCallback),\
                               reinterpret_cast<netMemberCallback>(ReceiveCallback),\
                               reinterpret_cast<netMemberCallback>(CloseCallback),\
                               SendBufSize, RecvBufSize,\
                               reinterpret_cast<void*>(this), &CLASS::Net_Call);\
};\
\
inline NetConnection NetTCPListen(Port port,\
                 LocalCallback ConnectCallback, LocalCallback SendCallback,\
                 LocalCallback ReceiveCallback, LocalCallback CloseCallback) {\
\
    return NetTCPListen(port, ConnectCallback, SendCallback, ReceiveCallback,\
                         CloseCallback, 8192, 8192);\
};\
\
\
\
inline NetConnection NetUDPBind(IPAddress addr, Port port,\
                 LocalCallback SendCallback, LocalCallback ReceiveCallback,\
                 size_t SendBufSize, size_t RecvBufSize) {\
\
    return NetUDPBind_Class(addr, port,\
                               reinterpret_cast<netMemberCallback>(SendCallback),\
                               reinterpret_cast<netMemberCallback>(ReceiveCallback),\
                               SendBufSize, RecvBufSize,\
                               reinterpret_cast<void*>(this), &CLASS::Net_Call);\
};\
\
inline NetConnection NetUDPBind(IPAddress addr, Port port,\
                 LocalCallback SendCallback, LocalCallback ReceiveCallback) {\
\
    return NetUDPBind(addr, port, SendCallback, ReceiveCallback, 8192, 8192);\
};\
\
inline NetConnection NetUDPListen(Port port,\
                 LocalCallback SendCallback, LocalCallback ReceiveCallback,\
                 size_t SendBufSize, size_t RecvBufSize) {\
\
    return NetUDPListen_Class(port,\
                               reinterpret_cast<netMemberCallback>(SendCallback),\
                               reinterpret_cast<netMemberCallback>(ReceiveCallback),\
                               SendBufSize, RecvBufSize,\
                               reinterpret_cast<void*>(this), &CLASS::Net_Call);\
};\
\
inline NetConnection NetUDPListen(Port port,\
                 LocalCallback SendCallback, LocalCallback ReceiveCallback) {\
\
    return NetUDPListen(port, SendCallback, ReceiveCallback, 8192, 8192);\
};













/* Macro for class support */

#define ADD_NETWORK_SUPPORT_3_3(CLASS) \
\
typedef void (CLASS::*LocalCallback)(NetConnection, int);\
\
static const LocalCallback BLOCK_CONNECT;\
static const LocalCallback BLOCK_LISTEN;\
static const LocalCallback BLOCK_SEND;\
static const LocalCallback BLOCK_RECEIVE;\
static const LocalCallback BLOCK_CLOSE;\
\
static void Net_Call(netMemberCallback FuncToCall, NetConnection Conn, int Bytes) {\
    (reinterpret_cast<CLASS*>(Conn->This)->*reinterpret_cast<LocalCallback>(FuncToCall))\
                                                                          (Conn, Bytes);\
}\
\
inline NetConnection NetTCPConnect(IPAddress addr, Port port,\
                 LocalCallback ConnectCallback, LocalCallback SendCallback,\
                 LocalCallback ReceiveCallback, LocalCallback CloseCallback,\
                 size_t SendBufSize, size_t RecvBufSize) {\
\
    return NetTCPConnect_Class(addr, port,\
                               reinterpret_cast<netMemberCallback>(ConnectCallback),\
                               reinterpret_cast<netMemberCallback>(SendCallback),\
                               reinterpret_cast<netMemberCallback>(ReceiveCallback),\
                               reinterpret_cast<netMemberCallback>(CloseCallback),\
                               SendBufSize, RecvBufSize,\
                               reinterpret_cast<void*>(this), &CLASS::Net_Call);\
};\
\
inline NetConnection NetTCPConnect(IPAddress addr, Port port,\
                 LocalCallback ConnectCallback, LocalCallback SendCallback,\
                 LocalCallback ReceiveCallback, LocalCallback CloseCallback) {\
\
    return NetTCPConnect(addr, port, ConnectCallback, SendCallback, ReceiveCallback,\
                         CloseCallback, 8192, 8192);\
};\
\
inline NetConnection NetTCPListen(Port port,\
                 LocalCallback ConnectCallback, LocalCallback SendCallback,\
                 LocalCallback ReceiveCallback, LocalCallback CloseCallback,\
                 size_t SendBufSize, size_t RecvBufSize) {\
\
    return NetTCPListen_Class(port,\
                               reinterpret_cast<netMemberCallback>(ConnectCallback),\
                               reinterpret_cast<netMemberCallback>(SendCallback),\
                               reinterpret_cast<netMemberCallback>(ReceiveCallback),\
                               reinterpret_cast<netMemberCallback>(CloseCallback),\
                               SendBufSize, RecvBufSize,\
                               reinterpret_cast<void*>(this), &CLASS::Net_Call);\
};\
\
inline NetConnection NetTCPListen(Port port,\
                 LocalCallback ConnectCallback, LocalCallback SendCallback,\
                 LocalCallback ReceiveCallback, LocalCallback CloseCallback) {\
\
    return NetTCPListen(port, ConnectCallback, SendCallback, ReceiveCallback,\
                         CloseCallback, 8192, 8192);\
};\
\
\
\
inline NetConnection NetUDPBind(IPAddress addr, Port port,\
                 LocalCallback SendCallback, LocalCallback ReceiveCallback,\
                 size_t SendBufSize, size_t RecvBufSize) {\
\
    return NetUDPBind_Class(addr, port,\
                               reinterpret_cast<netMemberCallback>(SendCallback),\
                               reinterpret_cast<netMemberCallback>(ReceiveCallback),\
                               SendBufSize, RecvBufSize,\
                               reinterpret_cast<void*>(this), &CLASS::Net_Call);\
};\
\
inline NetConnection NetUDPBind(IPAddress addr, Port port,\
                 LocalCallback SendCallback, LocalCallback ReceiveCallback) {\
\
    return NetUDPBind(addr, port, SendCallback, ReceiveCallback, 8192, 8192);\
};\
\
inline NetConnection NetUDPListen(Port port,\
                 LocalCallback SendCallback, LocalCallback ReceiveCallback,\
                 size_t SendBufSize, size_t RecvBufSize) {\
\
    return NetUDPListen_Class(port,\
                               reinterpret_cast<netMemberCallback>(SendCallback),\
                               reinterpret_cast<netMemberCallback>(ReceiveCallback),\
                               SendBufSize, RecvBufSize,\
                               reinterpret_cast<void*>(this), &CLASS::Net_Call);\
};\
\
inline NetConnection NetUDPListen(Port port,\
                 LocalCallback SendCallback, LocalCallback ReceiveCallback) {\
\
    return NetUDPListen(port, SendCallback, ReceiveCallback, 8192, 8192);\
};






#define ADD_NETWORK_CONSTANTS_3_3(CLASS) \
\
const CLASS::LocalCallback CLASS::BLOCK_CONNECT = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
const CLASS::LocalCallback CLASS::BLOCK_LISTEN  = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
const CLASS::LocalCallback CLASS::BLOCK_SEND    = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
const CLASS::LocalCallback CLASS::BLOCK_RECEIVE = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);\
const CLASS::LocalCallback CLASS::BLOCK_CLOSE   = reinterpret_cast<LocalCallback>(&Net_Class::Block_Dummy_Func);


/* End of declarations */

#endif // EasyNet_macro_h_DEFINED




/*
---------------------------------------------------------------
int NetReceiveToChar(NetConnection Connection, char c, char* buf, size_t max);\
inline int NetReceiveToChar(NetConnection Connection, char c, char* buf);\
inline int NetReceiveStr(NetConnection Connection, char* buf);\
inline int NetReceiveStr(NetConnection, char* buf);\
*/













