/* 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.
  ========================================================================= */

//
//
//  EasyNet.h - by Francesco Tamburrino, Carnegie Mellon University 
//  v 2.0a, 24 March 2004
//
//

#ifndef EasyNet_h_DEFINED
#define EasyNet_h_DEFINED



#include <Types.h>
#include <entry.h>
#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.cc */

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);

NetConnection NetDoTCPConnect (NetConnection Connection, IPAddress addr, Port port);
NetConnection NetDoTCPListen  (NetConnection Connection, Port port);
NetConnection NetDoUDPBind    (NetConnection Connection, IPAddress addr, Port port);
NetConnection NetDoUDPListen  (NetConnection Connection, Port port);

void NetDoConnectCont (ANTENVMSG msg);
void NetDoSendCont    (ANTENVMSG msg);
void NetDoReceiveCont (ANTENVMSG msg);
void NetDoCloseCont   (ANTENVMSG msg);

/* Global error variable implemented in EasyNet.cc */

extern NetError NetLastError;



// In order to be compiled as "inline", the following functions (declared above)
// must be defined here (in the same file in which they are declared):


inline int NetReceive (NetConnection Connection, size_t min, size_t max)
{
    return NetReceive (Connection, NULL, min, max);   
}


inline int NetReceive (NetConnection Connection, void* buf, size_t size)
{
    return NetReceive (Connection, buf, size, size);
}


inline int NetReceive (NetConnection Connection, size_t size)
{
    return NetReceive (Connection, NULL, size, size);
}


inline void NetNextReceive (NetConnection Connection, size_t min, size_t max)
{
    Connection->MinReceive = min;
    Connection->MaxReceive = max;
}


inline void NetNextReceive (NetConnection Connection, size_t size)
{
    Connection->MinReceive = Connection->MaxReceive = size;
}


inline int NetClose(NetConnection Connection)
{
    return NetClose(Connection, CLOSE_CLEAN_ABORT);
}




template <class T>
class NetClass {

protected:

    // LocalCallback typedef

    typedef void (T::*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<T*>(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), &T::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), &T::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), &T::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), &T::Net_Call);
    }

    // -----------------


    inline NetConnection NetUDPListen(Port port,
                         LocalCallback SendCallback, LocalCallback ReceiveCallback) {

        return NetUDPListen(port, SendCallback, ReceiveCallback, 8192, 8192);
    }


}; // End of NetClass declaration





template <class T>
class NetObject: public NetClass<T> {

public:

    inline void Net_ConnectCont(ANTENVMSG msg) {
        return NetDoConnectCont(msg);
    }

    inline void Net_SendCont(ANTENVMSG msg) {
        return NetDoSendCont(msg);
    }

    inline void Net_ReceiveCont(ANTENVMSG msg) {
        return NetDoReceiveCont(msg);
    }

    inline void Net_CloseCont(ANTENVMSG msg) {
        return NetDoCloseCont(msg);
    }

};




// Initialization of blocking constants for behaviors (NetClass)

template <class T> const typename NetClass<T>::LocalCallback NetClass<T>::BLOCK_CONNECT =
        reinterpret_cast<typename NetClass<T>::LocalCallback>(&Net_Class::Block_Dummy_Func);
template <class T> const typename NetClass<T>::LocalCallback NetClass<T>::BLOCK_LISTEN  =
        reinterpret_cast<typename NetClass<T>::LocalCallback>(&Net_Class::Block_Dummy_Func);
template <class T> const typename NetClass<T>::LocalCallback NetClass<T>::BLOCK_SEND    =
        reinterpret_cast<typename NetClass<T>::LocalCallback>(&Net_Class::Block_Dummy_Func);
template <class T> const typename NetClass<T>::LocalCallback NetClass<T>::BLOCK_RECEIVE =
        reinterpret_cast<typename NetClass<T>::LocalCallback>(&Net_Class::Block_Dummy_Func);
template <class T> const typename NetClass<T>::LocalCallback NetClass<T>::BLOCK_CLOSE   =
        reinterpret_cast<typename NetClass<T>::LocalCallback>(&Net_Class::Block_Dummy_Func);



#endif // EasyNet_h_DEFINED


