#include "tcp_stream6.h"

using namespace std;
using namespace net_tools;

static const size_t IO_BUFFER_SIZE = 1024;

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

   _error = false;

   _fd = fd;

   memset(_buffer, 0, IO_BUFFER_SIZE);

   _ip_address = "";

   _port = 0;
}

int
tcp_connect(const char * host, const char * serv)
{
   int sockfd;
   struct addrinfo hints,*res,*ressave;
   bzero(&hints,sizeof(struct addrinfo));
   hints.ai_family = AF_INET6;
   hints.ai_socktype = SOCK_STREAM;
   getaddrinfo(host, serv, &hints, &res);
   ressave = res;
   do {
      sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
      if(sockfd < 0) continue;
      if(connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
         break;
      close(sockfd);
   }
   while((res = res->ai_next) != 0);
   freeaddrinfo(ressave);
   return sockfd;
}

tcp_stream6::tcp_stream6(const char * ip_address, 
                         const int port)
{
   _open = true;

   _error = false;

   _fd = 0;

   memset(_buffer, 0, IO_BUFFER_SIZE);

   _ip_address = ip_address;

   _port = port;

   char serv[20];
   
   sprintf(serv, "%d", _port);

   _fd = tcp_connect(_ip_address, serv);

   if(_fd <= 0) _error = true;
}

tcp_stream6::~tcp_stream6()
{
   if(_open) {
      ::close(_fd);
      _open = false;
   }
}

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

   memset(_buffer, 0, IO_BUFFER_SIZE);
}

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

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

   return p;
}

tcp_stream6 & tcp_stream6::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_stream6 & tcp_stream6::operator<<(const char * str)
{
   int sz = strlen(str);
   if(send(_fd, str, sz, 0) != sz) {
      _error = true;
   }
   return *this;
}

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

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

tcp_stream6 & tcp_stream6::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_stream6::get() 
{
   char ch = '\0';

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

   return ch;
}

void tcp_stream6::close() 
{
   if(_open) {
      ::close(_fd);
      _open = false;
   }
}
