/**********************************************************************
 
	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	"memory_debug.h"
#include	"xl.h"
#include	"xlerror.h"
#include	"utils.h"
#include	"resource.h"
#include	"queue.h"
#include	"pri_level.h"

typedef struct cindex_t {
	Q_HEADER	h;
	XL_SEXP *	s;
	D_SEXP *	d;
} CINDEX_T;


typedef struct cindex_proc_que {
	struct cindex_proc_que *	next;
	L_CHAR * 			crd;
} CINDEX_PROC_QUE;

extern SEM res_lock;

void gc_cque();
void gc_get_cque();
void cindex_task();
void gc_d_sexp();
void gc_gb_sexp();

SYS_QUEUE cindex_que;
XL_SEXP * gb_MPcindex();
CINDEX_PROC_QUE * pq_head;

void
init_gb_MPcindex(XLISP_ENV * env)
{
	memset(&cindex_que,0,sizeof(SYS_QUEUE));
	cindex_que.flags = QF_FIFO|QF_HIGH;
	cindex_que.gc_func = gc_cque;
	cindex_que.gc_get = gc_get_cque;
	cindex_que.key_func = 0;
	cindex_que.pri = PRI_XL_RELAY;
	setup_queue(&cindex_que);


	set_env(env,l_string(std_cm,"MPcindex"),
		get_func_prim(gb_MPcindex,FO_APPLICATIVE,0,2,2));
	create_task(cindex_task,0,PRI_XL_RELAY);
}

void
gc_cque(CINDEX_T * n)
{
	gc_gb_sexp(n->s);
	gc_d_sexp(n->d);
}

void
gc_get_cque(CINDEX_T * n)
{
	lock_mem();
	gc_set_nl(n->s,gc_gb_sexp);
	gc_set_nl(n->d,gc_d_sexp);
	unlock_mem();
}



void
insert_cindex_pq(L_CHAR * crd)
{
CINDEX_PROC_QUE * q;
	for ( q = pq_head ; q ; q = q->next )
		if ( l_strcmp(q->crd,crd) == 0 ) {
			ss_printf("duplicate exit\n");
			exit(1);
		}
	q = d_alloc(sizeof(*q),346);
	q->crd = ll_copy_str(crd,346);
	q->next = pq_head;
	pq_head = q;
}




void
setup_minrect(MAP * m)
{
GB_RECT r;
GB_POINT p;
GB_RECT *mr;
REAL1 reso;
	if ( m->map_file->h.minrect.tl.x <=
		m->map_file->h.minrect.br.x )
		return;
	if ( m->src == 0 )
		return;
	mr = &m->src->h.minrect;
	p = mr->tl;
	reso = 1;
	map_conv_forward(m->map_file,&p,&reso,1);
	if ( reso < 0 )
		return;
	r.tl = r.br = p;

	p = mr->br;
	reso = 1;
	map_conv_forward(m->map_file,&p,&reso,1);
	if ( reso < 0 )
		return;
	insert_rect(&r,p);

	p.x = mr->tl.x;
	p.y = mr->br.y;
	reso = 1;
	map_conv_forward(m->map_file,&p,&reso,1);
	if ( reso < 0 )
		return;
	insert_rect(&r,p);

	p.x = mr->br.x;
	p.y = mr->tl.y;
	reso = 1;
	map_conv_forward(m->map_file,&p,&reso,1);
	if ( reso < 0 )
		return;
	insert_rect(&r,p);


	m->map_file->h.minrect = r;
}


LOAD_RESOURCE_WORK *
load_children_map(RESOURCE * r)
{
MAP * m;
LOAD_RESOURCE_WORK * ret;
int len;


	ret = 0;
	for ( m = R_NEXT(MAP*,&r->c.map_children);
			m != (MAP*)&r->c.map_children ; 
			m = R_NEXT(MAP*,&m->h) ) {

		len = l_strlen(m->src_url.resource);
		if ( l_strcmp(&m->src_url.resource[len-4],
				l_string(std_cm,".crd")) == 0 )
			continue;

		if ( m->mod_time && m->cindex_time &&
				m->cindex_time >= m->mod_time )
			continue;

		if ( m->src == 0 ) {
			ret = new_lrw(ret);
			copy_url(&ret->url,&m->src_url);
		}


		if ( m->map_file == 0 ) {
			ret = new_lrw(ret);
			copy_url(&ret->url,&m->map_url);
		}


	}
	return ret;
}


void
browse_children_map(int ses,RESOURCE * r,
	LOAD_RESOURCE_WORK * w)
{
MAP * m;
int ret,this_coord;
MAP_HISTORY * mh;
GB_RECT g;
int len;
LOAD_RESOURCE_WORK * wp;

	ret = 0;
	wp = w;

	for ( m = R_NEXT(MAP*,&r->c.map_children);
			m != (MAP*)&r->c.map_children;
			m = R_NEXT(MAP*,&m->h) ) {

		len = l_strlen(m->src_url.resource);
		if ( l_strcmp(&m->src_url.resource[len-4],
				l_string(std_cm,".crd")) == 0 )
			continue;

		lock_task(res_lock);
		if ( m->flags & MF_BROWSE ) {
			unlock_task(res_lock,"write_lock");
			continue;
		}
		m->flags |= MF_BROWSE;
		unlock_task(res_lock,"write_lock");

		if ( m->map_file == 0 ) {
			m->map_file
				= get_lrw(w,&m->map_url);
			if ( m->map_file == 0 )
				goto err;
			if ( url_cmp(&m->map_file->map.dest,
					&r->h.entry) ) {
				m->map_file = 0;
				goto err;
			}
			if ( url_cmp(&m->map_file->map.src,
					&m->src_url) ) {
				m->map_file = 0;
				goto err;
			}
			ret = 1;
			this_coord = 1;
		}
		if ( m->src == 0 ) {
			m->src = get_lrw(w,&m->src_url);

			if ( m->src == 0 )
				goto err;
			ret = 1;
			this_coord = 1;
			if ( m->src->h.notes )
				call_gv_event(m->src->h.no,
					l_string(std_cm,"set-note"));
		}

		setup_minrect(m);

	err:
		lock_task(res_lock);
		m->flags &= ~MF_BROWSE;
		unlock_task(res_lock,"write_lock");


	}
}


void
send_record(L_CHAR * target,MAP * mp,int * cindex_time)
{
XL_SEXP * gt;
L_CHAR * _target;
XL_SEXP * rec;
URL u;
L_CHAR * f;
int len;

	if ( mp->src && mp->src->h.type == RT_COORDINATE )
		return;
	if ( mp->map_file == 0 )
		return;
	if ( mp->mod_time && mp->cindex_time &&
			mp->cindex_time >= mp->mod_time )
		return;
/*
ss_printf("SR 3 %i %i\n",mp->mod_time,mp->cindex_time);
*/
	mp->cindex_mr = mp->map_file->h.minrect;

	gt = n_get_symbol("Set");
	set_attribute(gt,
		l_string(std_cm,"option"),
		l_string(std_cm,"part"));
	_target = ll_copy_str(target,1394);
	len = l_strlen(_target);
	_target = d_re_alloc(_target,(len+10)*sizeof(L_CHAR));
	l_strcpy(&_target[len],l_string(std_cm,".chi"));
	get_url2(&u,_target,1235);
	d_f_ree(_target);
	if ( mp->mod_time_org == 0 )
		mp->mod_time_org = 1;
	rec = List(gt,
		get_string(f = get_url_filepath(&u)),
		List(n_get_symbol("record"),
			List(n_get_symbol("src"),
				get_string(
				get_url_str2(&mp->src_url)),
				-1),
			List(n_get_symbol("dest"),
				get_string(
				get_url_str2(&mp->dest_url)),
				-1),
			List(n_get_symbol("map"),
				get_string(
				get_url_str2(&mp->map_url)),
				-1),
			List(n_get_symbol("mod"),
				get_integer(mp->mod_time_org,
					l_string(std_cm,"sec")),
				-1),
			List(n_get_symbol("mr"),
				get_floating(
					mp->cindex_mr.tl.x,
					0),
				get_floating(
					mp->cindex_mr.tl.y,
					0),
				get_floating(
					mp->cindex_mr.br.x,
					0),
				get_floating(
					mp->cindex_mr.br.y,
					0),
				-1),
			-1),
		-1);
	xl_Set_part(0,rec,0,gt->symbol.field,*cindex_time,1);
	*cindex_time = 0;
}


XL_SEXP *
cindex_proc(int ses,CINDEX_T * ct)
{
XL_SEXP * crd;
RESOURCE * r;
URL u;
int len;
L_CHAR * fcrd;
int cnt;
LOAD_RESOURCE_WORK * w;
char * hn;
MAP * m;
L_CHAR * f;
int cf;

	cf = get_xltime();
	crd = get_el(ct->s,1);
	if ( get_type(crd) != XLT_STRING )
		goto type_missmatch;

	fcrd = crd->string.data;
	len = l_strlen(fcrd);
	if ( l_strcmp(&fcrd[len-4],l_string(std_cm,".crd")) )
		goto type_missmatch;
	get_url2(&u,fcrd,346);
	if ( u.proto )
		d_f_ree(u.proto);
	u.proto = nl_copy_str(std_cm,"xlp");
	if ( u.server )
		d_f_ree(u.server);

	hn = d_alloc(1000,55);
	get_localhostname(hn);
	u.server = nl_copy_str(std_cm,hn);
	d_f_ree(hn);

	u.port = get_my_port();

	r = load_resource(ses,&u,Q_PRI_CRD);
	if ( r == 0 )
		goto no_obj;
	lr_extend(r,0);
	cnt = 0;
	for ( ; cnt < 120 && (r->h.flags & RF_LOAD_EXTEND) == 0 ; cnt ++ )
		sleep_sec(1);
	if ( (r->h.flags & RF_LOAD_EXTEND) == 0 )
		goto no_obj2;
	w = load_children_map(r);
	load_resource_list(w,Q_PRI_OBJ,1);
	browse_children_map(ses,r,w);
	free_lrw_req_next(w);
	f = ll_copy_str(get_url_str2(&u),346);
	for ( m = R_NEXT(MAP*,&r->c.map_children);
			m != (MAP*)&r->c.map_children;
			m = R_NEXT(MAP*,&m->h) ) {
		gc_push(0,0,"send_record");
		send_record(f,m,&cf);
		gc_pop(0,0);
	}
	d_f_ree(f);

end:

	insert_cindex_pq(fcrd);
	return 0;

type_missmatch:
	return get_error(
		ct->s->h.file,
		ct->s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"MPcindex"),
		n_get_string("type missmatch"));

no_obj:
	return get_error(
		ct->s->h.file,
		ct->s->h.line,
		XLE_PROTO_INV_OBJECT,
		l_string(std_cm,"MPcindex"),
		n_get_string("invalid crd resource"));

no_obj2:
	return get_error(
		ct->s->h.file,
		ct->s->h.line,
		XLE_PROTO_INV_OBJECT,
		l_string(std_cm,"MPcindex"),
		n_get_string("invalid crd resource(2)"));


}


void
cindex_task()
{
XL_INTERPRETER * xli;
CINDEX_T * ct;
XL_SEXP * ret;
int ses;

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	ses = open_session(SEST_OPTIMIZE);

	for ( ; ; ) {

		gc_push(0,0,"routing_task");

		ct = delete_queue(&cindex_que,0,0,1);
		ret = cindex_proc(ses,ct);
		set_d_sexp(ct->d,ret);

		d_f_ree(ct);

		gc_pop(0,0);
	}
}



XL_SEXP *
gb_MPcindex(XLISP_ENV * env,XL_SEXP * s,
	XLISP_ENV * a,
	XL_SYM_FIELD * sf)
{
CINDEX_T * ct;
XL_SEXP * ret;

	ct = new_queue_node(sizeof(*ct),1346);
	ct->h.key = 0;
	ct->s = s;
	ret = new_d_sexp(&ct->d);
	insert_queue(&cindex_que,ct,1);
	return ret;
}


