/* 
 * Thomas Pantzer: t_ringbuf.cc, v0.1b  6.8.99 16:10 
 * 
 * 
 * Copyright 1999 by Thomas Pantzer
 * 
 * Permission to use, copy, modify, and distribute this software for noncommercial 
 * use and without fee is hereby granted, provided that the above copyright notice 
 * appear in all copies and that both that copyright notice and this permission 
 * notice appear in supporting documentation, and that the name of the Author not be 
 * used in advertising or publicity pertaining to distribution of the software 
 * without specific, written prior permission. The Author makes no representations about
 * the suitability of this software for any purpose.  It is provided "as is" 
 * without expressed or implied warranty. 
 * 
 * 
 * pantec@zorro.informatik.uni-leipzig.de   (Thomas Pantzer) 
 * 
 */






#include "t_ringbuf.h"
#include "utils.h"
#include <stdio.h>


void t_ringbuf::Init(int s)
{
	size = s;
	w_ptr = 0;
	r_ptr = 0;
	last_rptr = 0;
	A = new char[size+1024];
}


void t_ringbuf::Done(void)
{
	delete A;
	A = NULL;
	size = 0;
}

char t_ringbuf::Get_c(void)
{
	char c = A[rptr];
	rptr++;
	rptr %= size;
	return c;
}

char t_ringbuf::Get_c(int past)
{
	if (past > size)
	   past = 0;

	int i = rptr + size - past; 
	i %= size;

	return A[i];
}


void t_ringbuf::Put_c(char c)
{
	A[wptr] = c;
	wptr++;
	wptr %= size;
}












char *t_ringbuf::GetString(int pos)
{
	int p = (last_rptr + pos) % size;
	return &A[p];
}

int t_ringbuf::ReadFrom(int fd, int count)
{
	if ((size == 0) || (A == NULL) || (fd < 0))
	   return 0;
	
	int max_count = w_ptr - r_ptr;

	if (max_count < 0)
	   max_count += size;

	int get_count = __min(max_count,count);
	int used_count = __min((size - r_ptr),get_count);

	int rd = read(fd,(char *)&A[r_ptr],used_count);

	if (rd > 0)
	   {
	    A[r_ptr+rd] = '\0';
//	    int new_count = get_count - rd;

	    last_rptr = r_ptr;
            r_ptr += rd;
	    r_ptr %= size;	 

//	    if (new_count > 0)
//	       {	// ich sollte mehr holen
//	        if ((FD_Ready(fd) == true) && (new_count > 0))
//	           {	// es ist noch was zu holen
//		    int got = ReadFrom(fd,new_count);
//		    if (got > 0)
//			return (rd + got);
//		   }
//	       }	
	   }
	
	return rd;
}


void t_ringbuf::CopyFrom(char *S, int count)
{
	if ((size == 0) || (A == NULL) || (S == NULL))
	   return;


	for (int i=0; i<count; i++)
	  {
	   int j = (i+r_ptr) % size;
	   A[j] = S[i];
	  }

	last_rptr = r_ptr;

	r_ptr += count;
	r_ptr %= size;
}


int t_ringbuf::PasteTo(char *D, int count)
{
	if ((size == 0) || (A == NULL) || (D == NULL))
	   return 0;

	int max_count = r_ptr - w_ptr;

	if (max_count < 0)
	   max_count += size;

	int used_count = __min(max_count,count);
 	int k = 0;

	for (int i=0; i<used_count; i++)
	  {
	   int j = (i+w_ptr) % size;
	   D[i] = A[j];
           k++;
	  }

	w_ptr += count;
	w_ptr %= size;

	return k;
}

int t_ringbuf::WriteTo(int fd, int count)
{
	if ((size == 0) || (A == NULL) || (fd < 0))
	   return 0;

	int max_count = r_ptr - w_ptr;

	if (max_count < 0)
	   max_count += size;

	int used_count = __min(max_count,count);
 	int k = 0;

	int wr_count = __min((size-w_ptr),used_count);
	int wr = write(fd,(char *)&A[w_ptr],wr_count);

	if (wr > 0)
	   {	
	    w_ptr += wr;
	    w_ptr %= size;

	    int new_count = used_count - wr_count;
            if ((wr == wr_count) && (new_count > 0))
	       {
		int next = WriteTo(fd,new_count);
		if (next > 0)
		   return (next + wr);
	       }
	   }

	return wr;
}

