/***************************************************************
* PrDataInput.cpp
*
* This is an implementation of DataInput methods.
*
****************************************************************/

/*
* modification history
*----------------------
*
* 02/13/98: K.C. Chang: created.
*/

#include "PrDataInput.h"
#include "PrSocket.h"

#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <sys/time.h>
#include <sys/select.h>

#include <unistd.h>
#include <sys/ioctl.h>


PrDataInput::PrDataInput( PrSocket *socket, int bufferSize )
: size_( 0 )
{
   socketFD_ = socket->socketFD();
   Init(bufferSize);
}

PrDataInput::~PrDataInput()
{
   delete[] buffer_;
}

void PrDataInput::bufferSize(int nbytes)
{
   delete[] buffer_;
   Init(nbytes);
}

int PrDataInput::select( long msec )
{
   fd_set r,w;
   struct timeval timeout;

   FD_ZERO(&r);
   FD_ZERO(&w);
   FD_SET(socketFD_, &r);
   timeout.tv_sec=(long)(msec / 1000);
   timeout.tv_usec=(long)(msec - timeout.tv_sec*1000)*1000;
   if (::select(socketFD_ + 1, &r, &w, (fd_set *) 0, &timeout) < 0)
      perror("PrDataInput: select() error");
   if (FD_ISSET(socketFD_, &r)) return 1;
   else return 0;
}

// returns number of data bytes.
int PrDataInput::ready()
{
   size_ = 0;
   if (readSize_ == 1)
   {
      char s[2];
      if (Peek(s,2) < 2)
         return -1;
      size_ = Unpack2B(s);
      //fprintf(stderr, "got message of size %d\n", size_);
      memset(buffer_,'\0',bufferSize_);
      InitByteCounter();
      readSize_ = 0;
   }

   if (Peek() < size_ )
      return -1;

   if (Receive() != size_)
   {
      perror("PrDataInput: ready() error");
      return PR_DATAINPUT_ERROR;
   }

   //type_ = Unpack2B(buffer_+2);

   readSize_ = 1;
   return size_;// - InitByteCounter());
}

CMappedMsg PrDataInput::GetMsg()
{
   CMappedMsg msg;
   msg.SetMsg( buffer_, size_ );
   return msg;
}

/*
// p280 in UNIX Network Programming by Stevens
int PrDataInput::readLine( char *ptr, int maxlen )
{
int n,rc;
char c;

for(n=1;n<maxlen;n++)
{
if ((rc=recv(socketFD_,&c,1,0))==1)
{
*ptr++ = c; 
if(c=='\n') 
break;
} else if (rc == 0) 
{
if (n==1) return(0);	// EOF, no data read
else break;		// EOF, some data was read
} 
else return (-1);		// error 
}
*ptr = 0;
return(n);
}
*/

// little endian
//   [0] [1] [2] [3]
//    1   0   0   0
// big endian
//   [0] [1] [2] [3]
//    0   0   0   1
/*int PrDataInput::Endian()
{
int aint=1;
char *cptr = (char *)&aint;
if (*cptr == '\0')
return PR_BIG_ENDIAN; // 1 => big endian
else
return PR_LITTLE_ENDIAN;
}*/

void PrDataInput::Init(int nbytes)
{
   //endian_ = Endian();

   bufferSize_ = nbytes + InitByteCounter();
   buffer_ = new char[bufferSize_];

   memset(buffer_,'\0',bufferSize_);
   readSize_ = 1;
}

// p279 in UNIX Network Programming by Stevens
int PrDataInput::Receive()
{
   char *ptr = buffer_;

   int nleft,nread;
   nleft = size_;
   while(nleft>0)
   {
      nread = recv(socketFD_,ptr,nleft,0);
      if(nread<0) return (nread); /* error */
      else if(nread==0) break; /* EOF */
      nleft -= nread;
      ptr += nread;
   }
   return(size_ - nleft);  // return >= 0
}

int PrDataInput::Peek()
{
   int arg=0;

#ifdef PR_QNX
   if (ioctl((short)socketFD_,FIONREAD,&arg)<0)
#else // PR_QNX
   if (ioctl(socketFD_,FIONREAD,&arg)<0)
#endif // PR_QNX
   {
      perror("PrDataInput::Peek():ioctl() error");
      arg = -1;
   }

   //        fprintf( stderr, "peek %d\n", arg );
   return arg;
}

int PrDataInput::Peek( char *buff, int nbytes )
{
   int arg = Peek();
   if (arg >= nbytes)
   {
      if (recv(socketFD_,buff,nbytes,MSG_PEEK)!=nbytes)
      {
         perror("PrDataInput::Peek():recv() error");
         arg = -1;
      }
   }
   return arg;
}

/*
int PrDataInput::Peek( char *buff, int nbytes )
{
if (select(0)==0)
return -1;
int n=recv(socketFD_,buff,nbytes,MSG_PEEK);
//    printf("peek=%d\n",n);
if (n==nbytes)
return nbytes;
else
return -1;
}
*/


inline short PrDataInput::Unpack2B( char *text )
{
   return ntohs(*(short *)text);
   //return *(short *)text;
}

