/**********************************************************************
 
	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	"xl.h"
#include	"memory_debug.h"
#include	"acrp.h"
#include	"gbacrp.h"
#include	"gbmp.h"

int max_hops;
XL_SEXP * get_op();

void
test_set_buf(char * str)
{
int i;
	printf("%s...",str);
	fflush(stdout);
	for ( i = 0 ; i < 1000 ; i ++ )
		l_string(std_cm,"a");
	printf("END\n");
}


int
get_tolerance(MAP_PATH_TABLE * t)
{
int i;
int ret;
	ret = 0;
	for ( ; t ; t = t->next )
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ )
			if ( t->ent[i].dir[0].hops < 0 )
				ret ++;
	return ret;
}

void
clear_flags_mpt_entry(ACRP_ENTRY * e)
{
int i;
	for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ )
		e->dir[i].flags = 0;
}



MAP_PATH_TABLE * 
normalizing_mpt(MAP_PATH_TABLE * t,int len,int dir)
{
MAP_PATH_TABLE * tt;
int old_len;
int i;
L_CHAR * pri;
int sum;
ACRP_DIR * d;

	if ( t == 0 )
		return 0;
	old_len = addr_length(t);
	if ( old_len >= len )
		return t;
	pri = 0;
	sum = 0;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		if ( t->ent[i].dir[0].hops < 0 )
			continue;
		if ( pri == 0 )
			pri = t->ent[i].pri;
		else if ( l_strcmp(pri,t->ent[i].pri) > 0 )
			pri = t->ent[i].pri;
		sum += t->ent[i].sum;
	}
	tt = new_mpt();
	tt->next = t;

	tt->ent[0].pri = ll_copy_str(pri);
	tt->ent[0].sum = sum;
	d = &tt->ent[0].dir[0];
	d->hops = dir;
	d->map = nl_copy_str(std_cm,"");
	d->crd = nl_copy_str(std_cm,"");
	tt->id = 0;
	t = tt;

	old_len ++;
	for ( ; old_len < len ; old_len ++ ) {
		tt = new_mpt();
		tt->next = t;
		tt->ent[0].pri = ll_copy_str(pri);
		tt->ent[0].sum = sum;
		d = &tt->ent[0].dir[0];
		d->hops = dir;
		d->map = nl_copy_str(std_cm,"");
		d->crd = nl_copy_str(std_cm,"");
		tt->id = 0;

		t = tt;
	}

	i = 0;
	for ( tt = t ; tt ; tt = tt->next )
		tt->level = i ++;
	return t;
}

MAP_PATH_TABLE * 
optimizing_mpt(MAP_PATH_TABLE * t)
{
MAP_PATH_TABLE * tt;
int i;
	if ( t->next == 0 )
		return t;
	for ( ; t->next ; ) {
		if ( t->id )
			break;
		for ( i = 1 ; i < ACRP_SUBID_NOS ; i ++ )
			if ( t->ent[i].dir[0].hops >= 0 )
				goto end;
		tt = t;
		t = t->next;
		tt->next = 0;
		free_mpt(tt);
	}
end:
	i = 0;
	for ( tt = t ; tt ; tt = tt->next )
		tt->level = i ++;
	return t;
}

void
clear_flags_mpt(MAP_PATH_TABLE * t)
{
int i;
	for ( ; t ; t = t->next ) {
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ )
			clear_flags_mpt_entry(&t->ent[i]);
	}
}


void
clean_flags_mpt_entry(MAP_PATH_INFO * mpi,ACRP_ENTRY * e)
{
int i,j;
ACRP_DIR * d;
	for ( i = 0 ; i < ACRP_DIR_NOS ; ) {
		d = &e->dir[i];
		if ( d->hops < 0 )
			break;
		if ( d->hops == 0 )
			goto next;
		if ( d->flags & ADF_CHECK )
			goto next;
		free_mpt_entry_dir(d);
		for ( j = i ; j < ACRP_DIR_NOS-1 ; j ++ )
			e->dir[j] = e->dir[j+1];
		d = &e->dir[ACRP_DIR_NOS-1];
		d->flags = 0;
		d->hops = -1;
		d->map = 0;
		d->crd = 0;
		dirty_mpi(mpi);
		continue;
	next:
		i ++;
	}
}

void
clean_flags_mpt(MAP_PATH_INFO * mpi)
{
int i;
MAP_PATH_TABLE * t;
	for ( t = mpi->mpt ; t ; t = t->next ) {
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ )
			clean_flags_mpt_entry(mpi,&t->ent[i]);
	}
}


int *
get_mpi_cid(MAP_PATH_INFO * m)
{
int * ret;
int len,i;
MAP_PATH_TABLE * t;
	for ( len = 0 , t = m->mpt ; t ; t = t->next, len ++ );
	ret = d_alloc(sizeof(int)*(len+1));
	ret[0] = len;
	for ( t = m->mpt , i = 1 ; t ; t = t->next , i ++ ) {
		ret[i] = t->id;
	}
	return ret;
}

int
marge_mpt_entry(
	ACRP_ENTRY * e1,
	ACRP_ENTRY * e2,
	L_CHAR * map,
	L_CHAR * crd)
{
int cmp;
int i,j;
int ret;
	if ( e2->dir[0].hops < 0 )
		return 0;
	if ( e1->dir[0].hops < 0 ) {
		e1->pri = ll_copy_str(e2->pri);
		e1->sum = e2->sum;
		e1->dir[0] = e2->dir[0];
		e1->dir[0].map = ll_copy_str(map);
		e1->dir[0].crd = ll_copy_str(crd);
		e1->dir[0].flags |= ADF_CHECK;
		return 1;
	}
	cmp = l_strcmp(e1->pri,e2->pri);
	if ( cmp == 0 ) {
		if ( e1->dir[0].hops == 0 )
			return 0;
		ret = 1;
		for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ ) {
			if ( e1->dir[i].hops < 0 )
				break;
			if ( l_strcmp(e1->dir[i].map,map)  )
				continue;
			if ( e1->dir[i].hops == e2->dir[0].hops )
				ret = 0;
			free_mpt_entry_dir(&e1->dir[i]);
			for ( j = i ; j < ACRP_DIR_NOS-1 ; j ++ )
				e1->dir[j] = e1->dir[j+1];
			e1->dir[j].hops = -1;
			e1->dir[j].map = 0;
			e1->dir[j].crd = 0;
			break;
		}
		for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ ) {
			if ( e1->dir[i].hops == -1 )
				break;
			if ( e1->dir[i].hops > e2->dir[0].hops )
				break;
		}
		if ( i == ACRP_DIR_NOS )
			return 0;
		free_mpt_entry_dir(&e1->dir[ACRP_DIR_NOS-1]);
		for ( j = ACRP_DIR_NOS-1 ; j > i ; j -- )
			e1->dir[j] = e1->dir[j-1];
		e1->dir[i] = e2->dir[0];
		e1->dir[i].map = ll_copy_str(map);
		e1->dir[i].crd = ll_copy_str(crd);
		e1->dir[i].flags |= ADF_CHECK;
		return ret;
	}
	else if ( cmp > 0 ) {
		if ( e1->dir[0].hops == 0 )
			ret = -1;
		else	ret = 1;
		for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ )
			free_mpt_entry_dir(&e1->dir[i]);
		d_f_ree(e1->pri);
		e1->pri = ll_copy_str(e2->pri);
		e1->sum = e2->sum;
		e1->dir[0] = e2->dir[0];
		e1->dir[0].map = ll_copy_str(map);
		e1->dir[0].crd = ll_copy_str(crd);
		e1->dir[0].flags |= ADF_CHECK;
		return ret;
	}
	else {
		return 0;
	}
}

int
setup_sum(MAP_PATH_TABLE * m)
{
int i;
int sum,dsum;
	if ( m == 0 )
		return 1;
	dsum = setup_sum(m->next);
	sum = 0;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		if ( m->ent[i].dir[0].hops < 0 )
			continue;
		if ( m->ent[i].dir[0].hops == 0 )
			m->ent[i].sum = dsum;
		sum += m->ent[i].sum;
		if ( sum < 0 )
			sum = 0x7fffffff;
	}
	return sum;
}

void
marge_mpt_entry_setup(MAP_PATH_TABLE * m,L_CHAR * map,L_CHAR * crd)
{
int i,j;
ACRP_ENTRY * e;
ACRP_DIR * d;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		e = &m->ent[i];
		d = &e->dir[0];
		if ( d->hops < 0 )
			continue;
		if ( d->map )
			d_f_ree(d->map);
		if ( d->crd )
			d_f_ree(d->crd);
		d->map = ll_copy_str(map);
		d->crd = ll_copy_str(crd);
		d->flags |= ADF_CHECK;
		for ( j = 1 ; j < ACRP_DIR_NOS ; j ++ )
			free_mpt_entry_dir(&e->dir[j]);
	}
}

int
marge_mpt(MAP_PATH_INFO * me,MAP_PATH_TABLE * m,L_CHAR * map,L_CHAR * crd)
{
int i,j;
MAP_PATH_TABLE * m1, * m2, * m3;
int fit;
int ret;
	ret = 0;
	if ( me->mpt == 0 ) {
		me->mpt = copy_mpt(m);
		marge_mpt_entry_setup(me->mpt,map,crd);
		me->mpt->next = 0;
		me->mpt->id = -1;
		return -1;
	}
	for ( m1 = me->mpt, m2 = m ; m1 && m2; m1 = m1->next , m2 = m2->next) {
		fit = 0;
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			if ( m1->ent[i].dir[0].hops == 0 &&
					m2->ent[i].dir[0].hops == 1 )
				fit = 1;
			switch ( marge_mpt_entry(
				&m1->ent[i],
				&m2->ent[i],
				map,
				crd) ) {
			case -1:
				free_mpt(m1->next);
				m1->next = 0;
				m1->id = -1;
				fit = 0;
				dirty_mpi(me);
				ret = -1;
				break;
			case 0:
				break;
			case 1:
				dirty_mpi(me);
				break;
			}
		}
		if ( fit == 0 )
			break;
	}
	if ( fit && m2 ) {
		for ( m1 = me->mpt ; m1->next ; m1 = m1->next );
		m3 = copy_mpt(m2);
		marge_mpt_entry_setup(m3,map,crd);
		m1->next = m3;
		m3->next = 0;
		ret = -1;
	}
	setup_sum(me->mpt);
	return ret;
}


L_CHAR *
regulation(MAP_PATH_TABLE * m1)
{
int i;
L_CHAR * pri;
L_CHAR * dpri;
	if ( m1 == 0 )
		return 0;
	dpri = regulation(m1->next);
	pri = 0;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		if ( m1->ent[i].dir[0].hops < 0 )
			continue;
		if ( dpri && m1->ent[i].dir[0].hops == 0 ) {
			if ( m1->ent[i].pri )
				d_f_ree(m1->ent[i].pri);
			m1->ent[i].pri = ll_copy_str(dpri);
		}
		if ( pri == 0 )
			pri = m1->ent[i].pri;
		else if ( l_strcmp(pri,m1->ent[i].pri) > 0 )
			pri = m1->ent[i].pri;
	}
	return pri;
}

void
count_up_hops(MAP_PATH_TABLE * m,L_CHAR * map,L_CHAR * crd,L_CHAR * me)
{
int i,j;
ACRP_ENTRY * e;
ACRP_DIR * d;

	for ( ; m ; m = m->next ) {
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			e = &m->ent[i];
			d = &e->dir[0];
			if ( d->hops < 0 )
				continue;
			if ( d->hops == 0 ) {
				if ( d->map )
					d_f_ree(d->map);
				d->map = ll_copy_str(map);
				if ( d->crd )
					d_f_ree(d->crd);
				d->crd = ll_copy_str(crd);
			}
			if ( l_strcmp(d->crd,me) == 0 ) {
				free_mpt_entry_dir(d);
				if ( e->pri )
					d_f_ree(e->pri);
				e->pri = 0;
				e->sum = 0;
			}
			else d->hops ++;
			for ( j = 1 ; j < ACRP_DIR_NOS ; j ++ ) {
				d = &e->dir[j];
				free_mpt_entry_dir(d);
			}
		}
	}
}

void
clean_crd_mpt_entry(MAP_PATH_INFO * m,
	ACRP_ENTRY * e,L_CHAR * map,L_CHAR * crd)
{
int i,j;
ACRP_DIR * d;
	for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ ) {
		d = &e->dir[i];
		if ( d->hops <= 0 )
			break;
		if ( l_strcmp(d->map,map) == 0 &&
				l_strcmp(d->crd,crd) == 0 ) {
			free_mpt_entry_dir(d);
			for ( j = i ; j < ACRP_DIR_NOS-1 ; j ++ )
				e->dir[j] = e->dir[j+1];
			d = &e->dir[ACRP_DIR_NOS-1];
			d->hops = -1;
			d->map = 0;
			d->crd = 0;
			m->regulation = get_xltime();
			dirty_mpi(m);
			break;
		}
	}
}

void
clean_crd_mpt(MAP_PATH_INFO * m,MAP_PATH_TABLE * t,L_CHAR * map,L_CHAR * crd)
{
int i;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ )
		clean_crd_mpt_entry(m,&t->ent[i],map,crd);
}

void
clean_crd(MAP_PATH_INFO * m,L_CHAR * map,L_CHAR * crd)
{
MAP_PATH_TABLE * t;
	for ( t = m->mpt ; t ; t = t->next )
		clean_crd_mpt(m,t,map,crd);
}

void
check_id(MAP_PATH_INFO * m)
{
MAP_PATH_TABLE * t;
int i;
	for ( t = m->mpt ; t ; t = t->next ) {
		t->id = -1;
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			if ( t->ent[i].dir[0].hops == 0 ) {
				t->id = i;
				break;
			}
		}
	}
}



AROUND_LIST *
make_around_list(int ses,XL_SEXP * par,XL_SEXP * chi)
{
L_CHAR * src,*dest, * map;
MAP_PATH_TABLE * mpt;
AROUND_LIST * a,* aa;
XL_SEXP * r;

	a = 0;
	for ( ; get_type(chi) == XLT_PAIR ; chi = cdr(chi) ) {
set_cpu_msg(301);
		r = car(chi);
		if ( get_type(r) != XLT_PAIR )
			continue;
set_cpu_msg(302);
		get_sd_url(&src,&dest,&map,r);

		if ( map == 0 || src == 0 || dest == 0 )
			continue;
set_cpu_msg(303);
		mpt = get_mpi_cp_mpt(ses,src,0);
set_cpu_msg(304);

		if ( mpt ) {
			regulation(mpt);
			mpt = optimizing_mpt(mpt);
			count_up_hops(mpt,map,src,dest);
		}
		aa = d_alloc(sizeof(*aa));
		aa->map = ll_copy_str(map);
		aa->crd = ll_copy_str(src);
		aa->me = ll_copy_str(dest);
		aa->mpt = mpt;
		aa->next = a;
		a = aa;
set_cpu_msg(305);
	}
set_cpu_msg(306);
	for ( ; get_type(par) == XLT_PAIR ; par = cdr(par) ) {
set_cpu_msg(307);
		r = car(par);
		if ( get_type(r) != XLT_PAIR )
			continue;
set_cpu_msg(308);
		get_sd_url(&src,&dest,&map,r);
		if ( map == 0 || src == 0 || dest == 0 )
			continue;
set_cpu_msg(309);
		mpt = get_mpi_cp_mpt(ses,dest,0);
set_cpu_msg(310);
		if ( mpt ) {
			regulation(mpt);
			mpt = optimizing_mpt(mpt);
			count_up_hops(mpt,map,dest,src);
		}
set_cpu_msg(311);
		aa = d_alloc(sizeof(*aa));
		aa->map = ll_copy_str(map);
		aa->crd = ll_copy_str(dest);
		aa->me = ll_copy_str(src);
		aa->mpt = mpt;
		aa->next = a;
		a = aa;
set_cpu_msg(312);
	}
set_cpu_msg(313);
	return a;
}


int
get_around(AROUND_LIST * al,MAP_PATH_INFO * m)
{
int ret;


	ret = 0;
	clear_flags_mpt(m->mpt);
	for ( ; al ; al = al->next ) {
		if ( al->mpt == 0 ) {
			clean_crd(m,al->map,al->crd);
			continue;
		}
		if ( marge_mpt(m,al->mpt,al->map,al->crd) < 0 )
			ret = -1;
		check_id(m);
	}
	clean_flags_mpt(m);
	return ret;
}


int
setup_map_acrp_level_rand(AROUND_LIST * al,MAP_PATH_INFO * m,
	FINISH_LIST * fl,int addr_len,int force)
{
int i;
MAP_PATH_TABLE * m1, * m2;
ACRP_ENTRY * e;
int id;
int cnt;
int sum;
int r;
int lev;
int target_sum;
int all_zero;
#define NULL_SUM 0x7ffffffe
L_CHAR * pri;
int pri_f;
L_CHAR * target_pri;

	get_around(al,m);
	if ( m->mpt == 0 ) {
		m->mpt = new_mpt();
		m1 = m->mpt;
		m1->level = 0;

		if ( addr_len == 1 )
			id = (rand()%(ACRP_SUBID_NOS-1))+1;
		else	id = rand()%ACRP_SUBID_NOS;
		e = &m1->ent[id];
		goto set;
	}
	all_zero = 1;
	for ( m1 = m->mpt ; m1->next ; m1 = m1->next )
		if ( m1->id > 0 )
			all_zero = 0;
	if ( m1->id >= 0 ) {
		lev = m1->level;
		m1->next = new_mpt();
		m1 = m1->next;
		m1->level = lev+1;

		if ( (lev+1 == addr_len-1) && all_zero )
			id = (rand()%(ACRP_SUBID_NOS-1))+1;
		else	id = rand()%ACRP_SUBID_NOS;
		e = &m1->ent[id];
		goto set;
	}
	if ( m1->level == addr_len-1 ) {
		sum = NULL_SUM;
		cnt = 0;
		for ( i = all_zero ; i < ACRP_SUBID_NOS ; i ++ ) {
			if ( m1->ent[i].dir[0].hops < 0 )
				cnt ++;
		}
		if ( cnt == 0 )
			return -1;
	}
	else {
		all_zero = 0;
		for ( m2 = m->mpt ; m2 != m1 && fl ;
				m2 = m2->next , fl = fl->next );
		sum = -1;
		cnt = 0;
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			if ( fl && fl->list[i] )
				continue;
			if ( m1->ent[i].dir[0].hops == 1 )
				target_sum = m1->ent[i].sum;
			else if ( m1->ent[i].dir[0].hops < 0 )
				target_sum = NULL_SUM;
			else if ( force && l_strcmp(m1->ent[i].pri,
					m->my_pri) > 0 )
				target_sum = m1->ent[i].sum;
			else	target_sum = 0x7fffffff;
			if ( sum < 0 ) {
				sum = target_sum;
				cnt = 1;
			}
			else if ( target_sum < sum ) {
				cnt  = 1;
				sum = target_sum;
			}
			else if ( target_sum == sum ) {
				cnt ++;
			}
		}
		if ( sum == -1 || sum == 0x7fffffff )
			return -1;
	}
ok:
	if ( cnt == 1 )
		r = 0;
	else	r = rand()%cnt;
	for ( i = all_zero ; i < ACRP_SUBID_NOS ; i ++ ) {
		if ( sum == NULL_SUM ) {
			if ( m1->ent[i].dir[0].hops < 0 ) {
				if ( r == 0 )
					break;
				r --;
			}
		}
		else {
			if ( m1->ent[i].dir[0].hops > 1 ) {
				if ( force == 0 )
					continue;
				if ( l_strcmp(m1->ent[i].pri,
						m->my_pri) < 0 )
					continue;
			}
			if ( m1->ent[i].sum == sum ) {
				if ( r == 0 )
					break;
				r --;
			}
		}
	}
	if ( i == ACRP_SUBID_NOS )
		er_panic("rand???\n");
	e = &m1->ent[i];
	id = i;
set:

	if ( e->dir[0].hops >= 0 ) {
		if ( l_strcmp(e->pri,m->my_pri) > 0 ) {
			d_f_ree(e->pri);
			e->pri = ll_copy_str(m->my_pri);
		}
	}
	else {
		e->pri = ll_copy_str(m->my_pri);
		e->sum = 1;
	}
	for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ )
		free_mpt_entry_dir(&e->dir[i]);
	e->dir[0].hops = 0;
	e->dir[0].map = nl_copy_str(std_cm,"");
	e->dir[0].crd = nl_copy_str(std_cm,"");
	m1->id = id;
	return id;
}

void
free_finish_list(FINISH_LIST * fl)
{
FINISH_LIST * fl1;
	for ( ; fl ; ) {
		fl1 = fl->next;
		d_f_ree(fl);
		fl = fl1;
	}
}

void
setup_finish_list(FINISH_LIST ** flp,MAP_PATH_INFO * m)
{
MAP_PATH_TABLE * t;
FINISH_LIST * fl1;
int i;
	for ( t = m->mpt ; t ; t = t->next ) {
		if ( t->next == 0 )
			break;
		if ( *flp == 0 ) {
			*flp = fl1 = d_alloc(sizeof(*fl1));
			fl1->next = 0;
			for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ )
				fl1->list[i] = 0;
		}
		if ( t->next->next == 0 ) {
			fl1 = *flp;
			fl1->list[t->id] = 1;
			free_finish_list(fl1->next);
			fl1->next = 0;
			break;
		}
		flp = &(*flp)->next;
	}
}

void
_print_finish_list(FINISH_LIST * fl)
{
int i;
	printf("(");
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		if ( fl->list[i] == 0 )
			continue;
		printf("%i ",i);
	}
	printf(")\n");
}

void
print_finish_list(FINISH_LIST * fl)
{
	printf("xx ");
	for ( ; fl ; fl = fl->next )
		_print_finish_list(fl);
	printf("\n");
}

int	
setup_my_acrp_rand(AROUND_LIST * al,MAP_PATH_INFO * m,int addr_len)
{
int er;
FINISH_LIST * fl;
int ret;
int len;
int force;

printf("*rand*\n");
	force = 0;
retry:
	fl = 0;
	for ( ; ; ) {
check_mpt2("setup bef",m->mpt);
		len = addr_length(m->mpt);
		if ( len >= addr_len )
			break;
		er = setup_map_acrp_level_rand(al,m,fl,addr_len,force);
printf("er = %i\n",er);
check_mpt2("setup",m->mpt);
		if ( er == -1 ) {
			if ( m->mpt == 0 ) {
				ret = -1;
				goto end;
			}
			if ( m->mpt->next == 0 ) {
				free_mpt(m->mpt);
				dirty_mpi(m);
				m->mpt = 0;
				ret = -1;
				goto end;
			}
			setup_finish_list(&fl,m);
			free_mpt(m->mpt);
			dirty_mpi(m);
			m->mpt = 0;
		}
	}
	setup_sum(m->mpt);
	ret = 0;
end:
	free_finish_list(fl);
	if ( force == 0 && ret < 0 ) {
		force = 1;
		goto retry;
	}
	return ret;
}

int
setup_map_acrp_level_prev(AROUND_LIST * al,MAP_PATH_INFO * m,
	int * prev,int addr_len)
{
int i;
MAP_PATH_TABLE * m1;
ACRP_ENTRY * e;
int id;
int cnt;
int sum;
int r;
int lev;

	get_around(al,m);
	if ( m->mpt == 0 ) {
		m->mpt = new_mpt();
		m1 = m->mpt;
		m1->level = 0;
		e = &m1->ent[prev[1]];
		id = prev[1];
		goto set;
	}
	for ( m1 = m->mpt ; m1->next ; m1 = m1->next );
	if ( m1->id >= 0 ) {
		lev = m1->level;
		m1->next = new_mpt();
		m1 = m1->next;
		m1->level = lev+1;
		e = &m1->ent[prev[m1->level+1]];
		id = prev[m1->level+1];
		goto set;
	}
	id = prev[m1->level+1];
	e = &m1->ent[id];
	if ( e->dir[0].hops < 0 )
		goto set;
	if ( m1->level != addr_len-1 && e->dir[0].hops == 1 )
		goto set;
	if ( l_strcmp(e->pri,m->my_pri) < 0 )
		return -1;
set:
	if ( e->dir[0].hops >= 0 ) {
		if ( l_strcmp(e->pri,m->my_pri) > 0 ) {
			d_f_ree(e->pri);
			e->pri = ll_copy_str(m->my_pri);
		}
	}
	else {
		e->pri = ll_copy_str(m->my_pri);
		e->sum = 1;
	}
	for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ )
		free_mpt_entry_dir(&e->dir[i]);
	e->dir[0].hops = 0;
	e->dir[0].map = nl_copy_str(std_cm,"");
	e->dir[0].crd = nl_copy_str(std_cm,"");
	m1->id = id;
	return id;
}

int	
setup_my_acrp_prev(AROUND_LIST * al,MAP_PATH_INFO * m,
	int * prev,int addr_len)
{
int er;
int len;

printf("*prev* %i\n",addr_len);
	for ( ; ; ) {
		len = addr_length(m->mpt);
printf("len = %i\n",len);
		if ( len >= addr_len )
			break;
		er = setup_map_acrp_level_prev(al,m,prev,addr_len);
printf("er = %i\n",er);
		if ( er == -1 ) {
			free_mpt(m->mpt);
			m->mpt = 0;
			dirty_mpi(m);
			return -1;
		}
	}
	setup_sum(m->mpt);
	return 0;
}



int
search_sdm(ACRP_DIR * d,AROUND_LIST * al)
{
	for ( ; al ; al = al->next ) {
		if ( l_strcmp(al->crd,d->crd) )
			continue;
		if ( l_strcmp(al->map,d->map) )
			continue;
		return 0;
	}
	return -1;
}


void
clean_mpt_entry(MAP_PATH_INFO * mpi,ACRP_ENTRY * e,AROUND_LIST * al)
{
int i,j;
ACRP_DIR * d;
	for ( i = 0 ; i < ACRP_DIR_NOS ; ) {
		d = &e->dir[i];
		if ( d->hops < 0 )
			return;
		if ( search_sdm(d,al) == 0 ) {
			i ++;
			continue;
		}
		free_mpt_entry_dir(d);
		for ( j = i ; j < ACRP_DIR_NOS-1 ; j ++ )
			e->dir[j] = e->dir[j+1];
		d = &e->dir[ACRP_DIR_NOS-1];
		d->map = 0;
		d->crd = 0;
		d->hops = -1;
		mpi->regulation = get_xltime();
		dirty_mpi(mpi);
	}
}

void
clean_mpt(MAP_PATH_INFO * mpi,AROUND_LIST * al)
{
int i;
ACRP_ENTRY * e;
MAP_PATH_TABLE * m;
	for ( m = mpi->mpt ; m ; m = m->next ) {
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			e = &m->ent[i];
			if ( e->dir[0].hops <= 0 )
				continue;
			clean_mpt_entry(mpi,e,al);
		}
	}
}


int
max_addr_length(AROUND_LIST * al,MAP_PATH_INFO * m,int length)
{
AROUND_LIST * al2;
int ret,lev;
	if ( length == 0 ) {
		ret = 0;
		for ( al2 = al ; al2 ; al2 = al2->next ) {
			lev = addr_length(al2->mpt);
			if ( lev > ret )
				ret = lev;
		}
		if ( m ) {
			lev = addr_length(m->mpt);
			if ( lev > ret )
				ret = lev;
		}
	}
	else	ret = length;
	for ( al2 = al ; al2 ; al2 = al2->next ) {
		lev = addr_length(al2->mpt);
		if ( lev == ret )
			continue;
		al2->mpt = normalizing_mpt(al2->mpt,ret,1);
	}
	if ( m ) {
		lev = addr_length(m->mpt);
		if ( lev != ret ) {
			m->mpt = normalizing_mpt(m->mpt,ret,0);
			dirty_mpi(m);
		}
	}
	if ( ret == 0 )
		return 1;
	return ret;
}

int
_sum_check(MAP_PATH_TABLE * me,MAP_PATH_TABLE * t,L_CHAR * crd)
{
int i;
int ret;
	ret = 0;
	for ( ; me && t ; me = me->next , t = t->next ) {

		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {

			if ( me->ent[i].dir[0].hops <= 0 )
				continue;
			if ( t->ent[i].dir[0].hops <= 0 )
				continue;
			if ( me->ent[i].sum >= t->ent[i].sum )
				continue;
			me->ent[i].sum = t->ent[i].sum;
			ret = -1;
		}
		if ( me->id != t->id )
			break;
	}
	return ret;
}

int
sum_check(MAP_PATH_TABLE * m,AROUND_LIST * al)
{
int ret;
	ret = 0;
	for ( ; al ; al = al->next )
		if ( _sum_check(m,al->mpt,al->crd) < 0 )
			ret = -1;
	return ret;
}


void
check_limit(MAP_PATH_INFO * mm)
{
int max,_max;
int i,j;
MAP_PATH_TABLE * m;
	m = mm->mpt;
	if ( m == 0 )
		return;
	max = 0;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		if ( m->ent[i].dir[0].hops < 0 )
			continue;
		max += m->ent[i].sum;
	}
	for ( ; m ; m = m->next ) {
		_max = 10;
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			if ( m->ent[i].dir[0].hops == 0 )
				_max = m->ent[i].sum;
			if ( m->ent[i].dir[0].hops < 2*max )
				continue;
			for ( j = 0 ; j < ACRP_DIR_NOS ; j ++ )
				free_mpt_entry_dir(&m->ent[i].dir[j]);
			dirty_mpi(mm);
		}
		max = _max;
	}
}

void
check_loop_mpt(MAP_PATH_INFO * m)
{
int i,j;
ACRP_ENTRY * e;
MAP_PATH_TABLE * t;
	t = m->mpt;
	for ( ; t ; t = t->next ) {
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			e = &t->ent[i];
			if ( e->dir[0].hops < 0 )
				continue;
			if ( check_loop_max(e->dir[0].hops) < 0 ) {
printf("cut mpt\n");
				for ( j = 0; j < ACRP_DIR_NOS ; j ++ )
					free_mpt_entry_dir(&e->dir[j]);
				d_f_ree(e->pri);
				e->pri = 0;
				e->sum = 0;
				dirty_mpi(m);
			}
		}
	}
}

void
set_max_hops(MAP_PATH_INFO * m)
{
MAP_PATH_TABLE * t;
int i;
int max;
	if ( m->mpt == 0 )
		return;
	t = m->mpt;
	max = 0;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ )
		if ( t->ent[i].dir[0].hops >= 0 )
			max += t->ent[i].sum;
	max_hops = max + 10;
}

void
check_my_acrp(int ses,L_CHAR * filename)
{
MAP_PATH_INFO * m;
XL_SEXP * chi,*par;
int flag;
int * prev_addr;
AROUND_LIST * al;
XL_SEXP * c;
int addr_len;
int sum_dirty;
int reg;

/*
printf("start (%i) %s\n",get_tid(),n_string(std_cm,filename));
*/

set_cpu_msg(30);

	sum_dirty = 0;

	gc_push(0,0,"make_around_list");
	chi = filtering_crd(c=get_crd_chi(filename));
	par = filtering_crd(get_crd_par(filename));
	al = make_around_list(ses,par,chi);


	gc_pop(0,0);

set_cpu_msg(31);
	m = get_mpi(ses,filename,MPI_WRITE);

set_cpu_msg(32);
	if ( m->sts == MPIS_ERROR ) {
set_cpu_msg(33);
		addr_len = max_addr_length(al,0,0);

		if ( check_exist(filename) < 0 ) {
			flush_mpi(m);
			free_around_list(al);
			return;
		}
		prev_addr = 0;
	set_addr:

set_cpu_msg(34);
		free_mpt(m->mpt);
		m->sts = MPIS_LOCAL;
		m->mpt = 0;
		if ( prev_addr )
			if ( setup_my_acrp_prev(al,m,prev_addr,
					addr_len) == 0 )
				goto ok;
	retry:
		if ( setup_my_acrp_rand(al,m,addr_len) == 0 )
			goto ok;
		addr_len ++;
		max_addr_length(al,m,addr_len);
		goto retry;
	ok:
set_cpu_msg(35);
		check_loop_mpt(m);
		dirty_mpi(m);
	}
	else {
set_cpu_msg(36);

		set_mpi_around_list(m,al,1);

		if ( m->cid_flag )
{ss_printf("REWRITE %ls\n",filename);
			m->lock = -2;
			m->cid_flag = 0;
}

		addr_len = max_addr_length(al,m,0);

		prev_addr = get_mpi_cid(m);
		if ( m->regulation && 
				(m->regulation + REGULATION_TIMEOUT) 
				<= get_xltime() ) {
			regulation(m->mpt);
			dirty_mpi(m);
			m->regulation = 0;
		}
set_cpu_msg(37);

		clean_mpt(m,al);
	 	if ( get_around(al,m) < 0 )
			goto set_addr;

set_cpu_msg(38);
		if ( sum_check(m->mpt,al) < 0 )
			sum_dirty = 1;
		check_loop_mpt(m);
		check_limit(m);
	}
set_cpu_msg(39);

	set_max_hops(m);
	if ( prev_addr )
		d_f_ree(prev_addr);
	if ( m->lock == -2 )
		flag = 1;
	else	flag = 0; 
	if ( sum_dirty )
		dirty_mpi(m);
set_cpu_msg(40);
	if ( m->regulation == 0 )
		m->mpt = optimizing_mpt(m->mpt);

	reg = m->regulation;

	flush_mpi(m);
set_cpu_msg(41);
	if ( flag ) {
		trigger_around(ses,filename,al);
	}
set_cpu_msg(42);
	if ( reg ) {
		reg = reg + REGULATION_TIMEOUT
			- get_xltime();
		if ( reg < 0 )
			reg = 0;
		insert_tick_que(
			reg,
			filename,TQT_CRD,TQL_ACRP);
	}
/*
printf("end (%i)\n",get_tid());
*/
set_cpu_msg(43);
	free_around_list(al);
set_cpu_msg(44);
}

