/* 
 * Copyright (C) 2000-2001 Computer & Communications Research Laboratories,
 *				           Industrial Technology Research Institute
 */
/*
 * adtMsgQ.c
 *
 * $Id: adtMsgQ.c,v 1.16 2001/06/15 02:39:19 sjtsai Exp $ 
 */

#include <stdlib.h>
#include <memory.h>
#include <sys/timeb.h>
#include "common.h"
#include "osdep.h"
#include "lowSync.h"
#include "adtMsgQ.h"

TCR	msgq_tracer = NULL;

struct adtMsgQObj
{
	adtVector		_msgq;	
	adtVector		_msglen;
	lowMutex		_W_CS;

	TRACE_FLAG		traceFlag;
};

adtMsgQ adtMsgQNew(int mq_size)
{
	adtMsgQ mq = malloc(sizeof(struct adtMsgQObj));

	mq->_msgq = adtVectorNew(mq_size,V_POINTER);
	mq->_msglen = adtVectorNew(mq_size,V_INTEGER);
	mq->_W_CS = lowMutexNew(MUTEX_INTERTHREAD,0);

	return mq;
}

void adtMsgQFree(adtMsgQ mq)
{
	lowMutexLock(mq->_W_CS);
	lowMutexUnlock(mq->_W_CS);
	lowMutexFree(mq->_W_CS);
	adtVectorFree(mq->_msgq,free);
	adtVectorFree(mq->_msglen,free);
	free(mq);
}

int adtMsgQGetLen(adtMsgQ mq)
{
	return (mq)?adtVectorGetSize(mq->_msgq):0;
}

int adtMsgQSendMsg(adtMsgQ mq,char* msg,unsigned int len)
{
	char* buff = NULL;

	if(!mq||!msg)	return 0;

	lowMutexLock(mq->_W_CS);

	buff = malloc(len);
	memcpy(buff,msg,len);

	if( adtVectorAddElement(mq->_msgq,buff)<0 ) {
		free(buff);
		lowMutexUnlock(mq->_W_CS);
		return 0;		
	}	
	if( adtVectorAddElement(mq->_msglen,&len)<0 ) {
		adtVectorRemoveElement(mq->_msgq,buff);
		free(buff);
		lowMutexUnlock(mq->_W_CS);
		return 0;
	}

	lowMutexUnlock(mq->_W_CS);

	return len;
}

int adtMsgQGetMsg(adtMsgQ mq,char* msg,int len,unsigned long timeout)
{
	char* buff = NULL;
	int* pbufflen = NULL;
	int bufflen = 0;
	unsigned long start, now;
	struct timeb timebuf;

	ftime(&timebuf);
	start = timebuf.time * 1000 + timebuf.millitm;

	if(!mq||!msg)	return 0;

	while ( adtMsgQGetLen(mq)==0 ) {
		sleeping(10);

		ftime(&timebuf);
		now = timebuf.time * 1000 + timebuf.millitm;

		if( timeout!=0 && (now-start)>=timeout ) {
			return 0;
		}
	}
	lowMutexLock(mq->_W_CS);
	if ( adtMsgQGetLen(mq)==0 ) {
		goto ERR_RETURN;
	}
	buff = adtVectorRemoveElementAt(mq->_msgq,0);
	pbufflen = (int*)adtVectorRemoveElementAt(mq->_msglen,0);
	bufflen = ((pbufflen)?*pbufflen:0);

	if( buff && bufflen<=len ) {
		memcpy(msg,buff,bufflen);
		free(buff);
		free(pbufflen);

		lowMutexUnlock(mq->_W_CS);
		return bufflen;
	}
	
	free(buff);
	free(pbufflen);
ERR_RETURN:
	lowMutexUnlock(mq->_W_CS);

	return 0;
}

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

/*========================================================================
// vector Tracer */
void		adtMsgQSetTracer(TCR tracer)
{
	msgq_tracer = tracer;
}

TCR		adtMsgQGetTracer(void)
{
	return msgq_tracer;
}

