/* lag.c - measure server lag * distributed as part of _ s u l a _ *  *
 * Author: Tano Fotang, 1997 *  * This program is free software; you can
 * redistribute it and/or modify it * under the terms of the GNU General
 * Public License as published by the Free  * Software Foundation; either
 * version 2 of the License , or (at your option)  * any later version. * see 
 * the file COPYING for more info. *  */

#include <forms.h>
#include <time.h>
#include "aux.h"
#include "sula.h"
#include "chanwin.h"
#include "global.h"
#include "servers.h"
#include "lag.h"

#if DEBUG>2
#define DEBUGLAG  2
#endif

void    ClearLag(Server * s)
{
#ifndef NOLAG
	while (s->lag) {
		Lag    *p = s->lag;

		s->lag = (s->lag)->next;
		free(p);
	}
#endif
}

#ifndef NOLAG
static int lagTimeoutID = 0;
static void addlagtime(Lag ** s, struct timeval t)
{
	Lag    *p = *s;

	*s = (Lag *) malloc(sizeof(Lag));
	(*s)->next = p;
	(*s)->when.tv_sec = t.tv_sec;
	(*s)->when.tv_usec = t.tv_usec;
	/*(*s)->wait=timeout; */
}
static void del_lag_node(Lag ** head, Lag * trail, Lag * node)
{
	if (trail)
		trail->next = node->next;
	else
		*head = (*head)->next;
	free(node);
}
static void remove_lag(Server * s, struct timeval when)
{
	Lag    *p = s->lag;

	if (!p)
		return;
	if (p->when.tv_sec == when.tv_sec && p->when.tv_usec == when.tv_usec) {
		/* pop it off */
		s->lag = s->lag->next;
		free(p);
	}
	else {
		Lag    *q = p->next;

		while (q)
			if (q->when.tv_sec == when.tv_sec &&
			    q->when.tv_usec == when.tv_usec) {
				del_lag_node(&(s->lag), p, q);
				break;
			}
			else {
				p = q;
				q = q->next;
			}
	}
}

static void ping_server(Server * p)
{
	if (p) {
		Server *s;

		ping_server(p->left);
		s = search_server_tree_byname(p->servname, p->port);
		assert(s);
		if (!s->connecting)
			send_lag_junk(s, 0,1);
		ping_server(p->right);
	}
}

static void autocheck_lag(int id, void *junk)
{
	/*check all connected servers */
	ping_server(servFdTree);
	lagTimeoutID = 0;
}
extern void send_lag_msg(void)
{
	/* lag timeout is in seconds ! */
	if (servFdTree == NULL || !(gflags & AUTO_CHECKLAG)) {
		if (lagTimeoutID) {
			fl_remove_timeout(lagTimeoutID);
			lagTimeoutID = 0;
		}
	}
	else if (!lagTimeoutID) {
		static char first_run = 0;

		if (!first_run)
			ping_server(servFdTree);
		first_run = 1;
		lagTimeoutID = fl_add_timeout((double) (lag_tmout * 1000),
					      autocheck_lag, (void *) 0);
	}

}

extern void send_lag_junk(Server * p, char reset, char send)
{

	assert(p);
	if(!(p->fd<0)){

		if (reset)
			ClearLag(p);
		if (!p->lag) { /* now using only the 1st array element
		todo: p->lag shouldnt be an array*/
			struct timeval t;

			gettimeofday(&t, NULL);
			if(send){ 
			char   *buf = malloc(sizeof(char) * (strlen(p->nick) + 50));
			int n;
			sprintf(buf, "INVITE %s __%d_%d\n", p->nick, t.tv_sec, t.tv_usec);
			n = strlen(buf);
			if (writen(p->fd, buf, n) == n)
				addlagtime(&(p->lag), t);
			free(buf);
			}else  addlagtime(&(p->lag), t); /* called form connect_to_server*/
		}

	}

}

void    update_lag_display(Server * s, float t, struct timeval *remove)
{

	assert(s);
	if (
		   s->lag	/* have requested lag */

		   && build_winlistbyfd(s->fd)	/* not out of mem */
	   ) {

		WinList *p = servWin;
		char    buf[16];

		while (p) {
			sprintf(buf, "%0*.*fs", 7, 2, t);
			/*printf("%f(%0*.*fs)",t,7,2,t);fflush(stdout); */
			fl_set_object_label(p->win->chanwin->lag, buf);
			p = p->next;
		}		/*while */
		if (remove)
			remove_lag(s, *remove);
	}
}

#endif
