/**********************************************************************
 
	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	"gbview.h"
#include	"task.h"
#include	"xl.h"
#include	"xlerror.h"
#include	"lock_level.h"
#include	"pri_level.h"
#include	"win_flame.h"
#include	"queue.h"

#define THPUT_TH		16000
#define DM_HANGING_TIME		10
#define DM_LIST_SIZE		35
#define MIN_SIZE_OF_PACKET	8000
#define DM_INTERVAL		2


typedef struct dm_t {
	Q_HEADER		h;
	XL_SEXP *		data;
	RESOURCE *		r;
	WF_ID			wfid;
	int			max_size;
	int			lev_max;
	DRAW_MATRIX *		dm;
	DRAW_MATRIX *		dm_list[DM_LIST_SIZE];
	int			handle_time;
} DM_T;

typedef struct dm_time_list {
	struct dm_time_list *	next;
	L_CHAR *		key;
	XL_SEXP *		aboat_target;
	URL			target_url;
	int			time;
	int			start_time;
} DM_TIME_LIST;

extern RESOURCE ** res_entry_hash_table;
extern int default_dgb_pixel;
extern int spiral_count;

void dm_resource_scan();
void gc_gb_sexp();

SEM dm_lock;
int dm_nos;
RING_TYPE dm_h;



SYS_QUEUE	pipe0,pipe1,pipe2;

DM_TIME_LIST *	tlist;

int dg_write_lock;
int scan_flag;


GB_POINT dg1 = { -109897.1 , -22411.9};
GB_POINT dg2 = { -109741.0 , -22406.5};
GB_RECT dgr1,dgr2;

void
make_dg()
{
	dgr1.tl.x = dg1.x - 5;
	dgr1.tl.y = dg1.y - 5;
	dgr1.br.x = dg1.x + 5;
	dgr1.br.y = dg1.y + 5;

	dgr2.tl.x = dg2.x - 5;
	dgr2.tl.y = dg2.y - 5;
	dgr2.br.x = dg2.x + 5;
	dgr2.br.y = dg2.y + 5;
}

void dm_scan_task();
void dm_loading_task0();
void dm_loading_task1();
void dm_loading_task2();

void gc_dm_t();
void gc_get_dm_t();

void
init_draw_matrix()
{
void indicate_md_by_large();
void print_mem_size();

	dm_lock = new_lock(LL_DRAW_MATRIX);

	memset(&pipe0,0,sizeof(SYS_QUEUE));
	pipe0.flags = QF_FIFO;
	pipe0.gc_func = gc_dm_t;
	pipe0.gc_get = gc_get_dm_t;
	pipe0.key_func = 0;
	pipe0.pri = PRI_FETCH;
	pipe0.total_limit = 5;
	setup_queue(&pipe0);

	memset(&pipe1,0,sizeof(SYS_QUEUE));
	pipe1.flags = QF_FIFO;
	pipe1.gc_func = gc_dm_t;
	pipe1.gc_get = gc_get_dm_t;
	pipe1.key_func = 0;
	pipe1.pri = PRI_FETCH;
	pipe1.total_limit = 1;
	setup_queue(&pipe1);

	memset(&pipe2,0,sizeof(SYS_QUEUE));
	pipe2.flags = QF_FIFO;
	pipe2.gc_func = gc_dm_t;
	pipe2.gc_get = gc_get_dm_t;
	pipe2.key_func = 0;
	pipe2.pri = PRI_FETCH;
	pipe2.total_limit = 1;
	setup_queue(&pipe2);

	tlist = 0;

	INIT_RING(&dm_h);
	create_task(dm_scan_task,0,PRI_FETCH_STRONG);
	create_task(dm_loading_task0,0,PRI_FETCH);
	create_task(dm_loading_task1,0,PRI_FETCH);
	create_task(dm_loading_task2,0,PRI_FETCH);
/*
new_tick(print_mem_size,1);
*/
}

void
gc_dm_t(DM_T * n)
{
void gc_gb_sexp();

	if ( n->data )
		gc_gb_sexp(n->data);
}

void
gc_get_dm_t(DM_T * n)
{
void gc_gb_sexp();
	lock_mem();
	if ( n->data )
		gc_set_nl(n->data,gc_gb_sexp);
	unlock_mem();
}



void
dm_gc_obj()
{
	lock_task(dm_lock);
	scan_flag = 1;
	wakeup_task((int)&dm_h);
	sleep_task((int)&scan_flag,dm_lock);
}


void
gc_dm()
{
DM_TIME_LIST * tl;
	for ( tl = tlist ; tl ; tl = tl->next ) {
		if ( tl->aboat_target == 0 )
			continue;
		gc_gb_sexp(tl->aboat_target);
	}
}

DM_TIME_LIST *
_get_tlist(L_CHAR * key,URL * target_url)
{
DM_TIME_LIST * ret;
	for ( ret = tlist ; ret ; ret = ret->next )
		if ( l_strcmp(ret->key,key) == 0 )
			return ret;
	ret = d_alloc(sizeof(*ret));
	memset(ret,0,sizeof(*ret));
	ret->key = ll_copy_str(key);
	copy_url(&ret->target_url,target_url);

	ret->next = tlist;
	tlist = ret;

	return ret;
}

DM_TIME_LIST *
get_tlist(L_CHAR * key,URL * target_url)
{
DM_TIME_LIST * ret;
	lock_task(dm_lock);
	ret = _get_tlist(key,target_url);
	unlock_task(dm_lock,"get_tlist");
	return ret;
}

int
get_dm_th()
{
RESOURCE * r;
int sum;
int sub;
int max_dm,min_dm;
int dm;
int i;
	sum = 0;
	max_dm = 600*400*50/
			default_dgb_pixel/default_dgb_pixel;
	min_dm = 0;
	for ( sub = 1 ; sub <= max_dm ; sub *= 4 )
		min_dm ++;
	for ( i = 0 ; i < RES_HASH_SIZE ; i ++ ) {
		r = res_entry_hash_table[i];
		for ( ; r ; r = r->h.entry_next ) {
			if ( r->h.type != RT_DRAW_GB ||
					r->draw_gb.type != DGT_PDB )
				continue;
			sub = r->draw_gb.level - r->draw_gb.hit_level;
sum += sub;
/*
			if ( sub < min_dm ) {
				if ( sub <= 0 )
					sub = 1;
				dm = 1;
				for ( ; sub > 0 ; sub -- ) {
					sum += dm;
					dm *= 4;
				}
			}
			else {
				dm = max_dm;
				for ( ; sub > 0 ; sub -- ) {
					sum += dm;
					dm = dm/4;
					if ( dm <= 0 ) {
						sum += sub;
						break;
					}
				}
			}
*/
		}
	}
/*
printf("th %i %i\n",sum,sum*LOAD_TASK_MAX);
*/
	return sum*LOAD_TASK_MAX;
}


void
_aboat_dm_loading()
{
DM_TIME_LIST * tl;

	for ( tl = tlist ; tl ; tl = tl->next ) {
		if ( tl->aboat_target == 0 )
			continue;
		np_divide_p_agent(&tl->target_url);
		aboat_session(tl->aboat_target);
		for ( ; tl->aboat_target ; ) {
			sleep_task((int)&tl->aboat_target,dm_lock);
			lock_task(dm_lock);
		}
	}
}

void
dm_resource_scan()
{
RESOURCE * r;
int i,j,len;
DRAW_MATRIX * d;
DRAW_MATRIX * d_st;
int min,max;

int target;

	target = dm_nos * 0.75;
	if ( target <= 0 )
		target = 1;
printf("scan %i\n",target);
	for ( ; check_queue(&pipe1,0,0) ; )
		sleep_sec(1);

	lock_task(dm_lock);
	_aboat_dm_loading(0);
	for ( ; dg_write_lock ; ) {
		sleep_task((int)&dg_write_lock,dm_lock);
		lock_task(dm_lock);
	}
	dg_write_lock = 1;
	unlock_task(dm_lock,"scan");

	for ( ; dm_nos > target ; ) {
		lock_task(dm_lock);
		d_st = d = R_PREV(DRAW_MATRIX *,&dm_h);
		for ( ; ; ) {
			if ( d == (DRAW_MATRIX*)&dm_h )
				d = R_PREV(DRAW_MATRIX*,&dm_h);
			if ( d->up == 0 )
				goto no;

			for ( i = 0 ; i < DM_DIM ; i ++ )
				for ( j = 0 ; j < DM_DIM ; j ++ ) {
					if ( d->m[i][j] == 0 )
						continue;
					goto no;
				}
			*d->up = 0;

			DELETE_RING(&d->h);
			unlock_task(dm_lock,"scan");


			scan_dm_point_list(d);
			d_f_ree(d);
			touch_obj_mem(-sizeof(*d));
			dm_nos --;
			break;
		no:
			d = R_PREV(DRAW_MATRIX*,&d->h);
			if ( d == d_st )
{ss_printf("UNRESOLVE SCAN DM\n");
				goto end;
}
		}
	}

	lock_task(dm_lock);
end:
	dg_write_lock = 0;
	wakeup_task((int)&dg_write_lock);
	unlock_task(dm_lock,"scan");
}


void
dm_loading_task1()
{
XL_INTERPRETER * xli;

XL_SEXP * ld, * ret;
RESOURCE * r;
WF_ID id;
DM_T * n;

set_cpu_thr_type(6);

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

	for ( ; ; ) {

		gc_push(0,0,"loading1");
		n = delete_queue(&pipe2,0,0,1);

		ld = n->data;
		r = n->r;
		id = n->wfid;

		d_f_ree(n->h.key);
		d_f_ree(n);
		lock_task(dm_lock);
		for ( ; dg_write_lock ; ) {
			sleep_task((int)&dg_write_lock,dm_lock);
			lock_task(dm_lock);
		}
		dg_write_lock = 1;

		unlock_task(dm_lock,"dm_loading_task1");


		for ( ; get_type(ld) == XLT_PAIR ; ld = cdr(ld) ) {
			ret = _dgb_p2d_trailer(r,car(ld));
			if ( get_type(ret) == XLT_ERROR ) {
printf("ERROR 1\n");
				set_inc_status_error(r,ret);
			}
		}
		gc_pop(0,0);
		lock_task(dm_lock);
		dg_write_lock = 0;
		wakeup_task((int)&dg_write_lock);
		unlock_task(dm_lock,"dg_loading");

	}
}

void
dm_loading_task2()
{
XL_INTERPRETER * xli;

XL_SEXP * ld, * pp;
RESOURCE * r;
WF_ID id;
DRAW_MATRIX ** dm_list;
int i;
DM_T * n;
DM_TIME_LIST * tl;
L_CHAR * key;

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

	for ( ; ; ) {

		gc_push(0,0,"dm_loading_task");

		n = delete_queue(&pipe1,0,0,1);
		ld = n->data;
		r = n->r;
		id = n->wfid;
		key = n->h.key;
		dm_list = d_alloc(sizeof(DRAW_MATRIX*)*DM_LIST_SIZE);
		for ( i = 0 ; i < DM_LIST_SIZE ; i ++ ) {
			dm_list[i] = n->dm_list[i];
			if ( dm_list[i] == 0 )
				break;
		}
		lock_task(dm_lock);
		tl = _get_tlist(n->h.key,&r->h.target);
		tl->time = n->handle_time;
		tl->aboat_target = ld;
		tl->start_time = get_xltime();
		unlock_task(dm_lock,"dm_loading_task");

		d_f_ree(n);

		for ( pp = ld ; get_type(pp) == XLT_PAIR ; pp = cdr(pp) );



		lock_task(dm_lock);
		tl->aboat_target = 0;
		wakeup_task((int)&tl->aboat_target);
		tl->start_time = 0;
		if ( get_type(pp) != XLT_NULL ) {
			for ( i = 0 ; i < DM_LIST_SIZE ; i ++ ) {
				if ( dm_list[i] == 0 )
					break;
				dm_list[i]->flags &= ~DMF_LOADED;
			}
			unlock_task(dm_lock,"dm_loading_task2");
			d_f_ree(key);
ss_printf("ERROR 2\n");
			goto end;
		}

		unlock_task(dm_lock,"dm_loading_task2");

		/***/

		n = new_queue_node(sizeof(*n));
		n->data = ld;
		n->r = r;
		n->wfid = id;
		n->h.key = key;

		insert_queue(&pipe2,n,1);

	end:
		gc_pop(0,0);
	}
}

int
check_request()
{
DRAW_MATRIX * dm;
int ret;
	dm = R_NEXT(DRAW_MATRIX*,&dm_h);
	ret = 0;
	for ( ; dm != (DRAW_MATRIX*)&dm_h ;
			dm = R_NEXT(DRAW_MATRIX*,&dm->h) ) {
		if ( dm->loop_no <= dm->r->draw_gb.loop_no
				- spiral_count - 2 )
			continue;
		if ( dm->flags & DMF_REQUEST )
			ret ++;
	}
	return ret;
}

int
loading_draw(
	DRAW_MATRIX * dm,
	int lev_min,
	int lev_max,
	GB_RECT * rct,
	DRAW_MATRIX ** dm_list,
	int ses)
{
XL_SEXP * ret,* ret_size, * ret_query;
int er;
XL_SEXP * gvr,* gt, * cmp;
char buf[10];
XL_SEXP * ret_func;
XL_SEXP * query, * ff, * qret;
L_CHAR * f;
int size,max_size;
SERVER_INFO si;
int req;
RESOURCE * r;
int wfid;
int i;
SI_GBVIEW * si_g;
DM_T * n;



	r = dm->r;
	wfid = dm->wfid;

	er = 0;



	si.active_flags = SIA_THPUT|SIA_NAME|SIA_DATA;
	si.name = n_string(std_cm,r->h.target.server);
	if ( get_serverinfo(&si) )
		goto fifo;
	si_g = (SI_GBVIEW *)si.data;
	if ( si_g == 0 ) {
		goto fifo;
	}
	else {
		if ( si.thput > THPUT_TH )
			si_g->dm_sched_type = DMST_FIFO;
	}
	switch ( si_g->dm_sched_type ) {
	case DMST_SIZE:
		max_size = 2*si.thput;
		if ( max_size < MIN_SIZE_OF_PACKET )
			max_size = MIN_SIZE_OF_PACKET;
		if ( dm->get_handle_time &&
				dm->get_level <= lev_max ) {
			max_size = -1;
		}
		break;
	case DMST_FIFO:
	fifo:
		max_size = -1;
		break;
	default:
		er_panic("loading_draw");
	}
/*
printf("get_handle_time = (%x) %i %i\n",dm,dm->get_handle_time,
max_size);
*/
	set_inc_status(r,RS_LOAD);
	gc_push(0,0,"loading_draw");
	gc_push(0,0,"loading_draw");
	gt = get_symbol(l_string(std_cm,"Get"));

	set_attribute(gt,
		l_string(std_cm,"format"),
		l_string(std_cm,"binary"));

	ff = get_string(f=get_url_filepath(&r->h.target)),
	d_f_ree(f);
	query = 0;
	for ( ; lev_min <= lev_max ; lev_min ++ ) {
		query = cons(
		    List(gt,
			n_get_symbol("path"),
			get_integer(lev_min,0),
			n_get_symbol("sq"),
			-1),
			query);
	}
	query = cons(n_get_symbol("List"),query);

	if ( max_size >= 0 ) {
		ret_func = List(n_get_symbol("If"),
			List(n_get_symbol(">"),
				get_integer(max_size,0),
				n_get_symbol("s"),
				-1),
			List(n_get_symbol("Then"),
				List(n_get_symbol("List"),
					n_get_string("ok"),
					n_get_symbol("result"),
					-1),
				-1),
			List(n_get_symbol("Else"),
				List(n_get_symbol("List"),
					n_get_string("large"),
					n_get_symbol("s"),
					-1),
				-1),
			-1);
		query = List(n_get_symbol("Sequence"),
				0,
				List(n_get_symbol("Define"),
					n_get_symbol("path"),
					ff,
					-1),
				List(n_get_symbol("Define"),
					n_get_symbol("sq"),
					List(n_get_symbol("List"),
						List(n_get_symbol("List"),
						 get_floating(rct->tl.x,0),
						 get_floating(rct->tl.y,0),
						 -1),
						List(n_get_symbol("List"),
						 get_floating(rct->br.x,0),
						 get_floating(rct->br.y,0),
						 -1),
						-1),
					-1),
				List(n_get_symbol("Define"),
					n_get_symbol("result"),
					query,
					-1),
				List(n_get_symbol("Define"),
					n_get_symbol("s"),
					List(n_get_symbol("GetSize"),
						n_get_symbol("result"),
						-1),
					-1),
				ret_func,
				-1);
	}
	else {
		ret_func = List(n_get_symbol("List"),
				n_get_string("ok"),
				query,
				-1);
		query = List(n_get_symbol("Sequence"),
				0,
				List(n_get_symbol("Define"),
					n_get_symbol("path"),
					ff,
					-1),
				List(n_get_symbol("Define"),
					n_get_symbol("sq"),
					List(n_get_symbol("List"),
						List(n_get_symbol("List"),
						 get_floating(rct->tl.x,0),
						 get_floating(rct->tl.y,0),
						 -1),
						List(n_get_symbol("List"),
						 get_floating(rct->br.x,0),
						 get_floating(rct->br.y,0),
						 -1),
						-1),
					-1),
				ret_func,
				-1);
	}

	set_inc_status(r,RS_LOAD);
/*
printf("query = ");
fflush(stdout);
print_sexp(s_stdout,query,0);
ss_printf("\n");
*/


set_cpu_msg(2);
	ret = remote_session(
		gblisp_top_env0,
		ses,
		&r->h.target,
		l_string(std_cm,"gbpdbp"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Get"),
		List(query,-1),
		0,0,0);
	n = new_queue_node(sizeof(*n));
	n->data = ret;
	n->r = r;
	n->wfid = wfid;
	n->max_size = max_size;
	n->lev_max = lev_max;

	n->dm = dm;
	for ( i = 0 ; i < DM_LIST_SIZE ; i ++ )
		n->dm_list[i] = dm_list[i];
	n->handle_time = dm->get_handle_time;
	n->h.key = get_server_key(&r->h.target);

	insert_queue(&pipe0,n,1);

	return 0;
}

void
dm_loading_task0()
{
XL_INTERPRETER * xli;

XL_SEXP * ld, * ret;
RESOURCE * r;
WF_ID id;
DM_T * n1,* n2;
int er;
DRAW_MATRIX * dm;
XL_SEXP * ret_size;
XL_SEXP * ret_query;
int i;

set_cpu_thr_type(6);

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

	for ( ; ; ) {

		n1 = delete_queue(&pipe0,0,0,1);

		ret = n1->data;
		dm = n1->dm;
		er = 0;
		r = n1->r;

		switch ( get_type(ret) ) {
		case XLT_ERROR:
			fprintf(stderr,"pdbp get error ");
			print_sexp(s_stderr,ret,0);

			set_inc_status_error(r,ret);

			fprintf(stderr,"\n");
			er = -1;
			goto end;
		case XLT_PAIR:
			set_inc_status(r,RS_IDLE);
			ret_size = get_el(ret,0);
			if ( l_strcmp(ret_size->string.data,
					l_string(std_cm,"ok")) ) {
				ret_query = get_el(ret,1);


				dm->get_handle_time
					= ret_query->integer.data/
						n1->max_size;
				if ( dm->get_handle_time <= 0 )
					dm->get_handle_time = 1;
				dm->get_level = n1->lev_max;
				er = -2;
printf("ERROR 3\n");
				goto end;
			}
			ret_query = get_el(ret,1);
			break;
		case XLT_NULL:
			set_inc_status(r,RS_IDLE);
printf("ERROR 4\n");
			er = -1;
			goto end;
		default:

			set_inc_status_error(r,
				get_error(
					0,
					0,
					XLE_SEMANTICS_TYPE_MISSMATCH,
					l_string(std_cm,"Get(pdbp)"),
				n_get_string(
				"server return invalid type data")));

			fprintf(stderr,
				"pdbp get: type missmatch return\n");
			print_sexp(s_stderr,ret,PF_RAW_DISABLE);
			fprintf(stderr,"\n");
			er = -1;
			goto end;
		}



		n2 = new_queue_node(sizeof(*n2));
		n2->data = ret_query;
		n2->r = n1->r;
		n2->wfid = n1->wfid;

		for ( i = 0 ; i < DM_LIST_SIZE ; i ++ )
			n2->dm_list[i] = n1->dm_list[i];
		n2->handle_time = dm->get_handle_time;
		n2->h.key = get_server_key(&r->h.target);

		insert_queue(&pipe1,n2,1);
	end:
		gc_pop(0,0);
		gc_pop(0,0);

		lock_task(dm_lock);
		if ( er == -2 )
			dm->flags |= DMF_REQUEST;
		if ( er < 0 ) {
			for ( i = 0 ; i < DM_LIST_SIZE ; i ++ ) {
				if ( n1->dm_list[i] == 0 )
					break;
				n1->dm_list[i]->flags &= ~DMF_LOADED;
			}
		}
		unlock_task(dm_lock,"loading_draw");

		d_f_ree(n1->h.key);
		d_f_ree(n1);
	}
}

int
set_dm_list(DRAW_MATRIX ** list,int ptr,DRAW_MATRIX * dm)
{
	if ( dm->flags & DMF_LOADED )
		return ptr;
	dm->flags |= DMF_LOADED;
	list[ptr++] = dm;
	return ptr;
}

int
check_loaded(DRAW_MATRIX * dm,DRAW_MATRIX ** dm_list,int dm_ptr)
{
int i,j;
	for ( i = 0 ; i < 2 ; i ++ )
		for ( j = 0 ; j < 2 ; j ++ ) {
			if ( dm->m[i][j] == 0 )
				return dm_ptr;
			if ( !(dm->m[i][j]->flags & DMF_LOADED) )
				return dm_ptr;
		}
	return set_dm_list(dm_list,dm_ptr,dm);
}

void
set_dm_ac(DRAW_MATRIX * dm)
{
	DELETE_RING(&dm->h);
	INSERT_RING(&dm_h,&dm->h);
	dm->access = get_ac_time();

	dm = dm->parent;
	for ( ; dm ; ) {
		DELETE_RING(&dm->h);
		INSERT_RING(&dm_h,&dm->h);
		dm->access = get_ac_time();
		dm = dm->parent;
	}
}

int
load_dm(int ses,DRAW_MATRIX *dm)
{
DRAW_MATRIX * dm2;
int lev_min,lev_max;
GB_RECT rct;
GB_POINT pt;
extern int point_nos;
int ret,i,dm_ptr;
DRAW_MATRIX ** dm_list;
/*
printf("level = %i %f %i\n",dm->level,
dm->r->draw_gb.pitch_list[dm->level+1].x,
dm->r->draw_gb.level);
*/
	lock_task(dm_lock);
	dm_list = d_alloc(sizeof(DRAW_MATRIX)*DM_LIST_SIZE);
	for ( i = 0 ; i < DM_LIST_SIZE ; i ++ )
		dm_list[i] = 0;
	dm->flags &= ~DMF_REQUEST;
	for ( dm2 = dm->parent ;
			dm2 ; dm2 = dm2->parent ) {
		dm2->flags &= ~DMF_REQUEST;
		dm2->get_handle_time = 0;
		dm2->get_level = 0;
	}

	dm_ptr = set_dm_list(dm_list,0,dm);
/*
	set_dm_ac(dm);
*/
	unlock_task(dm_lock,"load_dm");
	pt.x = dm->ofs.x*
		dm->r->draw_gb.pitch_list[dm->level].x;
	pt.y = dm->ofs.y*
		dm->r->draw_gb.pitch_list[dm->level].y;
	rct.tl = p_add(pt,dm->r->draw_gb.matrix_ofs);
	pt.x = (dm->ofs.x+1)*
		dm->r->draw_gb.pitch_list[dm->level].x;
	pt.y = (dm->ofs.y+1)*
		dm->r->draw_gb.pitch_list[dm->level].y;
	rct.br = p_add(pt,dm->r->draw_gb.matrix_ofs);
	if ( rct.br.x > dm->r->h.minrect.br.x )
		rct.br.x = dm->r->h.minrect.br.x;
	if ( rct.br.y > dm->r->h.minrect.br.y )
		rct.br.y = dm->r->h.minrect.br.y;
	if ( rct.tl.x < dm->r->h.minrect.tl.x )
		rct.tl.x = dm->r->h.minrect.tl.x;
	if ( rct.tl.y < dm->r->h.minrect.tl.y )
		rct.tl.y = dm->r->h.minrect.tl.y;
	if ( rct.tl.x >= rct.br.x )
		return 0;
	if ( rct.tl.y >= rct.br.y )
		return 0;
	lock_task(dm_lock);
	lev_min = dm->level;
	lev_max = dm->level;
	dm2 = dm;
	dm = dm->parent;
	for ( ; dm ; ) {
		if ( dm->flags & DMF_LOADED )
			break;
		lev_max = dm->level;
		dm_ptr = check_loaded(dm,dm_list,dm_ptr);
		dm = dm->parent;
	}
	unlock_task(dm_lock,"load_dm");

	dm_list[dm_ptr] = 0;
	loading_draw(dm2,
		lev_min,
		lev_max,
		&rct,
		dm_list,
		ses);
	d_f_ree(dm_list);

	return 0;
}


DRAW_MATRIX *
get_next_dm1()
{
DRAW_MATRIX * dm;
DRAW_MATRIX * dm_large,* dm_min;
REAL1 vr;
int ht;

	dm_large = 0;
	dm = R_NEXT(DRAW_MATRIX*,&dm_h);
	for ( ; dm != (DRAW_MATRIX*)&dm_h ;
		dm = R_NEXT(DRAW_MATRIX*,&dm->h) ) {
		if ( !(dm->flags & DMF_REQUEST) )
			continue;
		if ( dm->loop_no <= dm->r->draw_gb.loop_no
				- spiral_count - 2 ) {
			dm->flags &= ~DMF_REQUEST;
			continue;
		}
		if ( dm->get_handle_time == 0 ) {
			dm_min = dm;
			goto next;
		}
		if ( dm_large == 0 )
			dm_large = dm;
		else if ( dm_large->get_handle_time >
				dm->get_handle_time )
			dm_large = dm;
	}
	dm_min = dm_large;
next:
	if ( dm_min == 0 )
		return 0;
	if ( dm_min->r->h.visible_resolution == 0 )
		return dm_min;
	vr = dm_min->r->h.visible_resolution;
	ht = dm_min->get_handle_time + 2;
	dm_large = 0;
	dm = R_NEXT(DRAW_MATRIX*,&dm_h);
	for ( ; dm != (DRAW_MATRIX*)&dm_h ;
		dm = R_NEXT(DRAW_MATRIX*,&dm->h) ) {
		if ( dm == dm_min )
			continue;
		if ( !(dm->flags & DMF_REQUEST) )
			continue;
		if ( dm->loop_no <= dm->r->draw_gb.loop_no
				- spiral_count - 2 ) {
			dm->flags &= ~DMF_REQUEST;
			continue;
		}
		if ( vr <= dm->r->h.visible_resolution )
			continue;
		if ( ht < dm->get_handle_time )
			continue;
		dm_large = dm;
	}
	if ( dm_large == 0 )
		return dm_min;
	return dm_large;
}

DRAW_MATRIX *
get_next_dm2()
{
DRAW_MATRIX * dm;
DRAW_MATRIX * dm_large;
SI_GBVIEW * si_g;
SERVER_INFO si;

	dm_large = 0;
	dm = R_NEXT(DRAW_MATRIX*,&dm_h);
	for ( ; dm != (DRAW_MATRIX*)&dm_h ;
		dm = R_NEXT(DRAW_MATRIX*,&dm->h) ) {
		if ( !(dm->flags & DMF_REQUEST) )
			continue;
		if ( dm->loop_no <= dm->r->draw_gb.loop_no
				- spiral_count - 2 ) {
			dm->flags &= ~DMF_REQUEST;
			continue;
		}
		si.active_flags = SIA_NAME|SIA_DATA;
		si.name = n_string(std_cm,dm->r->h.target.server);
		if ( get_serverinfo(&si) )
			return dm;
		si_g = (SI_GBVIEW *)si.data;
		if ( si_g == 0 )
			return dm;
		if ( si_g->dm_sched_type != DMST_FIFO )
			continue;
		return dm;
	}
	return 0;
}


DRAW_MATRIX *
get_next_dm()
{
DRAW_MATRIX * dm;

	dm = get_next_dm2();
	if ( dm )
		return dm;
	return get_next_dm1();
}

void
dm_scan_task()
{
DRAW_MATRIX * dm;
XL_INTERPRETER * xli;
int ses;


printf("dm_scan_task %i\n",get_tid());

set_cpu_thr_type(4);

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);
	ses = open_session(SEST_OPTIMIZE);

	for ( ; ; ) {

		lock_task(dm_lock);
		if ( scan_flag ) {
			scan_flag = 0;
			unlock_task(dm_lock,"scan_required");
			dm_resource_scan();
			wakeup_task((int)&scan_flag);
		}
		else	unlock_task(dm_lock,"scan_required");


		lock_task(dm_lock);
		dm = get_next_dm();
		if ( dm )
			goto load;

		if ( scan_flag ) {
			unlock_task(dm_lock,"scan_Required");
			continue;
		}
		sleep_task((int)&dm_h,dm_lock);

		continue;
	load:
		unlock_task(dm_lock,"scan_required");
		load_dm(ses,dm);
	}
}


int
dm_last_access(int * ret_p)
{
DRAW_MATRIX * dm;
int ret;
	lock_task(dm_lock);
	dm = R_PREV(DRAW_MATRIX*,&dm_h);
	for ( ; dm != (DRAW_MATRIX*)&dm_h;
			dm = R_PREV(DRAW_MATRIX*,&dm->h) ) {
		if ( dm->up == 0 )
			continue;
		*ret_p = dm->access;
		ret = 0;
		goto end;
	}
	ret = -1;
end:
	unlock_task(dm_lock,"digging");
	return ret;
}

DRAW_MATRIX *
new_draw_matrix(WF_ID wfid,RESOURCE * r,DRAW_MATRIX * dm,int x,int y)
{
DRAW_MATRIX * dm1;
int i,j;
	touch_obj_mem(sizeof(*dm1));
	dm1 = d_alloc(sizeof(*dm1));
	dm1->get_handle_time = 0;
	dm1->get_level = 0;
	dm1->dm_point_list = 0;
	if ( dm == 0 ) {
		dm1->level = 0;
		dm1->ofs.x = 0;
		dm1->ofs.y = 0;
		dm1->up = 0;
		dm1->r = r;
		dm1->parent = 0;
	}
	else {
		if ( dm->level <= 0 )
			er_panic("new_draw_matrix(1)"); 
		dm1->level = dm->level-1;
		dm1->ofs.x = dm->ofs.x*DM_DIM + x;
		dm1->ofs.y = dm->ofs.y*DM_DIM + y;
		dm1->up = &dm->m[x][y];
		dm1->r = r;
		dm1->parent = dm;
	}
	for ( i = 0 ; i < DM_DIM ; i ++ )
		for ( j = 0 ; j < DM_DIM ; j ++ ) {
			dm1->m[i][j] = 0;
		}
	dm1->flags = 0;
	dm1->wfid = wfid;
	dm1->loop_no = r->draw_gb.loop_no;
	dm1->access = get_ac_time();
	dm_nos ++;
	INSERT_RING(&dm_h,&dm1->h);
	return dm1;
}

void
_digging_matrix(
	WF_ID wfid,
	RESOURCE * res,
	DRAW_MATRIX * dm,
	GB_RECT * r,
	int lev,
	DM_TIME_LIST * tl)
{
int i,j;
GB_RECT rr;
DRAW_MATRIX ** t_matrix;
DRAW_MATRIX * dm1;
int predict;
SI_GBVIEW g;
L_CHAR * key;
	DELETE_RING(&dm->h);
	INSERT_RING(&dm_h,&dm->h);
	dm->access = get_ac_time();
	dm->r = res;
	dm->loop_no = res->draw_gb.loop_no;


	if ( dm->level == lev && !(dm->flags & DMF_LOADED) ) {
		if ( !(dm->flags & DMF_REQUEST) &&
				tl->start_time ) {
			predict = tl->time  
				- (get_xltime() - tl->start_time);
			if ( predict < -DM_HANGING_TIME ||
					predict > DM_HANGING_TIME ) {
				_aboat_dm_loading();
				g.dm_sched_type = DMST_SIZE;
				set_si_gbview(
					n_string(std_cm,
						dm->r->h.target.server),
					SIG_DM_SCHED_TYPE,
					&g);
			}
		}

		dm->flags |= DMF_REQUEST;
		dm->wfid = wfid;
		wakeup_task((int)&dm_h);
	}
	if ( dm->level < lev )
		return;
	if ( dm->level == 0 )
		return;
	for ( i = 0 ; i < DM_DIM ; i ++ )
		for ( j = 0 ; j < DM_DIM ; j ++ ) {
			rr.tl.x = (dm->ofs.x*DM_DIM + i)*
				res->draw_gb.pitch_list[dm->level-1].x
				+ res->draw_gb.matrix_ofs.x;
			rr.tl.y = (dm->ofs.y*DM_DIM + j)*
				res->draw_gb.pitch_list[dm->level-1].y
				+ res->draw_gb.matrix_ofs.y;
			rr.br.x = (dm->ofs.x*DM_DIM + i + 1)*
				res->draw_gb.pitch_list[dm->level-1].x
				+ res->draw_gb.matrix_ofs.x;
			rr.br.y = (dm->ofs.y*DM_DIM + j + 1)*
				res->draw_gb.pitch_list[dm->level-1].y
				+ res->draw_gb.matrix_ofs.y;
			t_matrix = &dm->m[i][j];
			if ( cross_rect_rect(&rr,r) == 0 )
				continue;

			if ( *t_matrix ) {
				_digging_matrix(
					wfid,
					res,
					*t_matrix,
					r,
					lev,
					tl);
			}
			else {
				*t_matrix = new_draw_matrix(
						wfid,res,dm,i,j);
				_digging_matrix(
					wfid,
					res,
					*t_matrix,
					r,
					lev,
					tl);
/*
printf("lev %i %i %i\n",dm->level,
dm->ofs.x + i,dm->ofs.y + j);
*/
			}
		}
}

void
digging_matrix(
	WF_ID wfid,
	RESOURCE * res,
	GB_RECT * r,
	int lev)
{
DM_TIME_LIST * tl;
L_CHAR * f;
	lock_task(dm_lock);
	tl = _get_tlist(f = get_server_key(&res->h.target),&res->h.target);
	d_f_ree(f);
	_digging_matrix(wfid,res,res->draw_gb.dm,r,lev,tl);
	unlock_task(dm_lock,"digging");
}




int
_get_lod_of_position(RESOURCE * r,DRAW_MATRIX * dm,GB_POINT pt)
{
int i,j;
GB_RECT rr;
DRAW_MATRIX ** t_matrix;
DRAW_MATRIX * dm1;
	for ( i = 0 ; i < DM_DIM ; i ++ )
		for ( j = 0 ; j < DM_DIM ; j ++ ) {
			rr.tl.x = (dm->ofs.x*DM_DIM + i)*
				r->draw_gb.pitch_list[dm->level-1].x
					+ r->draw_gb.matrix_ofs.x;
			rr.tl.y = (dm->ofs.y*DM_DIM + j)*
				r->draw_gb.pitch_list[dm->level-1].y
					+ r->draw_gb.matrix_ofs.y;
			rr.br.x = (dm->ofs.x*DM_DIM + i + 1)*
				r->draw_gb.pitch_list[dm->level-1].x
					+ r->draw_gb.matrix_ofs.x;
			rr.br.y = (dm->ofs.y*DM_DIM + j + 1)*
				r->draw_gb.pitch_list[dm->level-1].y
					+ r->draw_gb.matrix_ofs.y;
			if ( inside_rect(&rr,pt) == 0 )
				continue;
			if ( dm->m[i][j] == 0 )
				return dm->level;
			return _get_lod_of_position(r,dm->m[i][j],pt);
		}
	return dm->level;
}

int
get_lod_of_position(RESOURCE * r,GB_POINT pt)
{
	return _get_lod_of_position(r,r->draw_gb.dm,pt);
}


DRAW_MATRIX *
_get_dm_of_position(RESOURCE * r,DRAW_MATRIX * dm,int lod,GB_POINT pt)
{
int i,j;
GB_RECT rr;
DRAW_MATRIX ** t_matrix;
DRAW_MATRIX * dm1;
	if ( dm->level == lod )
		return dm; 
	for ( i = 0 ; i < DM_DIM ; i ++ )
		for ( j = 0 ; j < DM_DIM ; j ++ ) {
			rr.tl.x = (dm->ofs.x*DM_DIM + i)*
				r->draw_gb.pitch_list[dm->level-1].x
					+ r->draw_gb.matrix_ofs.x;
			rr.tl.y = (dm->ofs.y*DM_DIM + j)*
				r->draw_gb.pitch_list[dm->level-1].y
					+ r->draw_gb.matrix_ofs.y;
			rr.br.x = (dm->ofs.x*DM_DIM + i + 1)*
				r->draw_gb.pitch_list[dm->level-1].x
					+ r->draw_gb.matrix_ofs.x;
			rr.br.y = (dm->ofs.y*DM_DIM + j + 1)*
				r->draw_gb.pitch_list[dm->level-1].y
					+ r->draw_gb.matrix_ofs.y;
			if ( inside_rect(&rr,pt) == 0 )
				continue;
			if ( dm->m[i][j] == 0 )
				return 0;
			return _get_dm_of_position(r,dm->m[i][j],lod,pt);
		}
	return 0;
}

DRAW_MATRIX *
get_dm_of_position(RESOURCE * r,int lod,GB_POINT pt)
{
	return _get_dm_of_position(r,r->draw_gb.dm,lod,pt);
}

WF_ID 
free_dm(DRAW_MATRIX * dm)
{
int i,j;
WF_ID wfid;
	if ( dm == 0 )
		return 0;
	for ( i = 0 ; i < DM_DIM ; i ++ )
		for ( j = 0 ; j < DM_DIM ; j ++ )
			free_dm(dm->m[i][j]);
	wfid = dm->wfid;
	DELETE_RING(&dm->h);
	d_f_ree(dm);
	touch_obj_mem(-sizeof(*dm));
	return wfid;
}
