//*********************************************************************
// socket.h
// Copyright © 2002 Paul J Medlock
//*********************************************************************

#ifndef SOCKET_H
#define SOCKET_H

#ifndef FV_MSWIN32
   #include <netdb.h>
   #include <sys/types.h>
   #include <sys/socket.h>
   #include <sys/wait.h>
   #include <arpa/inet.h>
   #include <netinet/in.h>
   #include <unistd.h>
   #define SOCKET_ERROR -1

#else // FV_MSWIN32
   #include <winsock.h>
   typedef int socklen_t;

#endif // FV_MSWIN32

#ifndef FARBASE_H
#include "atom.h"
#include "strlist.h"
#endif

const short defaultPort    = 3490;
const short sizeSocketBuf  = 1024;

//*********************************************************************
//
_FBDEF(CSocket)
class FBC_USE CSocket: public CAtom {
   public:
      FB_USE CSocket(int _handle = SOCKET_ERROR, bool _blocking = true);
      virtual FB_USE ~CSocket();

      virtual FB_USE_(short) Ima(void);
      virtual FB_USE_(Pchar) IAm(void);
      virtual FB_USE_(bool)  Isa(const short _type);

      static bool   Initialize   (short _timeOut);
      static void   UnInitialize (void);

      FB_USE_(bool) ClientConnect(Pchar _host = 0, short _port = -1);
      FB_USE_(bool) ServerConnect(                 short _port = -1);
      FB_USE_(void) Disconnect   (void);

      FB_USE_(PCSocket) Accept   (void);

      FB_USE_(bool) IsConnected  (void);

      FB_USE_(int)   GetLastError(void);
      FB_USE_(Pchar) GetLastErrorMessage(void);

      FB_USE_(bool) SendQuit     (void);
      FB_USE_(bool) SendText     (Pchar _text, short _len);
      FB_USE_(bool) Sendf        (Pchar _frm, ...);

      FB_USE_(bool) Send         (Pchar    _msg, short  _len);
      FB_USE_(bool) Send         (RPCBlock _block);
      FB_USE_(bool) Send         (RPCList  _list);

      FB_USE_(ulong) GetAvailableSize(void);

      FB_USE_(ulong) Receive     (RPCBlock _msg, long _maxSize);

      FB_USE_(char)  GetChar     (bool  _block = false);
      FB_USE_(bool)  GetLine     (Pchar _line,
                                  short _size,
                                  bool  _block = false);

      FB_USE_(Pchar) GetName     (void);
      FB_USE_(short) GetPort     (void);

      FB_USE_(void) SError       (Pchar _caller);
      FB_USE_(void) Error        (Pchar _msg);

#ifdef FV_MSWIN32
      static Pchar GetErrorString(int _err);
#endif // FV_MSWIN32

   private:
      static short nrSocketsOpen;
      static short timeOut;

      bool blockSocket(bool _block);

      int   handle;
      Pchar name;
      short port;
      bool  blocking;
      Pchar lastError;
      int   errNo;
   }; // CSocket

//---------------------------------------------------------------------
//
inline bool CSocket::IsConnected(void) {
   return handle != SOCKET_ERROR;
   } // IsConnected

//---------------------------------------------------------------------
//
inline int CSocket::GetLastError(void) {
   return errNo;
   } // GetLastError

//---------------------------------------------------------------------
//
inline Pchar CSocket::GetLastErrorMessage(void) {
   return lastError;
   } // GetLastErrorMessage

//---------------------------------------------------------------------
//
inline bool CSocket::SendQuit(void) {
   return Send(0, 0);
   } // SendQuit

//---------------------------------------------------------------------
//
inline bool CSocket::SendText(Pchar _text, short _len) {
   return Send(_text, _len);
   } // SendText

//---------------------------------------------------------------------
//
inline bool CSocket::Sendf(Pchar _frm, ...) {
   if (!StrEmpty(_frm)) {
      // Print formatted message
      va_list args;
      va_start(args, _frm);
      char msg[sizeString];
      vsprintf(msg, _frm, args);
      va_end(args);
      Assert(strlen(msg) < sizeString);
      return Send(msg, short(strlen(msg) + 1));
      }
   return false;
   } // Sendf

//---------------------------------------------------------------------
//
inline Pchar CSocket::GetName(void) {
   return name;
   } // GetName

//---------------------------------------------------------------------
//
inline short CSocket::GetPort(void) {
   return port;
   } // GetPort

#endif // SOCKET_H