/*

TCP/IP IOStreams like class.

Use a template member function with a data stream class as the template
type. pipe_stream, iostream, fstream, tcp_stream and others.

Author: Matthew W. Coan
Date: Fri Jun 18 14:04:57 EDT 2010
 
*/

#ifndef _TCP_STREAM_H
#define _TCP_STREAM_H

//#define OS_UNIX
#ifndef OS_WINDOWS
#define OS_WINDOWS
#endif

#ifdef OS_UNIX
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <netdb.h>
#endif 

#ifdef OS_WINDOWS
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <assert.h>
#endif

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>

namespace net_tools {

using namespace std;

static const size_t IO_BUFFER_SIZE = 1024;

class tcp_stream {
   bool _error;
   SOCKET _fd;
   char _buffer[IO_BUFFER_SIZE];
   string _ip_address;
   int _port;
   bool _open;

public:
   tcp_stream(SOCKET fd);

   tcp_stream(const string & ip_address, 
              const int port,
              const int tval = 5);


   virtual ~tcp_stream();

   void clearerr();

   operator void*();

   tcp_stream & operator<<(char ch);

   tcp_stream & operator<<(int i);

   tcp_stream & operator<<(const char * str);

   tcp_stream & operator<<(const string & str);

   tcp_stream & operator>>(string & str);

   tcp_stream & operator>>(int & i);

   char get();

   void write(const char * ptr, size_t sz) {
      if(send(_fd, ptr, sz, 0) != sz)
         _error = true;
   }

   void read(char * ptr, size_t sz) {
      if(recv(_fd, ptr, sz, 0) != sz)
         _error = true;
   }   

   SOCKET get_fd() {
      return _fd;
   }

   string read_line(size_t max = 1024) {
      string line;

      char ch = get();

      while(*this) {
         if(ch == '\n')
            break;

         line += ch;

         if(line.size() >= max)
            break;

         ch = get();
      }
  
      return line;
   }

   void close();

   bool get_error() {
      return _error || _fd == INVALID_SOCKET;
   }
};

}

#endif /* _TCP_STREAM_H */
