#include "tcp_stream.h"

using namespace std;
using namespace net_tools;

static const size_t IO_BUFFER_SIZE = 1024;

tcp_stream::tcp_stream(int fd)
{
   _open = true;

   _error = false;

   _fd = fd;

   memset(_buffer, 0, IO_BUFFER_SIZE);

   _ip_address = "";

   _port = 0;
}

tcp_stream::tcp_stream(const char * ip_address, 
           const int port)
{
   hostent * p_host = gethostbyname(ip_address);

   if(p_host != NULL) {
      ip_address =  inet_ntoa(*(in_addr*)(p_host->h_addr));
   }

   _open = true;

   _error = false;

   _fd = 0;

   memset(_buffer, 0, IO_BUFFER_SIZE);

   _ip_address = ip_address;

   _port = port;

   sockaddr_in sock_data;

   int sz = sizeof(sock_data);

   memset((char*)(&sock_data), 0, sizeof(sock_data));

   sock_data.sin_family = AF_INET;
   memcpy(&(sock_data.sin_addr.s_addr), p_host->h_addr, p_host->h_length);
   sock_data.sin_port = htons(_port);

   if((_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
      _error = true;
   }

   if(connect(_fd, (sockaddr*)(&sock_data), sz) < 0) {
      _error = true;
   }
}

tcp_stream::~tcp_stream()
{
   if(_open) {
#ifdef OS_WINDOWS
      ::closesocket(_fd);
#endif
#ifdef OS_UNIX
      ::close(_fd);
#endif
      _open = false;
   }
}

void tcp_stream::clearerr()
{
   _error = false;

   memset(_buffer, 0, IO_BUFFER_SIZE);
}

tcp_stream::operator void*()
{
   void * p;

   if(_error && _open) {
      p = (void*)(0U);
   }         
   else {
      p = (void*)(1U);
   }

   return p;
}

tcp_stream & tcp_stream::operator<<(int i) 
{
   memset(_buffer, 0, IO_BUFFER_SIZE);

   sprintf(_buffer, "%d", i);

   int sz = strlen(_buffer);

   if(send(_fd, _buffer, sz, 0) != sz) {
      _error = true;
   }

   return *this;
}

tcp_stream & tcp_stream::operator<<(const char * str)
{
   int sz = strlen(str);
   if(send(_fd, str, sz, 0) != sz) {
      _error = true;
   }
   return *this;
}

tcp_stream & tcp_stream::operator<<(const string & str)
{
   if(send(_fd, str.c_str(), str.size(), 0) != static_cast< int >(str.size())) {
      _error = true;
   }
   return *this;
}

tcp_stream & tcp_stream::operator>>(string & str)
{
   char ch;
   str = "";
   while(recv(_fd, &ch, 1, 0) == 1) {
      if(isspace(ch)) {
         break;
      }
      str += ch;
   }
   return *this;
}

tcp_stream & tcp_stream::operator>>(int & i)
{
   char ch;

   if(recv(_fd, &ch, 1, 0) != 1) {
      _error = true;
   }

   while(isspace(ch)) {
      if(recv(_fd, &ch, 1, 0) != 1) {
         _error = true;
      }
   }   

   string temp;

   while(isdigit(ch)) {
      temp += ch;
 
      if(recv(_fd, &ch, 1, 0) != 1) {
         _error = true;
      }
   }

   i = atoi(temp.c_str());

   return *this;
}

char tcp_stream::get() 
{
   char ch = '\0';

   if(recv(_fd, &ch, 1, 0) != 1) {
      _error = true;
   }

   return ch;
}

void tcp_stream::close() 
{
   if(_open) {
#ifdef OS_WINDOWS
      ::closesocket(_fd);
#endif
#ifdef OS_UNIX
      ::close(_fd);
#endif
      _open = false;
   }
}
