static    char    sccsid[]="%Z% %M% %I% %D% %T%";
/*************************************************
 *
 *  akxetimer.c
 *
 *        coded by A.Kobayashi 2000/2/23
 *
 *************************************************/
#include "akunix.h"
#include "akx.h"

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_timer_set(ptvalo,ptvali)
struct timeval *ptvalo,*ptvali;
{
	int t_sec,t_usec;

	if (ptvali) {
		t_sec  = ptvali->tv_sec;
		t_usec = ptvali->tv_usec;
	}
	else {
		t_sec  = t_usec = 0;
	}
	if (ptvalo) {
		ptvalo->tv_sec  = t_sec;
		ptvalo->tv_usec = t_usec;
	}

	return t_sec*1000 + t_usec/1000;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_timer_add(ptvalo,ptvali,ptval2)
struct timeval *ptvalo,*ptvali,*ptval2;
{
	int t_sec,t_usec;

	if (ptvali) {
		t_sec  = ptvali->tv_sec;
		t_usec = ptvali->tv_usec;
	}
	else {
		t_sec  = t_usec = 0;
	}
	if (ptval2) {
		t_sec  += ptval2->tv_sec;
		t_usec += ptval2->tv_usec;
	}
	if (t_usec >= 1000000) {
		t_sec++;
		t_usec -= 1000000;
	}
	else if (t_usec < 0) {
		t_sec--;
		t_usec += 1000000;
	}
	if (ptvalo) {
		ptvalo->tv_sec  = t_sec;
		ptvalo->tv_usec = t_usec;
	}

	return t_sec*1000 + t_usec/1000;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_timer_set_msec(ptval,msec)
struct timeval *ptval;
int msec;
{
	if (msec) {
		ptval->tv_sec  = msec / 1000;
		ptval->tv_usec = (msec % 1000)*1000;
	}
	else {
		ptval->tv_sec  = 0;
		ptval->tv_usec = 0;
	}

	return msec;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_timer_add_msec(ptvalo,ptvali,msec)
struct timeval *ptvalo,*ptvali;
int msec;
{
	struct timeval tval;

	akxe_timer_set_msec(&tval,msec);

	return akxe_timer_add(ptvalo,ptvali,&tval);
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_timer_sub(ptvalo,ptvali,ptval2)
struct timeval *ptvalo,*ptvali,*ptval2;
{
	struct timeval tval;

	if (ptval2) {
		tval.tv_sec  = -ptval2->tv_sec;
		tval.tv_usec = -ptval2->tv_usec;
	}
	else {
		tval.tv_sec = tval.tv_usec = 0;
	}

	return akxe_timer_add(ptvalo,ptvali,&tval);
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_timer_cmp(ptval1,ptval2)
struct timeval *ptval1,*ptval2;
{
	int t1_sec,t1_usec;
	int t2_sec,t2_usec;
	int f=0;

	if (ptval1) {
		t1_sec  = ptval1->tv_sec;
		t1_usec = ptval1->tv_usec;
	}
	else {
		t1_sec  = t1_usec = 0;
	}
	if (ptval2) {
		t2_sec  = ptval2->tv_sec;
		t2_usec = ptval2->tv_usec;
	}
	else {
		t2_sec  = t2_usec = 0;
	}
	if (!(f = t1_sec - t2_sec)) f = t1_usec - t2_usec;

	return f;
}

/********************************************************/
/*                                                      */
/********************************************************/
tdtTimerCtlHead *akxe_timer_new()
{
	tdtTimerCtlHead *pTC;
	struct timeval tval;

	if (pTC = (tdtTimerCtlHead *)Malloc(sizeof(tdtTimerCtlHead))) {
		memset(pTC,0,sizeof(tdtTimerCtlHead));
		pTC->th_mwtext = pTC->th_minwait = -1;
		if (akxe_get_msec(pTC,&tval) < 0) {
			Free(pTC);
			pTC = NULL;
		}
	}
	return pTC;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_timer_free(pTC)
tdtTimerCtlHead *pTC;
{
	if (pTC) Free(pTC);
	return 0;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_get_msec(pTC,ptval)
tdtTimerCtlHead *pTC;
struct timeval *ptval;
{
	struct timeval tval;
	int t, t_sec,t_usec;

	t = gettimeofday(&tval,NULL);
	if (!t) {
		if (pTC) {
			if (!pTC->th_tmbase.tv_sec) {
				pTC->th_tmbase.tv_sec  = tval.tv_sec;
				pTC->th_tmbase.tv_usec = tval.tv_usec;
			}
			t_sec  = tval.tv_sec  - pTC->th_tmbase.tv_sec;
			t_usec = tval.tv_usec - pTC->th_tmbase.tv_usec;
			if (t_usec < 0) {
				t_sec--;
				t_usec += 1000000;
			}
			pTC->th_latest.tv_sec  = t_sec;
			pTC->th_latest.tv_usec = t_usec;
		}
		else {
			t_sec  = tval.tv_sec;
			t_usec = tval.tv_usec;
		}
		if (ptval) {
			ptval->tv_sec  = t_sec;
			ptval->tv_usec = t_usec;
		}
	/* 1/1000 secではプロセス起動後、24.86日でマイナスになる
		t = t_sec*1000 + t_usec/1000;
	*/
		t = t_sec;
	}
	return t;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_register_timer(pTC,cpTimerName,pFuncName,iWaitTime,cpParm)
tdtTimerCtlHead *pTC;
char *cpTimerName ; /* タイマー名称 */
int (*pFuncName)(); /* タイムアウト時呼び出し関数へのポインタ */
int  iWaitTime    ; /* タイムアウト時間(msec) */
char *cpParm      ; /* 関数呼び出し時のパラメータ */
{
	tdtTimerCtl *curr,*next,*empty;
	int i,ret,iTimerId,iWT;
	struct timeval ttime;

	if (!pTC) {
	/*	ERROROUT("タイマー管理表へのポインタがＮＵＬＬ");	*/
		return -1;
	}
	if (!cpTimerName) {
		return -2;
	}
	if (!*cpTimerName) {
		return -3;
	}
	if (!pFuncName) {
	/*	ERROROUT("関数名がＮＵＬＬ");	*/
		return -4;
	}
	if (iWaitTime < 0) {
		iWT = 0;
		iWaitTime = -iWaitTime;
	}
	else if (iWaitTime > 0) {
		iWT = iWaitTime;
	}
	else {
	/*	ERROROUT1("タイムアウト時間(%d)が０",iWaitTime);	*/
		return -5;
	}
	iTimerId = 0;
	empty = curr = NULL;
	next = pTC->th_ptimer;
	if (!next) {
		if (!(next=(tdtTimerCtl *)Malloc(sizeof(tdtTimerCtl)))) {
			return -7;
		}
		memset(next,0,sizeof(tdtTimerCtl));
		pTC->th_ptimer = next;
	}
	next->tc_tmrid = iTimerId + 1;
	next->tc_tmrname = Strdup(cpTimerName);
	next->tc_pfunc = pFuncName;
	next->tc_watime = iWaitTime;
	next->tc_parm    = cpParm;
	next->tc_status  = AKX_TIMER_START;
	if (akxe_get_msec(pTC,&ttime) < 0) return -9;
	akxe_timer_add_msec(&next->tc_timeout,&ttime,iWT);

	if (pTC->th_minwait<0 || iWaitTime<pTC->th_minwait) pTC->th_minwait = iWaitTime;

	return next->tc_tmrid;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_proc_timer(pTC)
tdtTimerCtlHead *pTC;
{
	tdtTimerCtl *next;
	struct timeval ttime;
	int rc, iMinWait, iWaitTime;
	char c;

	if (!pTC) return -1;

	if (pTC->th_minwait < 0) return 0;

	/* 現在時刻の取りだし */
	if (akxe_get_msec(pTC,&ttime) < 0) return -2;

	iMinWait = -1;
	next = pTC->th_ptimer;
	if (next) {
		if (next->tc_tmrname) {
			if (akxe_timer_cmp(&ttime,&next->tc_timeout) >= 0) {
				pTC->th_mwtext = -1;
				rc = next->tc_pfunc(next->tc_tmrid, next->tc_tmrname,
				                     next->tc_parm, &ttime);
				next->tc_event = 0;
				if (rc < 0) {
					if (next->tc_tmrname) Free(next->tc_tmrname);
					next->tc_tmrname = NULL;
					next->tc_pfunc = NULL;
					next->tc_watime = 0;
					next->tc_status  = AKX_TIMER_UNUSED;
				}
				else {
					if (rc > 0) iWaitTime = rc;
					else iWaitTime = next->tc_watime;
					akxe_timer_add_msec(&next->tc_timeout,&ttime,iWaitTime);
					if (iMinWait<0 || iWaitTime<iMinWait) iMinWait = iWaitTime;
				}
				if ((iWaitTime=pTC->th_mwtext) >= 0) {
					if (iMinWait<0 || iWaitTime<iMinWait) iMinWait = iWaitTime;
				}
			}
			else {
				iWaitTime = akxe_timer_sub(NULL,&next->tc_timeout,&ttime);
				if (iMinWait<0 || iWaitTime<iMinWait) iMinWait = iWaitTime;
			}
		}
	}
	pTC->th_minwait = iMinWait;
	pTC->th_mwtext = -1;
	return 0;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxe_min_wait_timer(pTC)
tdtTimerCtlHead *pTC;
{
	tdtTimerCtl *next;
	struct timeval ttime;
	int rc, iMinWait, iWaitTime;

	if (!pTC) return -1;
	if (akxe_get_msec(pTC,&ttime) < 0) return -3;
	iMinWait = -1;
	next = pTC->th_ptimer;
	if (next) {
		if (next->tc_tmrname) {
			iWaitTime = akxe_timer_sub(NULL,&next->tc_timeout,&ttime);
			if (iWaitTime < 0) iWaitTime = 0;
			if (iMinWait<0 || iWaitTime<iMinWait) iMinWait = iWaitTime;
		}
	}
	pTC->th_minwait = iMinWait;
	return iMinWait;
}
/********************************************************/
/*                                                      */
/********************************************************/
int akxe_get_msecL(pTC,ptval)
tdtTimerCtlHead *pTC;
struct timeval *ptval;
{
	int t,t_sec,t_usec;

	if (pTC) {
		t_sec  = pTC->th_latest.tv_sec;
		t_usec = pTC->th_latest.tv_usec;
		if (ptval) {
			ptval->tv_sec  = t_sec;
			ptval->tv_usec = t_usec;
		}
	/* 1/1000 secではプロセス起動後、24.86日でマイナスになる
		t = t_sec*1000 + t_usec/1000;
	*/
		t = t_sec;
	}
	else {
		t = akxe_get_msec(NULL,ptval);
	}

	return t;
}
