/////////////////////////////////////////////////////////////////////////////
// Name:        iobase.cpp
// Purpose:
// Author:      Joachim Buermann
// Id:          $Id: iobase.cpp,v 1.1.1.1 2004/11/24 10:30:11 jb Exp $
// Copyright:   (c) 2001 Joachim Buermann
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <string.h>
#include "ctb-0.14/iobase.h"
#include "ctb-0.14/timer.h"

#define DELTA_BUFSIZE 512 

int wxIOBase::Readv(char* buf,size_t len,unsigned int timeout_in_ms)
{
    char *cp = buf;
    int n = 0;
    int timeout = 0;
    size_t toread = len;

    timer t(timeout_in_ms,&timeout,NULL);
    if(timeout_in_ms != 0xFFFFFFFF) {
	   t.start();
    }

    while(!timeout && (toread > 0)) {
	   if((n = Read(cp,toread)) < 0) {
		  break;
	   }
	   if(!n) {
		  sleepms(1);
	   }
	   toread -= n;
	   cp += n;
    }
    // ok, all bytes received
    return (int)(len - toread);
}

/*
  Readv() calls the member function Read() repeatedly, til all
  demand bytes were received. To avoid an endless loop, you
  can refer an integer, which was set unequal zero after a
  specific time. (See the timer class)
*/
int wxIOBase::Readv(char* buf,size_t len,int* timeout_flag,bool nice)
{
    size_t toread = len;
    int n = 0;
    char *cp = buf;

    while(toread > 0) {
           if(timeout_flag && (*timeout_flag > 0)) {
                  return (int)(len - toread);
           }
           if((n = Read(cp,toread)) < 0) {
                  return (int)(len - toread);
           }
           if(!n && nice) {
                  sleepms(1);
           }
           if (n > 0)
           {
                  toread -= n;
                  cp += n;
           }
    }
    // ok, all bytes received
    return (int)(len - toread);
}

int wxIOBase::ReadUntilEOS(char*& readbuf,
					  size_t* readedBytes,
					  const char* eosString,
					  long timeout_in_ms,
					  char quota)
{
    int n = 0;
    int timeout = 0;
    int bufsize = DELTA_BUFSIZE;
    int result = 0;
    int quoted = 0;
    char* buf = new char[bufsize];
    char* des = buf;
    const char* eos = eosString;
    char ch;

    timer t(timeout_in_ms,&timeout,NULL);
    t.start();

    while(!timeout) {
	   if(des >= &buf[bufsize]) {
		  // buffer full, realloc more memory
		  char* tmp = new char[bufsize + DELTA_BUFSIZE + 1];
		  memcpy(tmp,buf,bufsize);
		  delete [] buf;
		  buf = tmp;
		  des = &buf[bufsize];
		  bufsize += DELTA_BUFSIZE;
	   }
	   // read next byte
	   n = Read(&ch,1);
	   if(n < 0) {
		  // an error occured
		  result = -1;
		  break;
	   }
	   else if(n == 0) {
		  // no data available, give up the processor for some time
		  // to reduce the cpu last
		  sleepms(10);
		  continue;
	   }
	   // if eos is composed of more than one char, and the current
	   // byte doesn't match the next eos character, we handle the
	   // readed byte as a normal char (and not an eos)
	   if((eos != eosString) && (ch != *eos)) {
		  // FIXME!
		  // write all characters, which was matched the eos string
		  // until now (with the first wrong character all received
		  // eos characters are invalid and must handled as normal
		  // characters).

		  // This doesn't work right and is only a little workaround
		  // because the received eos chars are lost
		  PutBack(ch);
		  // because we doesn't match the eos string, we must 'reset' 
		  // the eos match
		  eos = eosString;
		  continue;
	   }
	   else {
		  if((ch == *eos) && !quoted) {
			 if(*++eos == 0) {
				// the eos string is complete
				result = 1;
				break;
			 }
			 continue;
		  }
	   }
	   if(ch == quota) {
		  quoted ^= 1;
	   }
	   *des++ = ch;
    }
    *des = 0;
    readbuf = buf;
    *readedBytes = des - buf;
    return result;
}

int wxIOBase::Writev(char* buf,size_t len,unsigned int timeout_in_ms)
{
    char *cp = buf;
    int n = 0;
    int timeout = 0;
    size_t towrite = len;

    timer t(timeout_in_ms,&timeout,NULL);
    if(timeout_in_ms != 0xFFFFFFFF) {
	   t.start();
    }

    while(!timeout && (towrite > 0)) {
	   if((n = Write(cp,towrite)) < 0) {
		  // an error occurs
		  break;
	   }
	   if(!n) {
		  sleepms(1);
	   }
	   towrite -= n;
	   cp += n;
    }
    return (int)(len - towrite);
}

/*
  Similar to Readv(). Writev() calls Write() repeatedly till
  all bytes are written.
*/
int wxIOBase::Writev(char* buf,size_t len,int* timeout_flag,bool nice)
{
    size_t towrite = len;
    int n = 0;
    char *cp = buf;

    while(towrite > 0) {
           if(timeout_flag && (*timeout_flag > 0)) {
                  return (int)(len - towrite);
           }
           if((n = Write(cp,towrite)) < 0) {
                  // an error occurs
                  return (int)(len - towrite);
           }
           if(!n && nice) {
                  sleepms(1);
           }
           towrite -= n;
           cp += n;
    }
    return (int)(len);
}
