/*****************************************************************************\
 *
 * TNet.h
 *
 * Author: PCJohn (peciva _AT fit.vutbr.cz)
 *
 * Contributors:
 *
 * ----------------------------------------------------------------------------
 *
 * THIS SOFTWARE IS NOT COPYRIGHTED
 *
 * This source code is offered for use in the public domain.
 * You may use, modify or distribute it freely.
 *
 * This source code is distributed in the hope that it will be useful but
 * WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
 * DISCLAIMED.  This includes but is not limited to warranties of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * If you find the source code useful, authors will kindly welcome
 * if you give them credit and keep their names with their source code,
 * but do not feel to be forced to do so.
 *
\*****************************************************************************/

#ifndef TNET_H_INCLUDED_
#define TNET_H_INCLUDED_

#ifdef COIN_INTERNAL // Are we compiled inside Coin?
#include <Inventor/C/basic.h>
typedef int bool_t;
#define TNET_DLL_API COIN_DLL_API
#else
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef int bool_t;
#define TNET_DLL_API
#endif


class TNET_DLL_API TNAddr {
public:
  TNAddr() {}
  TNAddr(ip_t ip, port_t port = 0);
  TNAddr(const TNAddr &a);

  void setIP(ip_t ip);
  ip_t getIP() const;
  void setPort(port_t port);
  port_t getPort() const;

  bool_t setIP(const char *s, char **endp);
  bool_t setPort(const char *s, char **endp);
  bool_t setAddr(const char *s, char **endp);
  std::string getIP() const;
  std::string getPort() const;
  std::string getAddr() const;

  bool_t dnsConvertFromStr(const char *s);
  std::string dnsConvertToStr() const;

  TNAddr& operator=(const TNAddr &a) const;
  TNAddr& operator==(const TNAddr &a) const;
  TNAddr& operator!=(const TNAddr &a) const;

protected:
  ip_t ip;
  port_t port;
};


class TNET_DLL_API TNConnection { // or TnConnection, TNSocket, TNetStream
public:
  virtual void send(const void *buf, unsigned int bufsize);
  virtual int recv(void *buf, int bufsize);

  virtual void connect(TNAddr remoteAddr, TNAddr localAddr = TNAddr(0,0));
  virtual void close();

  enum State { CONNECTING = 1, CONNECTED = 2, TN_DISCONNECTING = 3,
               TN_DISCONNECTED = -1, TN_BROKEN = -2, TN_LISTENING = 4 };

  virtual State updateState();
  virtual State getState();

  enum Property { BLOCKING_MODE = 0x01, NO_BLOCKING_MODE = 0x02,
                  NAGLE_DELAY = 0x04, NO_DELAY = 0x08,
                  EXCLUSIVE_ADDR = 0x10, REUSE_ADDR = 0x20,
                  SOCKET = 0x1000, ERROR_CODE,
                  TN_PEER_IP, TN_PEER_PORT, TN_LOCAL_IP, TN_LOCAL_PORT,
                  TN_SEND_BUFFER_SIZE, TN_RECV_BUFFER_SIZE,
                  TN_APP_BUFFER_SIZE, TN_LATENCY, TN_LATENCY_DISPERSION,
                  TN_GLOBAL_LATENCY, TN_GLOBAL_LATENCY_DISPERSION,
                  TN_NUM_CONNECTIONS, TN_BYTES_SENT, TN_BYTES_RECEIVED,
                  TN_TOTAL_BYTES_SENT, TN_TOTAL_BYTES_RECEIVED };

  virtual int get(Property param);
  virtual void set(Property param, int value);

  TNConnection();
  virtual ~TNConnection();

  // global functions
  static int get(Property param);
  static void set(Property param, int value);
  static list<ip_t> getLocalIPAddress();

  // initialization
  enum ErrorSeverity { SEV_ERROR = 0, SEV_INFO };
  typedef void ErrorCb(enum ErrorSeverity severity, Connection *c, const char *str, int errorCode);
  static bool_t init();
  static bool_t initDebug(ErrorCb *cb, int debugLevel);
  static void cleanUp();
};


class TNET_DLL_API TNTcpConnection : public TNConnection {
public:
  virtual void send(const void *buf, unsigned int bufsize);
  virtual int recv(void *buf, int bufsize);

  virtual void connect(TNAddr remoteAddr, TNAddr localAddr = TNAddr(0,0));
  virtual void listen(port_t port);
  virtual void listen(TNAddr localAddr);
  virtual TNConnection* accept();
  virtual void disconnect();
  virtual void close();

  virtual State updateState();
  virtual State getState();

  virtual int get(Property param);
  virtual void set(Property param, int value);

  TNTcpConnection();
  TNTcpConnection();
  virtual ~TNTcpConnection();
};


class TNET_DLL_API TNUdpConnection : public TNConnection {
public:
  virtual void send(const void *buf, unsigned int bufsize);
  virtual int recv(void *buf, int bufsize);

  virtual void connect(TNAddr remoteAddr, TNAddr localAddr = TNAddr(0,0));
  virtual void close();

  virtual State updateState();
  virtual State getState();

  virtual int get(Property param);
  virtual void set(Property param, int value);

  TNTcpConnection();
  virtual ~TNTcpConnection();
};



#ifdef COIN_INTERNAL // Are we compiled inside Coin?
#include <Inventor/C/basic.h>
typedef int bool_t;
#define TNET_DLL_API COIN_DLL_API
#else
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef int bool_t;
#define TNET_DLL_API
#endif


#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus */


typedef int32_t TNConnection;
typedef uint32_t ip_t;
typedef uint16_t port_t;
enum TNState { TN_FREE = 0, TN_CONNECTING = 1, TN_CONNECTED = 2,
    TN_DISCONNECTING = 3, TN_DISCONNECTED = -1, TN_BROKEN = -2, TN_LISTENING = 4};


// send/receive functions
TNET_DLL_API void tnSend(TNConnection c, const void *buf, unsigned int bufsize);
TNET_DLL_API int tnRecv(TNConnection c, void *buf, int bufsize);


// connecting and disconnecting functions
TNET_DLL_API TNConnection tnConnect(ip_t remoteIP, port_t remotePort, port_t localPort);
TNET_DLL_API TNConnection tnListen(port_t port);
TNET_DLL_API TNConnection tnAccept(TNConnection lc);
TNET_DLL_API void tnDisconnect(TNConnection c);
TNET_DLL_API void tnClose(TNConnection c);


// multi-homed functions
TNET_DLL_API TNConnection tnConnectFromIP(ip_t remoteIP, port_t remotePort, ip_t localIP, port_t localPort);
TNET_DLL_API TNConnection tnListenOnIP(ip_t ip, port_t port);


// state reporting functions
TNET_DLL_API enum TNState tnGetState(TNConnection c);
TNET_DLL_API enum TNState tnPeekState(TNConnection c);


// constants for tnGet and tnSet functions
#define TN_SOCKET      0x01
#define TN_PEER_IP     0x02
#define TN_PEER_PORT   0x03
#define TN_LOCAL_IP    0x04
#define TN_LOCAL_PORT  0x05
#define TN_ERROR       0x06

#define TN_SEND_BUFFER_SIZE   0x10
#define TN_RECV_BUFFER_SIZE   0x11
#define TN_APP_BUFFER_SIZE    0x12

#define TN_LATENCY                    0x13
#define TN_LATENCY_DISPERSION         0x14
#define TN_GLOBAL_LATENCY             0x15
#define TN_GLOBAL_LATENCY_DISPERSION  0x16

#define TN_NUM_CONNECTIONS       0x20
#define TN_BYTES_SENT            0x21
#define TN_BYTES_RECEIVED        0x22
#define TN_TOTAL_BYTES_SENT      0x23
#define TN_TOTAL_BYTES_RECEIVED  0x24

TNET_DLL_API int tnGet(int param, TNConnection c);
TNET_DLL_API void tnSet(int param, TNConnection c, int value);


// environment functions
TNET_DLL_API ip_t* tnGetLocalIPAddresses();
TNET_DLL_API void tnFreeMem(void *ptr);


// initialization
enum TNErrorSeverity { TN_SEV_ERROR = 0, TN_SEV_INFO };
typedef void TNErrorCb(enum TNErrorSeverity severity, TNConnection c, const char *str, int errorCode);
TNET_DLL_API bool_t tnInit();
TNET_DLL_API bool_t tnInitDebug(TNErrorCb *cb, int debugLevel);
TNET_DLL_API void tnCleanUp();


// converting functions
TNET_DLL_API bool_t tnIP2Str(ip_t ip, char *buf, int bufsize);
TNET_DLL_API bool_t tnStr2IP(const char *s, ip_t *ip);
TNET_DLL_API bool_t tnReadIP(const char **s, ip_t *ip);


// future
TNET_DLL_API const char* tnError2Str(int err);
TNET_DLL_API const char* tnGetConnectionAdvInfo(TNConnection c);

// convenience function - FIXME: replace by tnPool()?
TNET_DLL_API void tnHandleDisconnects();


// configure sending - FIXME: merge with tnGet()
TNET_DLL_API bool_t tnIsSendBufferFull(TNConnection c);

// configure receiving - FIXME: merge with tnGet()
TNET_DLL_API int tnGetRecvDataSize(TNConnection c);


#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */

#endif /* TNET_H_INCLUDED_ */
