/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/


#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include	"machine/include.h"
#include	"memory_debug.h"
#include	"xl.h"
#include	"xldir.h"
#include	"mp.h"
#include	"gbmp.h"
#include	"lock_level.h"
#include	"lump.h"
#include	"acrp.h"

extern SYS_QUEUE mp_task_que;
extern int max_hops;
extern SEM tick_que_lock;

L_CHAR * get_sys_path(char *);
typedef struct lump_around_list {
	struct lump_around_list *	next;
	L_CHAR *			url;
} LUMP_AROUND_LIST;

SEM	lump_lock;

void
init_lump()
{
	lump_lock = new_lock(LL_LUMP);
}


char *
make_base_dir()
{
L_CHAR * path;
char * cpath;
        path = get_sys_path("/work");
        u_mkdir((n_string(std_cm,path)),0755);
        d_f_ree(path);
        path = get_sys_path("/work/lump");
	cpath = ln_copy_str(std_cm,path);
        u_mkdir(cpath,0755);
        d_f_ree(path);
        return cpath;
}



void
make_lump_dir(unsigned int id)
{
int i;
char * path;
int len;
	path = make_base_dir();
	len = strlen(path);
	path = d_re_alloc(path,len + 100);
	for ( i = 0 ; i < 4 ; i ++ ) {
		sprintf(&path[strlen(path)],"/%i",(id>>(8*(3-i)))&0x0ff);
		u_mkdir(path,0755);
	}
	d_f_ree(path);
}


char *
n_get_lump_path(unsigned int id)
{
char * path;
int len;
	path = copy_str("/work/lump");
	len = strlen(path);
	path = d_re_alloc(path,len + 100);
	sprintf(&path[len],"/%i/%i/%i/%i/",
		(id >> 24) & 0x0ff,
		(id >> 16) & 0x0ff,
		(id >> 8) & 0x0ff,
		id & 0x0ff);
	return path;
}

L_CHAR *
get_lump_path(unsigned int id)
{
char * path;
L_CHAR * ret;
	path = n_get_lump_path(id);
	ret = nl_copy_str(std_cm,path);
	d_f_ree(path);
	return ret;
}

int
check_dir(unsigned int id)
{
STREAM * s;
char * _path;
L_CHAR * path;
	_path = n_get_lump_path(id);
	path = get_sys_path(_path);
	s = s_open_file((n_string(std_cm,path)),O_RDONLY);
	d_f_ree(_path);	
	d_f_ree(path);
	if ( s == 0 )
		return 0;
	s_close(s);
	return -1;
}


unsigned int
new_lump()
{
unsigned int	id;
MP_WORK mpw;

	get_mp_work(&mpw,0);

	lock_task(lump_lock);
	id = mpw.lump_id;
	for ( ; check_dir(id) ; id ++ );
	make_lump_dir(id);
	mpw.lump_id = id + 1;
	unlock_task(lump_lock,"new_lump");

	set_mp_work(&mpw);
	return id;
}


int
check_lump_path(int ses,char * path)
{
L_CHAR * _path;
L_CHAR * ptr;
int cnt;
LUMP_INFO info;
LUMP_OPT opt;
XL_SEXP * lump;
URL u;
int ret;
int len;
XL_SEXP * remote_fetch_lump();


	_path = nl_copy_str(std_cm,path);
	len = l_strlen(_path);
	_path = d_re_alloc(_path,(len+10)*sizeof(L_CHAR));
	_path[len] = '/';
	_path[len+1] = 0;
	ptr = &_path[len+1];
	for ( cnt = 7 ; cnt > 0 ; cnt -- ) {
		ptr --;	
		for ( ; *ptr != '/' ; ptr -- );
	}
	if ( load_lump_info(&info,ptr) < 0 ) {
		ret = -1;
		goto end0;
	}

	gc_push(0,0,"check_lump_path");

	get_url2(&u,info.crd);
	lump = remote_fetch_lump(ses,&u,1);
	if ( lump == 0 ) {
		ret = -1;
		goto end;
	}
	lump = get_el_by_symbol(lump,
		l_string(std_cm,"option"),
		0);
	if ( get_type(lump) == XLT_NULL ) {
		ret = -1;
		goto end;
	}
	init_lump_opt(&opt);
	lr_option(&opt,lump);
	if ( opt.lump == 0 ) {
		ret = -1;
		goto end1;
	}
	ptr[l_strlen(opt.lump)] = 0;
	if ( l_strcmp(ptr,opt.lump) ) {
		ret = -1;
		goto end1;
	}
	ret = 0;
end1:
	free_lump_opt(&opt);
end:
	gc_pop(0,0);
	free_lump_info(&info);
end0:
	d_f_ree(_path);
	return ret;
}


void
rm_lump_path(char * path)
{
char * p;
char * ptr;
int cnt;
int flag;
	p = copy_str(path);
	flag = RMF_REC|RMF_DIR|RMF_FILE;
	ptr = &p[strlen(p)];
	for ( cnt = 4 ; cnt > 0 ; cnt -- ) {
		u_rm(p,flag);
		flag = RMF_DIR|RMF_FILE;
		ptr --;
		for ( ; *ptr != '/' ; ptr -- );
		ptr[1] = 0;
	}
	d_f_ree(p);
}

void
lump_gc_path(int ses)
{
L_CHAR * path;
DIR_LIST * d, * d1;
	path = get_sys_path("/work/lump/*/*/*/*");
	d = get_dir((n_string(std_cm,path)),0,0,0,
		DLF_DIR|DLF_T_EXIST_D|DLF_T_STAMP_D);
	d_f_ree(path);
	for ( d1 = d ; d1 ; d1 = d1->next ) {
//printf("-- %s\n",d1->name);
		if ( check_lump_path(ses,d1->name) == 0 )
			continue;
//printf("flush\n");
		log_printf(LOG_SYSTEM,LOG_LAYER_GB,0,
			"LUMP GC RM THE PATH %s",d1->name);
		rm_lump_path(d1->name);
	}
	free_dir_list(d);
}

LUMP_AROUND_LIST *
get_around_list(LUMP_AROUND_LIST * a,XL_SEXP * p,char * dir)
{
L_CHAR * _dir;
XL_SEXP * rec, * el, * sym,* dt;
LUMP_AROUND_LIST * al1;
	_dir = l_string(std_cm,dir);
	for ( ; get_type(p) == XLT_PAIR  ; p = cdr(p) ) {
		rec = car(p);
		if ( get_type(rec) != XLT_PAIR )
			continue;
		for ( ; get_type(rec) == XLT_PAIR ; rec = cdr(rec) ) {
			el = car(rec);
			if ( get_type(el) != XLT_PAIR )
				continue;
			sym = car(el);
			if ( get_type(sym) != XLT_SYMBOL )
				continue;
			if ( l_strcmp(sym->symbol.data,_dir) )
				continue;
			dt = get_el(el,1);
			if ( get_type(dt) != XLT_STRING )
				continue;
			al1 = d_alloc(sizeof(*al1));
			al1->url = ll_copy_str(dt->string.data);
			al1->next = a;
			a = al1;
		}
	}
	return a;
}

void
print_around_list(LUMP_AROUND_LIST * a)
{
	for ( ; a ; a = a->next ) {
		printf(" %s",n_string(std_cm,a->url));
	}
	printf("\n");
}

void
free_around_list2(LUMP_AROUND_LIST * a)
{
LUMP_AROUND_LIST * a1;
	for ( ; a ; ) {
		a1 = a->next;
		d_f_ree(a->url);
		d_f_ree(a);
		a = a1;
	}
}


XL_SEXP * 
remote_fetch_lump(int ses,URL * u,int err_f)
{
XL_SEXP * ret;
XL_SEXP * gt;
L_CHAR * f;
void gc_gb_sexp();


	gc_push(0,0,"remote_fetch");
	gt = get_symbol(l_string(std_cm,"Get"));
	set_attribute(gt,
		l_string(std_cm,"mode"),
		l_string(std_cm,"lump"));

	f = get_url_filepath(u);

	ret = remote_session(
		gblisp_top_env0,
		ses,
		u,
		l_string(std_cm,"gbstd"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Get"),
		List(List(gt,
			get_string(f),
			-1),
			-1),
		0,0,0,0);
	d_f_ree(f);

	if ( err_f && get_type(ret) != XLT_PAIR )
		ret = 0;
	gc_pop(ret,gc_gb_sexp);
	return ret;
}



LUMP_ROUTE *
compose_lr(URL * u,LUMP_ROUTE * lr1,LUMP_ROUTE * lr2,L_CHAR * comein)
{
LUMP_ROUTE * lr3, * lr4;
URL uu;
	for ( lr3 = lr2 ; lr3 ; lr3 = lr3->next ) {
		get_url2(&uu,lr3->dir);
		if ( url_cmp(u,&uu) == 0 ) {
			free_url(&uu);
			continue;
		}
		free_url(&uu);
		lr4 = search_lr(lr1,lr3->lump_crd);
		if ( lr4 ) {
			if ( lr3->distance + 1 < lr4->distance ) {
				lr4->distance = lr3->distance + 1;
				if ( lr4->dir )
					d_f_ree(lr4->dir);
				lr4->dir = ll_copy_str(comein);
			}
		}
		else {
			lr1 = insert_lr(lr1,lr3,1,comein);
		}
	}
	return lr1;
}




int
cmp_lr(LUMP_ROUTE * lr1,LUMP_ROUTE * lr2)
{
	for ( ; lr1 && lr2 ; lr1 = lr1->next , lr2 = lr2->next ) {
		if ( l_strcmp(lr1->lump_crd,lr2->lump_crd) )
			return -1;
		if ( l_strcmp(lr1->dir,lr2->dir) )
			return -1;
		if ( lr1->pri != lr2->pri )
			return -1;
		if ( lr1->distance != lr2->distance )
			return -1;
	}
	if ( lr1 == 0 && lr2 == 0 )
		return 0;
	return -1;
}

void
get_my_url(URL * u,L_CHAR * url_str)
{
static int local_ip;
int p;

	if ( local_ip == 0 )
		local_ip = get_xllisp_site_ip().d.v4;

	p = get_my_port();
	get_url2(u,url_str);
	if ( u->proto == 0 )
		u->proto = nl_copy_str(std_cm,"xlp");
	if ( u->server == 0 )
		u->server = ll_copy_str(get_xllisp_site());
	if ( u->port == 0 )
		u->port = p;
	if ( u->db[0] != '/' ) {
	L_CHAR * buf;
	int len;
		len = l_strlen(u->db);
		buf = d_alloc(sizeof(L_CHAR)*(len+2));
		l_strcpy(&buf[1],u->db);
		buf[0] = '/';
		d_f_ree(u->db);
		u->db = buf;
	}
}

XL_SEXP *
fileimage_of_lr(LUMP_OPT * opt,LUMP_ROUTE * lr)
{
XL_SEXP * ret;
XL_SEXP * option;

	ret = 0;
	option = 0;
	for ( ; lr ; lr = lr->next ) {
		ret = cons(
			List(n_get_symbol("entry"),
				get_string(lr->lump_crd),
				get_string(lr->dir),
				get_integer(lr->pri,0),
				get_integer(lr->distance,0),
				get_integer(lr->radius,0),
				-1),
			ret);
	}
	if ( opt ) {
		if ( opt->destroy ) {
			option = cons(
				List(n_get_symbol("destroy"),
					get_integer(opt->destroy,0),
					-1),
				option);
		}
		if ( opt->launch ) {
			option = cons(
				List(n_get_symbol("launch"),
					get_integer(opt->launch,0),
					-1),
				option);
		}
		if ( opt->lump ) {
			option = cons(
				List(n_get_symbol("lump"),
					get_string(opt->lump),
					-1),
				option);
		}
		if ( opt->fade_time ) {
			option = cons(
				List(n_get_symbol("fade"),
					get_integer(opt->fade_time,0),
					get_integer(opt->fade_interval,0),
					-1),
				option);
		}
	}
	if ( option )
		ret = cons(cons(n_get_symbol("option"),option),ret);
	ret = cons(n_get_symbol("lump-info"),ret);
	return ret;
}

void
save_lr(URL * u,LUMP_ROUTE * lr,LUMP_OPT * opt)
{
XL_SEXP * gt;
L_CHAR * filename;
STREAM * st;
L_CHAR * _f;
	_f = get_url_filepath(u);
	if ( path_check(_f) == 0 ) {
		log_printf(LOG_DEBUG,LOG_LAYER_GB,0,"save_lr CHECK ERROR %ls\n",_f);
		d_f_ree(_f);
		return;
	}
	d_f_ree(_f);

	gc_push(0,0,"save_lr");
	gt = n_get_symbol("?xl");
	set_attribute(gt,
		l_string(std_cm,"version"),
		l_string(std_cm,"0.1"));
	set_attribute(gt,
		l_string(std_cm,"encoding"),
		l_string(std_cm,"EUC-JP"));
	filename = get_access_path(u,".lmp");
	st = s_open_file(
		n_string(std_cm,filename),
		O_CREAT|O_TRUNC|O_RDWR,
		0644);
	if ( st == 0 ) {
		d_f_ree(filename);
		gc_pop(0,0);
		return;
	}
	print_sexp(
		st,
		List(	List(gt,-1),
			fileimage_of_lr(opt,lr),
			-1),
		PF_MULTI_ROOT|PF_INDENT);
	s_printf(st,"\n");
	s_close(st);
	d_f_ree(filename);
	gc_pop(0,0);
}

LUMP_ROUTE *
filter_lr(LUMP_ROUTE * lr)
{
int cnt;
LUMP_ROUTE ** lrp, * lr1;

	for ( lrp = &lr ; *lrp ; ) {
		lr1 = *lrp;
		if ( lr1->radius <= lr1->distance ) {
			*lrp = lr1->next;
			lr1->next = 0;
			free_lr(lr1);
		}
		else {
			lrp = &lr1->next;
		}
	} 
	cnt = 0;
	for ( lrp = &lr ; *lrp ; lrp = &(*lrp)->next , cnt ++ ) {
		if ( cnt >= LUMP_MAX )
			break;
	}
	for ( ; *lrp ; ) {
		lr1 = *lrp;
		*lrp = lr1->next;
		lr1->next = 0;
		free_lr(lr1);
	}
	return lr;
}

void
_trigger_lr(int ses,L_CHAR * url)
{
URL u;
int p;
int local_ip;
L_CHAR * path;
XL_SEXP * gt;
	p = get_my_port();
	local_ip = get_xllisp_site_ip().d.v4;
	get_url2(&u,url);
	if ( u.server == 0 && u.port == 0 ) {
		u.port = p;
	}
	path = get_url_filepath(&u);
	if ( cmp_site(u.server,0,u.port,
			0,local_ip,p) == 0 ) {
		insert_tick_que(0,path,TQT_LMP,TQL_LUMP);
	}
	else {

		gc_push(0,0,"remote_fetch");

		gt = n_get_symbol("MPTrigger");
		set_attribute(gt,
			l_string(std_cm,"mode"),
			l_string(std_cm,"lump"));

		remote_session(
			gblisp_top_env0,
			ses,
			&u,
			l_string(std_cm,"gbstd"),
			l_string(std_cm,"user"),
			l_string(std_cm,"Get"),
			List(List(gt,
				get_string(path),
				-1),
				-1),
			0,0,1,0);

		gc_pop(0,0);
	}
	free_url(&u);
	d_f_ree(path);
}

void
trigger_lr(int ses,LUMP_AROUND_LIST * a)
{
	for ( ; a ; a = a->next )
		_trigger_lr(ses,a->url);
}

LUMP_ROUTE *
get_dist0(LUMP_ROUTE * lr)
{
LUMP_ROUTE * ret;
	ret = 0;
	for ( ; lr ; lr = lr->next ) {
		if ( lr->distance )
			break;
		ret = insert_lr(ret,lr,0,0);
	}
	return ret;
}

LUMP_ROUTE *
set_dist0(LUMP_ROUTE * lr,URL * u)
{
LUMP_ROUTE lr0;
	lr0.lump_crd = get_url_str2(u);
	lr0.dir = l_string(std_cm,"");
	lr0.pri = get_xltime();
	lr0.distance = 0;
	lr0.radius = DEFAULT_TTL-1;
	return insert_lr(lr,&lr0,0,0);
}

int
check_launch(LUMP_ROUTE * lr,URL * me)
{
URL u;
int same,other;
LUMP_ROUTE * lrp;

	same = 0;
	other = 0;
	for ( lrp = lr ; lrp ; lrp = lrp->next ) {
		get_url2(&u,lrp->lump_crd);
		if ( l_strcmp(u.server,me->server) == 0 &&
				u.port == me->port )
			same ++;
		else	other ++;
		free_url(&u);
	}
	if ( same <= 1 && other == 0 )
		return 1;
	if ( same == 0 )
		return 1;
	return 0;
}



int
destroy_check(LUMP_ROUTE * lr)
{
LUMP_ROUTE * lr0;
URL me;
int ret;
URL u;
int same,other;


	if ( lr == 0 )
		return 0;
	if ( lr->distance )
		return 0;

	lr0 = lr;
	lr = lr->next;

	get_url2(&me,lr0->lump_crd);

	same = 0;
	other = 0;
	for ( ; lr ; lr = lr->next ) {
		get_url2(&u,lr->lump_crd);
		if ( l_strcmp(u.server,me.server) == 0 &&
				u.port == me.port ) {
			if ( lr->pri <= lr0->pri )
				same ++;
		}
		else	other ++;
		free_url(&u);
	}
	free_url(&me);

	if ( same <= 1 && other == 0 )
		return 0;
	if ( same == 0 )
		return 0;
	return 1;





	if ( check_launch(lr,&me) )
		ret = 0;
	else	ret = 1;
	free_url(&me);
	return ret;
}

int
check_loop_lump(LUMP_ROUTE ** lr)
{
int ret;
LUMP_ROUTE ** lrp;
LUMP_ROUTE * lr1;

	ret = 0;
	for ( lrp = lr ; *lrp ; ) {
		lr1 = *lrp;
		if ( (max_hops && lr1->distance > max_hops) ||
				check_loop_max(lr1->distance) < 0 ) {
ss_printf("cut lump %i\n",max_hops);
			ret = 1;
			*lrp = lr1->next;
			lr1->next = 0;
			free_lr(lr1);
		}
		else {
			lrp = &lr1->next;
		}
	}
	return ret;
}

void
check_my_lump(int ses,L_CHAR * filename)
{
XL_SEXP * chi, * par;
LUMP_AROUND_LIST * a, * a1;
URL u1,u2;
XL_SEXP * ret;
LUMP_ROUTE * lr, * lr1, * my_lr,* lr0;
LUMP_OPT opt;
char * path;
int fd;
L_CHAR * cc;
int loop_ditect;
unsigned int now;

	init_lump_opt(&opt);
	gc_push(0,0,"check_my_kump make_list");
	chi = filtering_crd(get_crd_chi(filename));
	a = get_around_list(0,chi,"src");
	par = filtering_crd(get_crd_par(filename));
	a = get_around_list(a,par,"dest");

	get_my_url(&u1,filename);

	cc = ll_copy_str(get_url_str2(&u1));
	ret = local_fetch(0,&u1,".lmp");
	my_lr = get_lr(&opt,ret,cc);
	d_f_ree(cc);

	gc_pop(0,0);



	lr = get_dist0(my_lr);
	for ( a1 = a ; a1 ; a1 = a1->next ) {
		get_url2(&u2,a1->url);
		gc_push(0,0,"check_my_lump");
		if ( l_strcmp(u2.server,u1.server) == 0 &&
				u2.port == u1.port )
			ret = local_fetch(0,&u2,".lmp");
		else	ret = remote_fetch_lump(ses,&u2,1);
		lr1 = get_lr(0,ret,0);
		lr = compose_lr(&u1,lr,lr1,a1->url);
		free_lr(lr1);
		gc_pop(0,0);
		free_url(&u2);
	}

	if ( lr == 0 || (lr->distance && check_launch(lr,&u1)) ) {
		if ( opt.launch == 0 ) {
			opt.launch = get_xltime() + 
				LUMP_LAUNCH_MIN + 
				(rand()%
				(LUMP_LAUNCH_MAX-LUMP_LAUNCH_MIN));
			opt.flag = 1;
		}
		else if ( opt.launch <= get_xltime() ) {
			lr = set_dist0(lr,&u1);
			opt.launch = 0;
			opt.flag = 1;
		}
	}
	else if ( destroy_check(lr) ) {
		if ( opt.destroy == 0 ) {
			opt.destroy = get_xltime() + 
				LUMP_DESTROY_MIN + 
				(rand()%
				(LUMP_DESTROY_MAX-LUMP_DESTROY_MIN));
			opt.flag = 1;
		}
		else if ( opt.destroy <= get_xltime() ) {
			lr0 = lr;
			lr = lr->next;
			lr0->next = 0;
			free_lr(lr0);
			opt.destroy = 0;
			if ( opt.lump )
				d_f_ree(opt.lump);
			opt.lump = 0;
			opt.flag = 1;
		}
	}
	else {
		if ( opt.launch ) {
			opt.launch = 0;
			opt.flag = 1;
		}
		if ( opt.destroy ) {
			opt.destroy = 0;
			opt.flag = 1;
		}
	}

	if ( lr && lr->distance == 0 )  {
		if ( opt.lump == 0 ) {
		LUMP_INFO info;
		new:
			info.crd = ll_copy_str(get_url_str2(&u1));
			opt.lump = get_lump_path(new_lump());

log_printf(LOG_DEBUG,LOG_LAYER_GB,0,"new lump = %s",n_string(std_cm,opt.lump));

			save_lump_info(opt.lump,&info);
/*
printf("opt.lum1 = %s\n",n_string(std_cm,opt.lump));
*/
			opt.flag = 1;
			free_lump_info(&info);
		}
		else {
			path = get_lump_info_path(opt.lump);
			fd = open(path,O_RDONLY);
			if ( fd < 0 ) {
log_printf(LOG_DEBUG,LOG_LAYER_GB,0,"cannot open the lump path %s",path);

				d_f_ree(opt.lump);
				d_f_ree(path);
				opt.lump = 0;
				goto new;
			}
			close(fd);
			d_f_ree(path);
		}
	}
	loop_ditect = check_loop_lump(&lr);

	lr = filter_lr(lr);
	if ( cmp_lr(lr,my_lr) || opt.flag || loop_ditect ) {
		opt.fade_interval = FADE_INTERVAL_MIN;
		opt.fade_time = get_xltime() + opt.fade_interval;
		save_lr(&u1,lr,&opt);
		trigger_lr(ses,a);
	}
	if ( opt.fade_time ) {
		if ( opt.fade_time <= get_xltime() ) {
			opt.fade_interval = opt.fade_interval * 2
				+ get_xltime() - opt.fade_time;
			if ( opt.fade_interval >= FADE_INTERVAL_MAX ) {
				opt.fade_time = 0;
				opt.fade_interval = 0;
			}
			else {
				opt.fade_time = get_xltime() 
						+ opt.fade_interval;
			}
			save_lr(&u1,lr,&opt);
		}
	}
	now = get_xltime();
	if ( opt.destroy ) {
		if ( now < opt.destroy )
			insert_tick_que(opt.destroy-get_xltime(),
				filename,TQT_LMP,TQL_LUMP);
		else	insert_tick_que(0,
				filename,TQT_LMP,TQL_LUMP);
	}
	if ( opt.launch ) {
		if ( now < opt.launch )
			insert_tick_que(opt.launch-get_xltime(),
				filename,TQT_LMP,TQL_LUMP);
		else	insert_tick_que(0,
				filename,TQT_LMP,TQL_LUMP);
	}
	if ( opt.fade_time ) {
		insert_tick_que(opt.fade_interval,filename,TQT_LMP,
					TQL_LUMP);
	}
	free_url(&u1);
	free_lr(lr);
	free_lr(my_lr);
	free_around_list2(a);
	free_lump_opt(&opt);
}


int
tick_lump(TICK_QUE * t,unsigned int tim)
{
int d;

	d = tim - t->invoke_time;
	if ( d > 0 ) {
		if ( d > 31 )
			d = LUMP_DELAY;
		else d = 1<<(d-1);
		if ( d > LUMP_DELAY )
			d = LUMP_DELAY;
	}
	else	d = 0;
	insert_tick_que(
		d,
		t->filename,TQT_LMP,
		TQL_LUMP);
	return 0;
}


XL_SEXP *
_lump_trigger_before(int ses,URL * u,L_CHAR * db,L_CHAR * target,int interval)
{
URL u2;
L_CHAR * f;
XL_SEXP * ret;

	copy_url(&u2,u);
	if ( u2.db )
		d_f_ree(u2.db);
	u2.db = ll_copy_str(db);
	if ( u2.resource )
		d_f_ree(u2.resource);
	u2.resource = nl_copy_str(std_cm,"db.pmd");
	f = get_url_filepath(&u2);
	gc_push(0,0,"_lump_trigger");


//ss_printf("LTB %ls : %ls %i\n",get_url_str2(&u2),target,interval);
	ret = remote_session(
		gblisp_top_env0,
		ses,
		&u2,
		l_string(std_cm,"gbpmd"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Set"),
		List(List(n_get_symbol("trigger"),
			get_string(f),
			get_string(target),
			get_integer(interval,0),
			-1),
			-1),
		0,0,0,0);

	gc_pop(ret,gc_gb_sexp);
	d_f_ree(f);
	free_url(&u2);
	return ret;
}

void lump_trigger_1(MP_TASK_ENV *,MP_TASK_T *);
void lump_trigger_2(MP_TASK_ENV *,MP_TASK_T *);
void lump_trigger_3(MP_TASK_ENV *,MP_TASK_T *);
void lump_trigger_4(MP_TASK_ENV *,MP_TASK_T *);
void lump_trigger_5(MP_TASK_ENV *,MP_TASK_T *);
void new_lump_trigger_3(MP_TASK_T * tt1,int index,L_CHAR * crd,L_CHAR *target);

void
lump_trigger_free(MP_TASK_T * t)
{
LUMP_TRIGGER_MP_T * arg;
	arg = (LUMP_TRIGGER_MP_T*)t->arg;
	if ( arg->crd )
		d_f_ree(arg->crd);
	if ( arg->target )
		d_f_ree(arg->target);
	d_f_ree(arg);
}

void
new_lump_trigger(MP_TASK_T * tt1,int index,L_CHAR * crd,L_CHAR * target)
{
LUMP_TRIGGER_MP_T * arg;
URL u;
MP_TASK_T * tt2;

	tt2 = new_queue_node(sizeof(*tt2));
	arg = d_alloc(sizeof(*arg));
	arg->crd = ll_copy_str(crd);
	arg->target = ll_copy_str(target);
	arg->org_thread = tt1;
	arg->index = index;

	get_url2(&u,crd);
	tt2->h.key = get_server_key(&u,"lump_trigger_1");
	free_url(&u);
	tt2->arg = arg;
	tt2->op = lump_trigger_1;
	tt2->sexp = 0;
	tt2->free_t = lump_trigger_free;

	insert_queue(&mp_task_que,tt2,1);

}

void
new_lump_trigger_3(MP_TASK_T * tt1,int index,L_CHAR * crd,L_CHAR * target)
{
LUMP_TRIGGER_MP_T * arg;
URL u;
MP_TASK_T * tt2;

	tt2 = new_queue_node(sizeof(*tt2));
	arg = d_alloc(sizeof(*arg));
	arg->crd = ll_copy_str(crd);
	arg->target = ll_copy_str(target);
	arg->org_thread = tt1;
	arg->index = index;

	get_url2(&u,crd);
	tt2->h.key = get_server_key(&u,"lump_trigger_3");
	free_url(&u);
	tt2->arg = arg;
	tt2->op = lump_trigger_3;
	tt2->sexp = 0;
	tt2->free_t = lump_trigger_free;

	insert_queue(&mp_task_que,tt2,1);

}

void
lump_trigger_1(MP_TASK_ENV * te,MP_TASK_T * tt)
{
LUMP_TRIGGER_MP_T * arg;
MP_TASK_T * tt_org;
ORG_THREAD_MP_T *org;
URL u1;
int len;

	arg = tt->arg;
	tt_org = arg->org_thread;
	org = tt_org->arg;


	len = l_strlen(arg->crd);
	if ( l_strcmp(&arg->crd[len-4],l_string(std_cm,".crd")) ) {
		lock_task(tick_que_lock);
		org->lump_pmd_interval[arg->index] = 0;
		org->lump_pmd_interval_max ++;
		org->lump_count ++;
		org->lump_fetch_count ++;
		unlock_task(tick_que_lock,"lump_trigger_1");

		ping_mapping_last_3(te,tt_org);

		free_mp_task_t(tt);
		return;
	}


	get_url2(&u1,arg->crd);

	tt->sexp = remote_fetch_lump(te->ses,&u1,0);

	if ( tt->h.key )
		d_f_ree(tt->h.key);
	tt->h.key = get_server_key(&u1,"lump_trigger_2");
	tt->op = lump_trigger_2;

	insert_queue(&mp_task_que,tt,1);

	free_url(&u1);
}


void
lump_trigger_2(MP_TASK_ENV * te,MP_TASK_T * tt)
{
LUMP_ROUTE * lr, * lr1;
XL_SEXP * r;
LUMP_TRIGGER_MP_T * arg;
MP_TASK_T * tt_org;
ORG_THREAD_MP_T *org;
int c;

	arg = tt->arg;
	tt_org = arg->org_thread;
	org = tt_org->arg;

	r = tt->sexp;
	lr = get_lr(0,r,0);

	for ( c = 0, lr1 = lr ; lr1 ; lr1 = lr1->next, c++  );

	for ( lr1 = lr ; lr1 ; lr1 = lr1->next ) {
		new_lump_trigger_3(tt_org,arg->index,lr1->lump_crd,
				arg->target);
	}

	lock_task(tick_que_lock);
	org->lump_pmd_interval_max += c;
	org->lump_fetch_count ++;		
	unlock_task(tick_que_lock,"lump_trigger_2");

	free_lr(lr);
	ping_mapping_last_3(te,tt_org);
	free_mp_task_t(tt);
}


void
lump_trigger_3(MP_TASK_ENV * te,MP_TASK_T * tt)
{
LUMP_TRIGGER_MP_T * arg;
URL u2;

	arg = tt->arg;

	get_url2(&u2,arg->crd);
	tt->sexp = remote_fetch_lump(te->ses,&u2,0);

	if ( tt->h.key )
		d_f_ree(tt->h.key);
	tt->h.key = get_server_key(&u2,"lump_trigger_4");
	tt->op = lump_trigger_4;

	insert_queue(&mp_task_que,tt,1);

	free_url(&u2);

}


void
lump_trigger_4(MP_TASK_ENV * te,MP_TASK_T * tt)
{
LUMP_TRIGGER_MP_T * arg;
LUMP_OPT opt2;
ORG_THREAD_MP_T * org;
MP_TASK_T * tt_org;
LUMP_ROUTE * lr2;
URL u2;

	arg = tt->arg;
	tt_org = arg->org_thread;
	org = tt_org->arg;

	init_lump_opt(&opt2);
	lr2 = get_lr(&opt2,tt->sexp,0);
	free_lr(lr2);

	if ( opt2.lump == 0  ) {
		org->lump_count ++;
		ping_mapping_last_3(te,tt_org);
		free_lump_opt(&opt2);
		free_mp_task_t(tt);
		return;
	}

	get_url2(&u2,arg->crd);
/*
ss_printf("TRIGGER %ls --\n\t%ls\n\t%ls\n\t%ls\n",
tt_org->tq->filename,
arg->crd,
opt2.lump,arg->target);
*/
	tt->sexp = _lump_trigger_before(te->ses,&u2,
			opt2.lump,arg->target,
			org->pmd_interval);

	free_lump_opt(&opt2);

	if ( tt->h.key )
		d_f_ree(tt->h.key);
	tt->h.key = get_server_key(&u2,"lump_trigger_5");
	tt->op = lump_trigger_5;

	insert_queue(&mp_task_que,tt,1);

	free_url(&u2);
}

void
lump_trigger_5(MP_TASK_ENV * te,MP_TASK_T * tt)
{
LUMP_TRIGGER_MP_T * arg;
ORG_THREAD_MP_T * org;
MP_TASK_T * tt_org;
int __ret;

	arg = tt->arg;
	tt_org = arg->org_thread;
	org = tt_org->arg;

	if ( get_type(tt->sexp) != XLT_INTEGER )
		__ret = 0;
	else	__ret = tt->sexp->integer.data;

	if ( org->lump_pmd_interval[arg->index] < __ret )
		org->lump_pmd_interval[arg->index] = __ret;
	org->lump_count ++;

	ping_mapping_last_3(te,tt_org);
	free_mp_task_t(tt);
}

