/* 
 * Copyright (C) 2000-2001 Computer & Communications Research Laboratories,
 *			   Industrial Technology Research Institute
 */
/*
 * adtBuffer.c
 *
 * $Id: adtBuffer.c,v 1.10 2001/06/21 02:48:46 sjtsai Exp $
 */

#include <memory.h>
#include <stdlib.h>
#include "adtBuffer.h"
#include "lowSync.h"

TCR	buffer_tracer = NULL;

struct adtBufferObj
{
	char*	_pData;
	int	_MAXLEN;
	int	_currLen;
	char*	_start;
	char*	_end;

	lowMutex CS;
	TRACE_FLAG	traceFlag;
};

void adtBufferInit(void) {}

adtBuffer	adtBufferNew(int total_len)
{
	adtBuffer	_this = (adtBuffer)malloc(sizeof(struct adtBufferObj));

	_this->_currLen = 0;
	_this->_pData = (char*)malloc((total_len+1)*sizeof(char));
	_this->_end = _this->_pData;
	_this->_start = _this->_pData;
	_this->_MAXLEN = total_len;

	_this->CS = lowMutexNew(MUTEX_INTERTHREAD,0); 
	if(!_this->CS) {
		free(_this->_pData);
		free(_this);
		return NULL;
	}

	return _this;
}

void		adtBufferFree(adtBuffer _this)
{
	if(_this) {
		lowMutex cstemp = _this->CS;
		_this->CS = NULL;
		lowMutexFree(cstemp);
		if(_this->_pData) 
			free(_this->_pData);
		free(_this);
	}
}

adtBuffer	adtBufferDup(adtBuffer _this)
{
	adtBuffer buffer;

	if(!_this)
		return NULL;

	lowMutexLock(_this->CS);

	buffer = adtBufferNew(_this->_MAXLEN);
	buffer->_currLen = _this->_currLen;
	buffer->_start = buffer->_pData + ( _this->_start-_this->_pData );
	buffer->_end = buffer->_pData + ( _this->_end-_this->_pData );
	memcpy(buffer->_pData,_this->_pData,_this->_MAXLEN);

	lowMutexUnlock(_this->CS);

	return buffer;
}

void		adtBufferClear(adtBuffer _this)
{
	if(!_this)
		return;

	lowMutexLock(_this->CS);

	_this->_end = _this->_pData;
	_this->_start = _this->_pData;
	_this->_currLen = 0;

	lowMutexUnlock(_this->CS);
}

int		adtBufferRead( adtBuffer _this, char* buff, int len)
{
	int xlen = 0;

	if( !_this || !buff || len<0 ) return -1;
	if( _this->_currLen==0 ) return 0;
	lowMutexLock(_this->CS);

	if(_this->_end>=_this->_start && _this->_currLen!=_this->_MAXLEN) {
		if(len>=_this->_currLen) {
			memcpy(buff,_this->_start,_this->_currLen);
			xlen = _this->_currLen;

			_this->_start = _this->_pData;
			_this->_end = _this->_pData;
			_this->_currLen = 0;
		}
		else {
			memcpy(buff,_this->_start,len);
			xlen = len;

			_this->_start += len;
			_this->_currLen -= len;
		}
	}
	else {
		/*__________________________________________
		// ********<-end       start->*******
		//   elen			slen
		//__________________________________________*/
		int slen = (_this->_pData + _this->_MAXLEN) - _this->_start;
		int elen = _this->_end - _this->_pData;

		if(len>=_this->_currLen) {
			memcpy(buff,_this->_start,slen);
			memcpy(buff+slen,_this->_pData,elen);
			xlen = _this->_currLen;

			_this->_start = _this->_pData;
			_this->_end = _this->_pData;
			_this->_currLen = 0;
		}
		else {
			if(len<slen) {
				memcpy(buff,_this->_start,len);
				xlen = len;

				_this->_start += len;
				_this->_currLen -= len;
			}
			else {
				memcpy(buff,_this->_start,slen);
				memcpy(buff+slen,_this->_pData,len-slen);
				xlen = len;

				_this->_start = ((_this->_start+len)-_this->_pData)%_this->_MAXLEN+_this->_pData;
				_this->_currLen -= len;
			}
		}
	}
	lowMutexUnlock(_this->CS);

	return xlen;
}

int		adtBufferWrite( adtBuffer _this, char* buff, int len)
{
	int xlen = 0;

	if( !_this || !buff || (_this->_MAXLEN-_this->_currLen)==0 || len<0 ) return -1;
	lowMutexLock(_this->CS);

	if(_this->_start>=_this->_end && _this->_currLen!=0) {
		if(len>=(_this->_MAXLEN-_this->_currLen)) {
			memcpy(_this->_end,buff,(_this->_MAXLEN-_this->_currLen));
			xlen = (_this->_MAXLEN-_this->_currLen);

			_this->_end += xlen;
			_this->_currLen += xlen;
		}
		else {
			memcpy(_this->_end,buff,len);
			xlen = len;

			_this->_end += len;
			_this->_currLen += len;
		}
	}
	else {
		/*__________________________________________
		// ++++++++start->********<-end+++++++++++++
		//   slen			 elen
		//__________________________________________*/
		int slen = _this->_start - _this->_pData;
		int elen = (_this->_pData + _this->_MAXLEN) - _this->_end;

		if(len>=(_this->_MAXLEN-_this->_currLen)) {
			memcpy(_this->_end,buff,elen);
			memcpy(_this->_pData,buff+elen,slen);
			xlen = (_this->_MAXLEN-_this->_currLen);

			_this->_end = _this->_start;
			_this->_currLen = _this->_MAXLEN;
		}
		else {
			if(len<=elen) {
				memcpy(_this->_end,buff,len);
				xlen = len;

				_this->_end += len;
				_this->_currLen += len;
			}
			else {
				memcpy(_this->_end,buff,elen);
				memcpy(_this->_pData,buff+elen,(len-elen));
				xlen = len;

				_this->_end = _this->_pData + (len-elen);
				_this->_currLen += len;
			}
		}
	}
	lowMutexUnlock(_this->CS);

	return xlen;
}

/*========================================================================
// set this adtBuffer's trace flag ON or OFF*/
void	adtBufferSetTraceFlag(adtBuffer _this,TRACE_FLAG traceflag)
{
	if ( _this==NULL ) 
		return;
	_this->traceFlag = traceflag;
}

/*========================================================================
// vector Tracer */
void		adtBufferSetTracer(TCR tracer)
{
	buffer_tracer = tracer;
}

TCR		adtBufferGetTracer(void)
{
	return buffer_tracer;
}

