/**********************************************************************
 
	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	<fcntl.h>
#include	<stdlib.h>
#include	"memory_debug.h"
#include	"xl.h"
#include	"xllisp.h"
#include	"gbacrp.h"
#include	"mp.h"
#include	"gbmp.h"
#include	"xldir.h"

void gc_tick_notin_tick();

extern struct path_pair * start;
int idle_interval;

DIR_LIST * marge_dir_list(DIR_LIST * d1,DIR_LIST * d2);
L_CHAR * get_full_url(L_CHAR * current,L_CHAR * url);
L_CHAR * get_full_my_url(L_CHAR * current);
void set_target(MP_TASK_ENV * te,MP_TASK_T * t);
void set_target_2(MP_TASK_ENV * te,MP_TASK_T * t);
void ping_mapping_last(MP_TASK_ENV * te,MP_TASK_T * t,int pitch);
void
new_org_thread(MP_TASK_T * t,
	int force,
	L_CHAR * src,
	L_CHAR * dest,
	L_CHAR * map,
	int dp,
	unsigned int mod,
	int interval,
	int _interval,
	int time,
	int pmd_interval,
	int pmd_time,
	int tat);
void ping_mapping_last_2(MP_TASK_ENV * te,MP_TASK_T * t);

extern SYS_QUEUE mp_task_que;
extern unsigned int tqt_tat[TQT_MAX];
extern int smap_start_time,smap_end_time;
extern SEM	tick_que_lock;


void
set_idle_interval(float p)
{
MP_WORK mpw;
TQ_STATISTICS tqs;


	get_mp_work(&mpw,0);
	tick_que_statistics(&tqs);
	mpw.total_maps = tqs.maps + get_map_nos();
	idle_interval = 2*idle_interval*(1-p);
	if ( idle_interval < mpw.total_maps*MAPPING_PING_INTERVAL_UNIT )
		idle_interval = mpw.total_maps*MAPPING_PING_INTERVAL_UNIT;
	if ( idle_interval < 10 )
		idle_interval = 10;
	set_mp_work(&mpw);
}

int
get_idle_interval()
{
	return idle_interval - (rand()/(float)RAND_MAX)*0.1*idle_interval;
}

int
mp_counter()
{
int cnt,cc;
MP_WORK mpw;
TQ_STATISTICS tqs;
int interval;
L_CHAR * lpath, * p;
DIR_LIST * d, * d1, * d2;
struct path_pair * wp;

	get_mp_work(&mpw,0);
	gc_push(0,0,"mp_counter");
	d = NULL;
	for(wp=start;wp != NULL;wp=wp->next)
	{
		lpath = get_append_path(wp->docs_path,"/**/*.crd");
		d1 = get_dir(n_string(std_cm,lpath),0,0,0,DLF_FILE);
		d_f_ree(lpath);
		d = marge_dir_list(d,d1);
		lpath = get_append_path(wp->docs_path,"/*.crd");
		d2 = get_dir(n_string(std_cm,lpath),0,0,0,DLF_FILE);
		d_f_ree(lpath);
		d = marge_dir_list(d,d2);
	}
	cnt = 0;
	for ( d1 = d ; d1 ; d1 = d1->next ) {
/*printf("-- %s\n",d1->name);*/
		p = (L_CHAR *)0;
		lpath = d_alloc(sizeof(L_CHAR)*(strlen(d1->name)+2));
		lpath = nl_copy_str(std_cm,d1->name);
		p = get_url_path(lpath,p);
		gc_push(0,0,"mp_counter");
		cc = list_length(
			get_crd_par(p));
		if ( cc > 0 )
			cnt += cc;
		cc = list_length(
			get_crd_chi(p));
		if ( cc > 0 )
			cnt += cc;
		gc_pop(0,0);
		d_f_ree(lpath);
	}
	free_dir_list(d2);
	mpw.total_map_references = cnt;

	tick_que_statistics(&tqs);
	mpw.total_maps = tqs.maps;
	gc_pop(0,0);
	set_mp_work(&mpw);
	interval = mpw.total_map_references * MP_COUNTER_INTERVAL_UNIT;
	if ( interval < 2*mpw.interval_avg )
		interval = 2*get_idle_interval();
	if ( interval < MP_COUNTER_MIN_INTERVAL )
		return MP_COUNTER_MIN_INTERVAL;
	return interval;
}




XL_SEXP *
get_mapping(L_CHAR * filename,char * prefix)
{
URL u;
L_CHAR * buf;


XL_SEXP * s, * ret;
XL_SEXP * get_op();
void gc_gb_sexp();
XL_SEXP * r;

	gc_push(0,0,"get_mapping");
	get_url2(&u,filename);
	buf = get_url_filepath(&u);
	free_url(&u);
	buf = get_append_path(buf,prefix);
	s = n_get_symbol("Get");
	ret = get_op(gblisp_top_env0,s,buf);
	d_f_ree(buf);
	

	switch ( get_type(ret) ) {
	case XLT_ERROR:
	case XLT_NULL:

		ret = 0;
	case XLT_PAIR:
		for ( r = ret ; get_type(r) ; r = cdr(r) );
		break;
	default:
		ret = 0;
	}
	gc_pop(ret,gc_gb_sexp);
	return ret;
}

XL_SEXP *
get_mapping_with_alias(int ses,L_CHAR * filename,L_CHAR ** ret_map)
{
XL_SEXP * meta;
XL_SEXP * a, * a_sym;
L_CHAR * t, * target;
URL u;
L_CHAR * f;
XL_SEXP * ret;
XL_SEXP * get_sym;

	*ret_map = 0;
	meta = get_mapping(filename,".mta");
	switch ( get_type(meta) ) {
	case XLT_ERROR:
	case XLT_NULL:
		return meta;
	case XLT_PAIR:
		break;
	default:
		return 0;
	}
	a = get_el_by_symbol(get_el(meta,1),
		l_string(std_cm,"alias"),0);
	if ( a == 0 ) {
		*ret_map = get_full_my_url(filename);
		return meta;
	}
	a_sym = car(a);
	t = get_sf_attribute(a_sym->symbol.field,
			l_string(std_cm,"target"));

	if ( t == 0 )
		return meta;
	target = get_full_url(filename,t);
	*ret_map = target;
	get_url2(&u,target);

	f = get_url_filepath(&u);

	get_sym = n_get_symbol("Get");
	set_attribute(get_sym,
		l_string(std_cm,"mode"),
		l_string(std_cm,"meta"));
/*
ss_printf("REMOTE_SESSION = %ls %ls\n",get_url_str2(&u),f);
*/
	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(get_sym,
				get_string(f),
				-1),
			-1),
		0,0,0,0);

	free_url(&u);
	d_f_ree(f);

	return ret;

}

int
check_mapping(
	L_CHAR * filename,
	unsigned int* __time,
	unsigned int * __interval,
	unsigned int* __pmd_time,
	unsigned int * __pmd_interval)
{
XL_SEXP * mpt;
unsigned int interval;
unsigned int time,now;
unsigned int pmd_interval;
unsigned int pmd_time;
XL_SEXP * _interval, * _time;
XL_SEXP * _pmd_interval, * _pmd_time;
XL_SEXP * xl_GetElement();
MP_WORK mpw;

	mpt = get_mapping(filename,".mpt");
	if ( mpt == 0 ) {
		get_mp_work(&mpw,0);
		pmd_interval = interval = mpw.interval_avg;
		pmd_time = time = get_xltime();
		goto ok;
	}
	_interval = xl_GetElement(gblisp_top_env0,
		List(n_get_symbol("GetElement"),
			get_el(mpt,1),
			n_get_symbol("interval"),
			-1),0,0);
	_interval = get_el(_interval,1);
	switch ( get_type(_interval) ) {
	case XLT_INTEGER:
		interval = _interval->integer.data;
		break;
	default:
		interval = MAPPING_INTERVAL_UNIT;
		break;
	}
	_time = xl_GetElement(gblisp_top_env0,
		List(n_get_symbol("GetElement"),
			get_el(mpt,1),
			n_get_symbol("invoke-time"),
			-1),0,0);
	_time = get_el(_time,1);
	switch ( get_type(_time) ) {
	case XLT_INTEGER:
		time = _time->integer.data;
		break;
	default:
		time = 0;
		break;
	}

	_pmd_time = xl_GetElement(gblisp_top_env0,
		List(n_get_symbol("GetElement"),
			get_el(mpt,1),
			n_get_symbol("invoke-pmd-time"),
			-1),0,0);
	_pmd_time = get_el(_pmd_time,1);
	switch ( get_type(_pmd_time) ) {
	case XLT_INTEGER:
		pmd_time = _pmd_time->integer.data;
		break;
	default:
		pmd_time = 0;
		break;
	}

	_pmd_interval = xl_GetElement(gblisp_top_env0,
		List(n_get_symbol("GetElement"),
			get_el(mpt,1),
			n_get_symbol("pmd-interval"),
			-1),0,0);
	_pmd_interval = get_el(_pmd_interval,1);
	switch ( get_type(_pmd_interval) ) {
	case XLT_INTEGER:
		pmd_interval = _pmd_interval->integer.data;
		break;
	default:
		pmd_interval = 0;
		break;
	}

	now = get_xltime();
	if ( time > now && pmd_time > now ) {
		if ( interval < 10 )
			interval = 10;
		if ( pmd_interval < 10 )
			pmd_interval = 10;
		*__time = time;
		*__interval = interval;
		*__pmd_time = pmd_time;
		*__pmd_interval = pmd_interval;
		return -1;
	}
ok:
	if ( interval < 10 )
		interval = 10;
	if ( pmd_interval < 10 )
		pmd_interval = 10;
	*__time = time;
	*__interval = interval;
	*__pmd_time = pmd_time;
	*__pmd_interval = pmd_interval;
	return 0;
}

int
set_mapping(
	L_CHAR * filename,
	unsigned int time,
	unsigned int interval,
	unsigned int pmd_time,
	unsigned int pmd_interval)
{
XL_SEXP * mpt, * gv;
CALL_LOCK_DESCRIPTER lr;
L_CHAR * _filename;
XL_SEXP * xl_GetElement();
STREAM * st;

	gv = n_get_symbol("?xl");
	set_attribute(gv,
		l_string(std_cm,"version"),
		l_string(std_cm,"1.0"));
	set_attribute(gv,
		l_string(std_cm,"encoding"),
		l_string(std_cm,"EUC-JP"));
	mpt = List(
		List(gv,-1),
		List(n_get_symbol("mp-sts"),
			List(n_get_symbol("interval"),
				get_integer(interval,0),
				-1),
			List(n_get_symbol("invoke-time"),
				get_integer(time,0),
				-1),
			List(n_get_symbol("pmd-interval"),
				get_integer(pmd_interval,0),
				-1),
			List(n_get_symbol("invoke-pmd-time"),
				get_integer(pmd_time,0),
				-1),
			-1),
			-1);

        _filename = get_xlsys(filename);
	_filename = get_append_path(_filename,".mpt");

	
	lr = call_lock(_filename,CLT_WRITE_LOCK,0,0);

	st = s_open_file(
		n_string(std_cm,_filename),
		O_CREAT|O_TRUNC|O_RDWR,
		0644);
	if ( st == 0 )
		goto end;
	print_sexp(
		st,
		mpt,
		PF_MULTI_ROOT|PF_INDENT);
	s_printf(st,"\n");
	s_close(st);

end:

	call_unlock(lr);

	d_f_ree(_filename);
	return 0;
}


int
set_par_chi(L_CHAR * filename,XL_SEXP * s,char * prefix)
{
CALL_LOCK_DESCRIPTER lr;
L_CHAR * _filename;
XL_SEXP * xl_GetElement();
STREAM * st;
XL_SEXP * gv;
        _filename = get_xlsys(filename);
	_filename = get_append_path(_filename,prefix);
		
	gv = n_get_symbol("?xl");

	lr = call_lock(_filename,CLT_WRITE_LOCK,0,0);

	st = s_open_file(
		n_string(std_cm,_filename),
		O_CREAT|O_TRUNC|O_RDWR,
		0644);
	if ( st == 0 )
		goto end;
	print_sexp(
		st,
		s,
		PF_MULTI_ROOT);
	s_printf(st,"\n");
	s_close(st);

end:
	call_unlock(lr);
	d_f_ree(_filename);
	return 0;
}



void
org_thread_free(MP_TASK_T * t)
{
ORG_THREAD_MP_T * arg;
	arg = (ORG_THREAD_MP_T*)t->arg;
	d_f_ree(arg->src);
	d_f_ree(arg->dest);
	d_f_ree(arg->map);
	d_f_ree(arg);
	t->arg = 0;
}

void
set_target_free(MP_TASK_T * t)
{
SET_TARGET_MP_T * arg;
	arg = (SET_TARGET_MP_T *)t->arg;
	d_f_ree(arg->target);
	d_f_ree(arg->prefix);
	d_f_ree(arg);
	t->arg = 0;
}

void
new_set_target(MP_TASK_T * t,
	int thread_no,
	L_CHAR * target,
	char * prefix)
{
SET_TARGET_MP_T * arg;
URL u;
MP_TASK_T * tt;

	tt = new_queue_node(sizeof(*tt));

	arg = d_alloc(sizeof(*arg));
	arg->target = ll_copy_str(target);
	arg->org_thread = t;
	arg->thread_no = thread_no;
	arg->prefix = copy_str(prefix);

	get_url2(&u,target);
	tt->h.key = get_server_key(&u,"set_target_1");
	free_url(&u);
	tt->arg = arg;
	tt->op = set_target;
	tt->sexp = 0;
	tt->free_t = set_target_free;

	insert_queue(&mp_task_que,tt,1);
}

void
new_org_thread(MP_TASK_T * t,
	int force,
	L_CHAR * src,
	L_CHAR * dest,
	L_CHAR * map,
	int dp,
	unsigned int mod,
	int interval,
	int _interval,
	int time,
	int pmd_interval,
	int pmd_time,
	int tat)
{
ORG_THREAD_MP_T * o;
	if ( t->free_t )
		(*t->free_t)(t);
	t->free_t = org_thread_free;
	o = d_alloc(sizeof(*o));
	memset(o,0,sizeof(*o));

	o->force = force;
	o->src = ll_copy_str(src);
	o->dest = ll_copy_str(dest);
	o->map = ll_copy_str(map);
	o->dp = dp;
	o->mod = mod;

	o->interval = interval;
	o->_interval = _interval;
	o->time = time;
	o->pmd_interval = pmd_interval;
	o->pmd_time = pmd_time;
	o->tat = tat;

	t->arg = o;
}


void
set_target(MP_TASK_ENV * te,MP_TASK_T * mp_t)
{
URL u;
XL_SEXP * ret;
XL_SEXP * gt;
L_CHAR * f;
L_CHAR * _target;
int len;

int ses;
L_CHAR * target;
L_CHAR * src;
L_CHAR * dest;
L_CHAR * map;
int dp;
char * prefix;
unsigned int interval;
unsigned int mod;
SET_TARGET_MP_T * t;
ORG_THREAD_MP_T * org;

	t = mp_t->arg;
	org = t->org_thread->arg;

	ses = te->ses;
	target = t->target;
	prefix = t->prefix;
	src = org->src;
	dest = org->dest;
	map = org->map;
	dp = org->dp;
	interval = org->interval;
	mod = org->mod;


	gt = n_get_symbol("Set");
	set_attribute(gt,
		l_string(std_cm,"option"),
		l_string(std_cm,"part"));
	_target = ll_copy_str(target);
	len = l_strlen(_target);
	_target = d_re_alloc(_target,(len+10)*sizeof(L_CHAR));
	l_strcpy(&_target[len],l_string(std_cm,prefix));
	get_url2(&u,_target);
/*
ss_printf("SET_TARGET %ls\n",_target);
*/
	d_f_ree(_target);
	ret = remote_session(
		gblisp_top_env0,
		ses,
		&u,
		l_string(std_cm,"gbstd"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Set"),
		List(List(gt,
			get_string(f = get_url_filepath(&u)),
			List(n_get_symbol("quote"),
				List(n_get_symbol("record"),
					List(n_get_symbol("src"),
						get_string(src),
						-1),
					List(n_get_symbol("dest"),
						get_string(dest),
						-1),
					List(n_get_symbol("map"),
						get_string(map),
						-1),
					List(n_get_symbol("dp"),
						get_integer(dp,0),
						-1),
					List(n_get_symbol("mod"),
						get_integer(mod,
						l_string(std_cm,"sec")),
						-1),
					-1),
				-1),
			get_integer(interval*4,0),
			-1),
			-1),
		0,0,0,0);

	d_f_ree(f);
	mp_t->sexp = ret;
	mp_t->op = set_target_2;
	if ( mp_t->h.key )
		d_f_ree(mp_t->h.key);
	mp_t->h.key = get_server_key(&u,"set_target_2");
	free_url(&u);

	insert_queue(&mp_task_que,mp_t,1);
}


void
set_target_2(MP_TASK_ENV * te,MP_TASK_T * t)
{
/*
ss_printf("++>");
print_sexp(s_stdout,ret,0);
ss_printf("\n");
*/
XL_SEXP * ret;
	ret = t->sexp;
	if ( get_type(ret) == XLT_PAIR ) {
		ret = get_el(ret,1);
		if ( get_type(ret) != XLT_INTEGER )
			ping_mapping_last(te,t,0);
		else	ping_mapping_last(te,t,ret->integer.data);
		return;
	}
	if ( get_type(ret) == XLT_ERROR ) {
		log_print_sexp(LOG_WARNING,LOG_LAYER_GB,0,
			"MP set_target ",
			ret,0);
	}
	ping_mapping_last(te,t,0);
	
}

int
delete_target(int ses,
	L_CHAR * target,L_CHAR * src,L_CHAR * dest,L_CHAR * map,int dp,
	char * prefix)
{
URL u;
XL_SEXP * ret;
XL_SEXP * gt;
L_CHAR * f;
L_CHAR * _target;
int len;
	gt = n_get_symbol("Set");
	set_attribute(gt,
		l_string(std_cm,"option"),
		l_string(std_cm,"delete"));
	_target = ll_copy_str(target);
	len = l_strlen(_target);
	_target = d_re_alloc(_target,(len+10)*sizeof(L_CHAR));
	l_strcpy(&_target[len],l_string(std_cm,prefix));
	get_url2(&u,_target);
	d_f_ree(_target);
	ret = remote_session(
		gblisp_top_env0,
		ses,
		&u,
		l_string(std_cm,"gbstd"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Set"),
		List(List(gt,
			get_string(f = get_url_filepath(&u)),
			List(n_get_symbol("quote"),
				List(n_get_symbol("record"),
					List(n_get_symbol("src"),
						get_string(src),
						-1),
					List(n_get_symbol("dest"),
						get_string(dest),
						-1),
					List(n_get_symbol("map"),
						get_string(map),
						-1),
					-1),
				-1),
			-1),
			-1),
		0,0,0,0);
	d_f_ree(f);
	free_url(&u);
	return 0;
}

L_CHAR * 
get_full_url(L_CHAR * current,L_CHAR * url)
{
char * my_url;
int port;
int len;
L_CHAR * ret;
L_CHAR * p;
	port = get_my_port();
	len = l_strlen(get_xllisp_site());
	p = current;
	my_url = d_alloc(100+len);
	if ( current[0] == '/' )
		sprintf(my_url,"xlp://%s:%i%s",
			n_string(std_cm,get_xllisp_site()),port,
			n_string(std_cm,p));
	else	sprintf(my_url,"xlp://%s:%i/%s",
			n_string(std_cm,get_xllisp_site()),port,
			n_string(std_cm,p));
	ret = compose_url(l_string(std_cm,my_url),url);
	d_f_ree(my_url);
	return ret;
}

L_CHAR * 
get_full_my_url(L_CHAR * current)
{
char * my_url;
int port;
int len,flen;
L_CHAR * ret;
L_CHAR * p;
	port = get_my_port();
	len = l_strlen(get_xllisp_site());
	p = current;
	flen = l_strlen(p);
	my_url = d_alloc(100+len+flen);
	if ( current[0] == '/' )
		sprintf(my_url,"xlp://%s:%i%s",
			n_string(std_cm,get_xllisp_site()),port,
			n_string(std_cm,p));
	else	sprintf(my_url,"xlp://%s:%i/%s",
			n_string(std_cm,get_xllisp_site()),port,
			n_string(std_cm,p));
	ret = nl_copy_str(std_cm,my_url);
	d_f_ree(my_url);
	return ret;
}



unsigned int
get_next_interval(unsigned int p1,unsigned int p2,unsigned int interval,
		int tat)
{
unsigned int max;
unsigned int next_interval;
MP_WORK mpw;
unsigned int ping_interval;
	get_mp_work(&mpw,0);
	if ( p1 == 0 && p2 == 0 )
		return interval;
	if ( p1 == 0 )
		max = p2;
	else if ( p2 == 0 )
		max = p1;
	else if ( p1 < p2 )
		max = p2;
	else	max = p1;
	ping_interval = get_idle_interval();
	next_interval = max*MAPPING_INTERVAL_UNIT;
	next_interval += tat;
	mpw.interval_avg = (mpw.interval_avg*2 + next_interval)/3;
	if ( ping_interval > next_interval )
		next_interval = ping_interval;
	if ( next_interval > 2*interval )
		next_interval = 2*interval;
	if ( next_interval <=  8 )
		return next_interval;
	set_mp_work(&mpw);
	return next_interval - (rand()/(float)RAND_MAX)*0.1*next_interval;
}


unsigned int
get_next_pmd_interval(unsigned int p1,unsigned int p2,unsigned int interval,
		      unsigned int pmd_prev_interval,
		      unsigned int tat)
{
int p_interval;
int next;
MP_WORK mpw;

	get_mp_work(&mpw,0);
	if ( p1 == 0 && p2 == 0 )
		next = interval;
	else if ( p1 == 0 )
		next = p2;
	else if ( p2 == 0 )
		next = p1;
	else if ( p1 > p2 )
		next = p1;
	else	next = p2;
/*
	p_interval = mpw.total_maps*MAPPING_PING_INTERVAL_UNIT;
	if ( next < p_interval ) {
		if ( 2*next < p_interval )
			next = 2*next;
		else	next = p_interval;
	}
*/
	p_interval = get_idle_interval();
	next = next - (rand()/(float)RAND_MAX)*0.2*next;
	next += tat;
	if ( next < 10 )
		next = 10;
	if ( next < p_interval )
		next = p_interval;
	if ( next > 2*pmd_prev_interval )
		next = 2*pmd_prev_interval;
	return next;
}

int
ping_mapping(MP_TASK_ENV * te,MP_TASK_T * tt,int force)
{
XL_SEXP * xl_GetElement();
XL_SEXP * meta;
L_CHAR * src, * dest, * map,* _map;
XL_SEXP * dp;
int _dp;
//unsigned int pitch1,pitch2;
unsigned int time,interval,_interval;
unsigned int pmd_time,pmd_interval;
//unsigned int pmd_interval1,pmd_interval2;
unsigned int mod;
unsigned int tat;
int dif;
//int ret;
L_CHAR * filename;
ORG_THREAD_MP_T * org;

	filename = tt->tq->filename;

	tat = 2*tqt_tat[tt->tq->type];

//ss_printf("TAT %i %i\n",tt->tq->type,tat);

	if ( check_mapping(filename,
			&time,
			&interval,
			&pmd_time,
			&pmd_interval) < 0 ) {
		if ( force == 0 || force == 2 ) {
			if ( pmd_time == 0 || pmd_time <= get_xltime() ) {
				force += 4;
				goto next;
			}
			if ( pmd_time > time ) {
				if ( time > get_xltime() ){
					dif = time - get_xltime();
					if ( tat >= dif )
						return 1;
					return dif - tat;
				}
			}
			else if ( pmd_time < time ) {
				if ( pmd_time > get_xltime() ) {
					dif = pmd_time - get_xltime();
					if ( tat >= dif )
						return 1;
					return dif - tat;
				}
			}
			if ( pmd_interval > interval ) {
				dif = interval - tat;
				if ( dif <= 0 )
					return 1;
				return dif;
			}
			else {
				dif = interval - tat;
				if ( dif <= 0 )
					return 1;
				return pmd_interval;
			}
		}
	}

next:

//ss_printf("PM 1 %ls (%i)\n",tt->tq->filename,get_xltime() - pmd_time);

	mod = get_file_modify(filename,".mta");
	meta = get_mapping_with_alias(te->ses,filename,&map);
	switch ( get_type(meta) ) {
	case XLT_NULL:
		log_printf(LOG_WARNING,LOG_LAYER_GB,0,
			"MP: cannot access metadata of the %s",
			n_string(std_cm,filename));
		if ( map )
			d_f_ree(map);
		return -1;
	case XLT_ERROR:
		log_print_sexp(LOG_DEBUG,LOG_LAYER_GB,0,
			"MP: cannot access the meta data",meta,0);
		if ( map )
			d_f_ree(map);
		return -1;
	}

	log_print_sexp(LOG_DEBUG,LOG_LAYER_GB,0,
			"MP access the meta data",meta,0);

	meta = get_el(meta,1);
	if ( meta == 0 ) {
		if ( map )
			d_f_ree(map);
		log_print_sexp(LOG_DEBUG,LOG_LAYER_GB,0,
			"MP access err 1",meta,0);
		return interval;
	}
	get_sd_url(&src,&dest,&_map,meta);
	if ( src == 0 || dest == 0 ) {
		if ( map )
			d_f_ree(map);
		log_print_sexp(LOG_DEBUG,LOG_LAYER_GB,0,
			"MP access err 2",meta,0);
		return interval;
	}
	dp = xl_GetElement(gblisp_top_env0,
		List(n_get_symbol("GetElement"),
			meta,
			n_get_symbol("dp"),
			-1),0,0);
	if ( dp == 0 ) {
		if ( map )
			d_f_ree(map);
		log_print_sexp(LOG_DEBUG,LOG_LAYER_GB,0,
			"MP access err 3",meta,0);
		return interval;
	}
	dp = get_el(dp,1);
	if ( get_type(dp) != XLT_INTEGER ) {
		if ( map )
			d_f_ree(map);
		log_print_sexp(LOG_DEBUG,LOG_LAYER_GB,0,
			"MP access err 4",meta,0);
		return interval;
	}

	_dp = dp->integer.data;
	src = get_full_url(filename,src);
	dest = get_full_url(filename,dest);
//	map = get_full_my_url(filename);

	if ( force == 3 ) {
		delete_target(te->ses,src,src,dest,map,_dp,".par");
		delete_target(te->ses,dest,src,dest,map,_dp,".chi");
		d_f_ree(src);
		d_f_ree(dest);
		d_f_ree(map);
		log_printf(LOG_DEBUG,LOG_LAYER_GB,0,"MP: delete %s",
			n_string(std_cm,filename));
		return -1;
	}


	if ( 2*tat > pmd_interval )
		pmd_interval = 2*tat;
	if ( 2*tat > interval )
		interval = 2*tat;

	new_org_thread(tt,
		force,
		src,
		dest,
		map,
		_dp,
		mod,
		interval,
		_interval,
		time,
		pmd_interval,
		pmd_time,
		tat);

	org = tt->arg;
/*
ss_printf("PMD TIME %i %i (%i)\n",
org->pmd_time,
get_xltime(),
get_xltime() - org->pmd_time);
*/

	if ( org->force == 1 || org->pmd_time == 0 || 
	     		org->pmd_time <= get_xltime() ) {
/*
		pmd_interval1 = lump_trigger(te->ses,org->src,org->map,
			org->pmd_interval);
		pmd_interval2 = lump_trigger(te->ses,org->dest,org->map,
			org->pmd_interval);
*/
		new_lump_trigger(tt,0,org->src,org->map);
		new_lump_trigger(tt,1,org->dest,org->map);
	}

	else {
		org->lump_fetch_count = 2;
		ping_mapping_last_2(te,tt);
	}

	d_f_ree(src);
	d_f_ree(dest);
	d_f_ree(map);

	return -2;
}


void
ping_mapping_last_3(MP_TASK_ENV * te,MP_TASK_T * org_tt)
{
ORG_THREAD_MP_T * org;

	org = org_tt->arg;
/*
ss_printf("ping_mapping_last_3 %ls %i %i %i %i\n",
org_tt->tq->filename,
(int)org->lump_last_1,
org->lump_fetch_count,
org->lump_pmd_interval_max,org->lump_count);
*/
	lock_task(tick_que_lock);
	if ( org->lump_last_1 ) {
		unlock_task(tick_que_lock,"ping_mapping_last_2");
		return;
	}
	if ( org->lump_fetch_count < 2 ) {
		unlock_task(tick_que_lock,"ping_mapping_last_2");
		return;
	}
	if ( org->lump_pmd_interval_max >
		org->lump_count ) {
		unlock_task(tick_que_lock,"ping_mapping_last_2");
		return;
	}
	org->lump_last_1 = 1;
	unlock_task(tick_que_lock,"ping_mapping_last_2");



	org->pmd_interval = get_next_pmd_interval(
		org->lump_pmd_interval[0],org->lump_pmd_interval[1],
		org->interval,
		org->pmd_interval,org->tat);
	org->pmd_time = get_xltime() + org->pmd_interval;
/*
ss_printf("calc %ls pmd_time = %i (%i %i)\n",
	org_tt->tq->filename,org->pmd_time,
	org->lump_pmd_interval[0],
	org->lump_pmd_interval[1]);
*/
	ping_mapping_last_2(te,org_tt);
}

void
ping_mapping_last_2(MP_TASK_ENV * te,MP_TASK_T * tt)
{
ORG_THREAD_MP_T * org;
int ret;

	org = tt->arg;

	lock_task(tick_que_lock);
	if ( org->lump_last ) {
		unlock_task(tick_que_lock,"ping_mapping_last_2");
		return;
	}
	if ( org->lump_fetch_count < 2 ) {
		unlock_task(tick_que_lock,"ping_mapping_last_2");
		return;
	}
	if ( org->lump_pmd_interval_max >
		org->lump_count ) {
		unlock_task(tick_que_lock,"ping_mapping_last_2");
		return;
	}
	org->lump_last = 1;
	unlock_task(tick_que_lock,"ping_mapping_last_2");

	if ( org->force >= 4 ) {

		set_mapping(tt->tq->filename,org->time,org->interval,
			org->pmd_time,org->pmd_interval);

		if ( org->force == 4 || org->force == 6 ) {

			if ( org->pmd_time > org->time ) {
				if ( org->time > get_xltime() ) {
					ret = org->time - get_xltime();
					insert_tick_que(ret,tt->tq->filename,
						TQT_MAP,TQL_NORMAL);
					free_mp_task_t(tt);
//ss_printf("PM L2-1 END %ls\n",tt->tq->filename);
					return;
				}
			}
			else {
				if ( org->pmd_time > get_xltime() ) {
					ret = org->pmd_time - get_xltime();
					insert_tick_que(ret,tt->tq->filename,
						TQT_MAP,TQL_NORMAL);
					free_mp_task_t(tt);
//ss_printf("PM L2-2 END %ls\n",tt->tq->filename);
					return;
				}
			}
/*
log_print_sexp(LOG_DEBUG,LOG_LAYER_GB,0,
"MP access err 6",meta,0);
*/
//ss_printf("PM L2-3 END %ls\n",tt->tq->filename);
			if ( org->interval > org->pmd_interval )
				ret = org->pmd_interval;
			else	ret = org->interval;
			insert_tick_que(ret,tt->tq->filename,
						TQT_MAP,TQL_NORMAL);
			free_mp_task_t(tt);
			return;
		}

	}

/*
	pitch1 = set_target(ses,src,src,dest,map,_dp,".par",
			interval,mod);
	pitch2 = set_target(ses,dest,src,dest,map,_dp,".chi",
			interval,mod);
*/

	new_set_target(tt,0,org->src,".par");
	new_set_target(tt,1,org->dest,".chi");

}

void
ping_mapping_last(MP_TASK_ENV * te,MP_TASK_T * t,int pitch)
{
int pitch1,pitch2;
SET_TARGET_MP_T * tt;
ORG_THREAD_MP_T * org;
MP_TASK_T * ot;
int ret;
int time;


	tt = (SET_TARGET_MP_T*)t->arg;
	ot = tt->org_thread;
	org = ot->arg;
//ss_printf("PM PITCH %ls %i\n",ot->tq->filename,pitch);

	lock_task(tick_que_lock);
	org->pitch[tt->thread_no] = pitch;
	org->count ++;
	free_mp_task_t(t);
	if ( org->count < 2 ) {
		unlock_task(tick_que_lock,"ping_mapping_last");
		return;
	}
	if ( org->ping_last ) {
		unlock_task(tick_que_lock,"ping_mapping_last");
		return;
	}
	org->ping_last = 1;
	unlock_task(tick_que_lock,"ping_mapping_last");
	
	pitch1 = org->pitch[0];
	pitch2 = org->pitch[1];

	org->interval = get_next_interval(pitch1,pitch2,org->interval,
					org->tat);
	if ( org->force == 2 )
		org->_interval = rand()%org->interval;
	else	org->_interval = org->interval;
	time = get_xltime() + org->_interval;
	set_mapping(ot->tq->filename,time,
			org->interval,org->pmd_time,
			org->pmd_interval);


	if ( org->pmd_interval > org->_interval )
		ret = org->_interval;
	else	ret = org->pmd_interval;
	if ( ret - org->tat <= 0 )
		ret = 1;
	else	ret = ret - org->tat;
/*
ss_printf("PM LAST %ls %i\n",ot->tq->filename,mp_task_que.total_cnt);
*/
	if ( ret >= 0 )
		insert_tick_que(org->interval,ot->tq->filename,
			TQT_MAP,TQL_NORMAL);
	free_mp_task_t(ot);
}


int
clear_crd_map(XL_SEXP ** retp,XL_SEXP * s)
{
XL_SEXP * ret;
XL_SEXP * t;
XL_SEXP * tm;
XL_SEXP * _tm;
extern XL_SEXP * xl_GetElement();
int flag;
XL_SEXP * sym;
	ret = 0;
	flag = 0;
	for ( ; get_type(s) == XLT_PAIR ; s = cdr(s) ) {
		t = car(s);
		tm = xl_GetElement(gblisp_top_env0,
			List(n_get_symbol("GetElement"),
				t,
				n_get_symbol("tm"),
				-1),0,0);
		if ( tm == 0 ) {
			sym = car(t);
			if ( get_type(sym) != XLT_SYMBOL ) {
				flag = 1;
				continue;
			}
			if ( l_strcmp(sym->symbol.data,
					l_string(std_cm,"cindex"))
					== 0 ) {
				ret = cons(t,ret);
				continue;
			}
			flag = 1;
			continue;
		}
		_tm = get_el(tm,1);
		if ( get_type(_tm) != XLT_INTEGER ) {
			flag = 1;
			continue;
		}
		if ( _tm->integer.data < get_xltime() ) {
			flag = 1;
			continue;
		}
		ret = cons(t,ret);
	}
	*retp = ret;
	return flag;
}

void
ping_crd_mapping(L_CHAR * filename)
{
XL_SEXP * p;

	gc_push(0,0,"trace_crd_mapping");
	p = get_mapping(filename,".par");
	if ( clear_crd_map(&p,p) ) {
		set_par_chi(filename,p,".par");
		insert_tick_que(0,filename,TQT_CRD,TQL_ACRP);
	}
	gc_pop(0,0);

	gc_push(0,0,"trace_crd_mapping");
	p = get_mapping(filename,".chi");
	if ( clear_crd_map(&p,p) ) {
		set_par_chi(filename,p,".chi");
		insert_tick_que(0,filename,TQT_CRD,TQL_ACRP);
	}
	gc_pop(0,0);
}

void
trace_mapping()
{
int ses;
L_CHAR * lpath;
DIR_LIST * d, * d1, * d2;
struct path_pair * wp;


	gc_push(0,0,"trace_mapping");
	d = NULL;
	for(wp=start;wp != NULL;wp=wp->next)
	{
		lpath = get_append_path(wp->docs_path,"/**/*.map");
		d1 = get_dir(n_string(std_cm,lpath),0,0,0,DLF_FILE);
		d_f_ree(lpath);
		d = marge_dir_list(d,d1);
		lpath = get_append_path(wp->docs_path,"/*.map");
		d2 = get_dir(n_string(std_cm,lpath),0,0,0,DLF_FILE);
		d_f_ree(lpath);
		d = marge_dir_list(d,d2);
	}


/* print_dir_list(d); */
	ses = open_session(SEST_OPTIMIZE);

	smap_start_time = get_xltime();

	for ( d1 = d ; d1 ; d1 = d1->next ) {
		lpath = get_url_path
				(l_string(std_cm,d1->name),0);
		if ( lpath == 0 )
			continue;

		gc_push(0,0,"trace mapping");
		insert_tick_que(0,lpath,TQT_SMAP,TQL_NORMAL);
		gc_pop(0,0);

		d_f_ree(lpath);
	}
	close_session(ses);
	free_dir_list(d2);
	gc_pop(0,0);

printf("END TRACE MAPPING\n");
}


void
trace_crd_mapping()
{
L_CHAR * lpath;
DIR_LIST * d, * d1, * d2;
struct path_pair * wp;
	gc_push(0,0,"trace_mapping");
	d = NULL;
	for(wp=start;wp != NULL;wp=wp->next)
	{
		lpath = get_append_path(wp->docs_path,"/**/*.crd");
		d1 = get_dir(n_string(std_cm,lpath),0,0,0,DLF_FILE);
		d_f_ree(lpath);
		d = marge_dir_list(d,d1);
		lpath = get_append_path(wp->docs_path,"/*.crd");
		d2 = get_dir(n_string(std_cm,lpath),0,0,0,DLF_FILE);
		d_f_ree(lpath);
		d = marge_dir_list(d,d2);
	}
	for ( d1 = d ; d1 ; d1 = d1->next ) {
		gc_push(0,0,"trace mapping");
		lpath = nl_copy_str(std_cm,d1->name);
		ping_crd_mapping(lpath);
		d_f_ree(lpath);
		gc_pop(0,0);
	}
	free_dir_list(d2);
	gc_pop(0,0);	
}


void
trace_crd_routing(int flag)
{
L_CHAR * lpath;
DIR_LIST * d, * d1, * d2;
struct path_pair * wp;
	gc_push(0,0,"trace_mapping");
	d = NULL;
	for(wp=start;wp != NULL;wp=wp->next)
	{
/* printf("-- CRD-pre %s\n",d1->name); */
		lpath = get_append_path(wp->docs_path,"/**/*.crd");
		d1 = get_dir(n_string(std_cm,lpath),0,0,0,DLF_FILE);
		d_f_ree(lpath);
		d = marge_dir_list(d,d1);
		lpath = get_append_path(wp->docs_path,"/*.crd");
		d2 = get_dir(n_string(std_cm,lpath),0,0,0,DLF_FILE);
		d_f_ree(lpath);
		d = marge_dir_list(d,d2);
	}
	for ( d1 = d ; d1 ; d1 = d1->next ) {
		lpath = get_url_path
				(l_string(std_cm,d1->name),0);
		if ( lpath == 0 )
			continue;

		gc_push(0,0,"trace crd mapping");
//printf("--C %s\n",d1->name);
		if ( flag )
			insert_tick_que(0,lpath,TQT_MCRD,TQL_ACRP);
		else	insert_tick_que(0,lpath,TQT_CRD,TQL_ACRP);
		gc_pop(0,0);

		d_f_ree(lpath);
	}
	free_dir_list(d2);
	gc_pop(0,0);	

printf("____________________ END TRACE CRD ROUTING\n");
}


