/**********************************************************************
 
	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	"memory_debug.h"
#include	"memory_routine.h"
#include	"xlerror.h"
#include	"xl.h"
#include	"utils.h"
#include	"gbview.h"
#include	"win_flame.h"
#include	"lock_level.h"


extern SEM dm_lock;
void gc_gb_sexp();
#define PDB_RESO	0.5

extern int point_nos;



XL_SEXP * dgb_polygon2d(XLISP_ENV *,XL_SEXP *);
XL_SEXP * dgb_point(XLISP_ENV *,XL_SEXP *);
XL_SEXP * dgb_end(XLISP_ENV*,XL_SEXP *);
XL_SEXP * dgb_line_color(XLISP_ENV*,XL_SEXP *);
XL_SEXP * dgb_padding_color(XLISP_ENV*,XL_SEXP *);
XL_SEXP * dgb_information(XLISP_ENV *,XL_SEXP *);
XL_SEXP * dgb_mark();
XL_SEXP * gv_draw_gb_status();
XL_SEXP * dgb_p2d_trailer();
XL_SEXP * dgb_get_object_information();
XL_SEXP * dgb_set_scheme();
XL_SEXP * gv_set_visible_resolution();
XL_SEXP * svg_path();

void
init_draw_gb()
{
XLISP_ENV * draw_gb_top;
XLISP_ENV * draw_cmd;
XLISP_ENV * svg_env;

	init_vector();
	init_draw_matrix();

	draw_gb_top = new_env(gblisp_top_env0);
	draw_cmd = new_env(0);
	set_env(draw_cmd,l_string(std_cm,"polygon2d"),
			get_func_prim(dgb_polygon2d,FO_APPLICATIVE,
			0,1,1));
	set_env(draw_cmd,l_string(std_cm,"p2d-trailer"),
			get_func_prim(dgb_p2d_trailer,FO_APPLICATIVE,
			0,2,2));
	set_env(draw_cmd,l_string(std_cm,"point"),
			get_func_prim(dgb_point,FO_APPLICATIVE,0,2,3));
	set_env(draw_cmd,l_string(std_cm,"end"),
			get_func_prim(dgb_end,FO_NORMAL,0,2,2));
	set_env(draw_cmd,l_string(std_cm,"line-color"),
		get_func_prim(dgb_line_color,FO_APPLICATIVE,0,2,5));
	set_env(draw_cmd,l_string(std_cm,"padding-color"),
		get_func_prim(dgb_padding_color,FO_APPLICATIVE,0,2,5));
	set_env(draw_cmd,l_string(std_cm,"information"),
			get_func_prim(dgb_information,FO_NORMAL,0,2,-1));
	set_env(draw_cmd,l_string(std_cm,"mark"),
			get_func_prim(dgb_mark,FO_APPLICATIVE,
				gblisp_top_env0,2,3));
	set_env(draw_cmd,l_string(std_cm,"get-object-information"),
			get_func_prim(dgb_get_object_information,
				FO_APPLICATIVE,0,2,2));
	set_env(draw_cmd,l_string(std_cm,"set-scheme"),
			get_func_prim(dgb_set_scheme,
			FO_APPLICATIVE,0,1,1));

	set_env(draw_cmd,l_string(std_cm,"set-visible-resolution"),
			get_func_prim(gv_set_visible_resolution,
			FO_APPLICATIVE,0,2,2));


	svg_env = new_env(draw_cmd);
	root_tag(draw_cmd,l_string(std_cm,"svg"),svg_env);

	set_env(draw_gb_top,l_string(std_cm,"gv-status"),
			get_func_prim(gv_draw_gb_status,
			FO_APPLICATIVE,0,1,1));

	root_tag(draw_gb_top,l_string(std_cm,"vector"),draw_cmd);
	set_env(gblisp_top_env0,l_string(std_cm,"vector"),
		get_env(draw_gb_top));
	set_gv_resource(RT_DRAW_GB,draw_gb_top);

	set_env(svg_env,l_string(std_cm,"path"),
			get_func_prim(svg_path,FO_APPLICATIVE,
				0,1,1));
}



GB_RECT *
get_object_minrect(OBJ * o)
{
	return &o->h.minrect;
}

void
new_vector_option1(RESOURCE * r,int ds)
{
	r->draw_gb.pdb_lock= 0;
	r->draw_gb.pdb_lock_task = 0;
	if ( ds == NR_CLEAR )
		free_object_list(r);
	r->draw_gb.obj_code_tree = 0;

	init_rect_tree(
		&r->draw_gb.obj_rect_tree,
		&r->h.minrect,
		get_object_minrect);
}

void
new_vector_option2(RESOURCE * r,int ds,int level)
{
	lock_task(dm_lock);
	if ( ds == NR_CLEAR )
		free_dm(r->draw_gb.dm);
	r->draw_gb.dm = new_draw_matrix(0,r,0,0,0);
	r->draw_gb.dm->level = level-1;
	r->draw_gb.pdb_lock = 0;
	r->draw_gb.pdb_lock_task = 0;
	r->draw_gb.dm->flags = 0;
	unlock_task(dm_lock,"draw_data");
	if ( ds == NR_CLEAR )
		free_object_list(r);
	r->draw_gb.obj_code_tree = 0;

	init_rect_tree(
		&r->draw_gb.obj_rect_tree,
		&r->h.minrect,
		get_object_minrect);
}


XL_SEXP *
dgb_get_object_information(
	XLISP_ENV * env,XL_SEXP * s,XLISP_ENV * a,XL_SYM_FIELD * sf)
{
XL_SEXP * code;
int format;
int _code;
RESOURCE * r;
XL_SEXP * ret;
OBJ * o;
XL_SEXP * anc;
	r = get_resource_ptr(&ret,env,s->h.file,s->h.line);
	if ( r == 0 )
		return ret;
	format = 0;
	for ( ; sf ; sf = sf->next ) {
		if ( l_strcmp(sf->name,l_string(std_cm,"format")) == 0 ) {
			if ( l_strcmp(sf->data,l_string(std_cm,"on")) == 0 ) {
				format = 1;
			}
			else if ( l_strcmp(sf->data,l_string(std_cm,"off"))
					== 0 ) {
				format = 0;
			}
			else	goto invalid_option;
		}
	}
	code = get_el(s,1);
	if ( get_type(code) != XLT_INTEGER )
		goto type_missmatch;
	_code = code->integer.data;
	o = search_obj(r,_code);
	if ( o == 0 )
		goto no_object;
	if ( (o->h.flags & OF_INFO_STS) == OF_INFO_NOCHECK )
		return 0;
	if ( format == 0 )
		return o->h.info_org;
	return o->h.info_card;
	return 0;
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"get-object-information"),
		List(n_get_string("type missmatch"),-1));
invalid_option:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"get-object-information"),
		List(n_get_string("option type missmatch"),-1));
no_object:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_UNDEF_NAME,
		l_string(std_cm,"get-object-information"),
		List(n_get_string("invalid object code"),-1));
}



XL_SEXP *
dgb_set_scheme(XLISP_ENV * env,XL_SEXP * s,
	XLISP_ENV * a,XL_SYM_FIELD * sf)
{
L_CHAR * card, * onmap;
L_CHAR * scheme;
char * e_param;
int card_type,onmap_type;
RESOURCE * r;
XL_SEXP * ret;
L_CHAR * entry;
	r = get_resource_ptr(&ret,env,s->h.file,s->h.line);
	if ( r == 0 )
		return ret;
	scheme = 0;
	card = 0;
	onmap = 0;
	card_type = SFT_XL;
	onmap_type = SFT_XL;
	for ( ; sf ; sf = sf->next ) {
		if ( l_strcmp(sf->name,l_string(std_cm,"scheme")) == 0 )
			scheme = sf->data;
		else if ( l_strcmp(sf->name,l_string(std_cm,"card")) == 0 )
			card = sf->data;
		else if ( l_strcmp(sf->name,l_string(std_cm,"onmap")) == 0 )
			onmap = sf->data;
		else if ( l_strcmp(sf->name,l_string(std_cm,"card.type"))
				== 0 ) {
			e_param = "card.type";
			if ( l_strcmp(sf->data,
				l_string(std_cm,"text/xl")) == 0 )
				card_type = SFT_XL;
			else if ( l_strcmp(sf->data,
				l_string(std_cm,"text/xsl")) == 0 )
				card_type = SFT_XSL;
			else goto type_missmatch;
		}
		else if ( l_strcmp(sf->name,l_string(std_cm,"onmap.type"))
				== 0 ) {
			e_param = "onmap.type";
			if ( l_strcmp(sf->data,
				l_string(std_cm,"text/xl")) == 0 )
				onmap_type = SFT_XL;
			else if ( l_strcmp(sf->data,
				l_string(std_cm,"text/xsl")) == 0 )
				onmap_type = SFT_XSL;
			else goto type_missmatch;
		}
	}
	if ( scheme == 0 ) {
		e_param = "scheme";
		goto attr_required;
	}
	if ( card == 0 ) {
		e_param = "card";
		goto attr_required;
	}
	if ( onmap == 0 ) {
		e_param = "onmap";
		goto attr_required;
	}
	entry = get_url_str2(&r->h.entry);
	card = compose_url(entry,card);
	onmap = compose_url(entry,onmap);
	insert_scheme(&r->draw_gb.ischeme,scheme,
		card_type,onmap_type,
		card,onmap);
	d_f_ree(onmap);
	d_f_ree(card);
	return 0;
attr_required:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"set-scheme"),
		List(n_get_string("attribute"),
			n_get_string(e_param),
			n_get_string("is required"),
			-1));
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"set-scheme"),
		List(n_get_string("attribute"),
			n_get_string(e_param),
			n_get_string("type missmatch"),
			-1));
}



int
get_object_list_func(AVT_NODE * a,XL_SEXP ** ret)
{
XL_SEXP * rec;
	object_list(a->data,&rec);
	*ret = cons(rec,*ret);
	return 0;
}


XL_SEXP *
get_object_list(RESOURCE * r)
{
OBJ * o;
XL_SEXP * ret;
XL_SEXP * rec;
	ret = 0;
	avt_trace_from_small(
		r->draw_gb.obj_code_tree,
		get_object_list_func,&ret);
	return ret;
}


XL_SEXP * 
gv_draw_gb_status(XLISP_ENV * env,XL_SEXP * s,
	XLISP_ENV * a,XL_SYM_FIELD * sf)
{
XL_SEXP * ret,* data;
RESOURCE * r;
	ret = get_resource_status_header(&r,env,s,a,0);
	if ( get_type(ret) == XLT_ERROR )
		return ret;
	switch ( r->draw_gb.type ) {
	case DGT_LOAD:
		data = List(List(get_symbol(l_string(std_cm,"type")),
				get_integer(r->draw_gb.type,0),
				-1),
			-1);
		break;
	case DGT_PDB:
		data = List(	List(get_symbol(l_string(std_cm,"type")),
					get_integer(r->draw_gb.type,0),
					-1),
				List(get_symbol(l_string(std_cm,"level")),
					get_integer(r->draw_gb.level,0),
					-1),
				List(get_symbol(
					l_string(std_cm,"resolution")),
					get_floating(r->draw_gb
						.resolution,
						0),
					-1),
				-1);
		break;
	}
	return cons(get_symbol(l_string(std_cm,"vector")),
		    append(ret,data));
}


int
get_point_draw(
	GBVIEW_FLAME * gf,
	RESOURCE *	r,
	GET_POINT_WORK * w)
{
OBJ * o;
int ret;
INDICATE * in;
GB_RECT min,max;
RT_OBJ_LIST * ol, * olp;

	min.tl = r->h.minrect.tl;
	min.br = w->pt;

	max.tl = w->pt;
	max.br = r->h.minrect.br;

	lock_pdb_lock(r,0);

	ol = search_rect_tree(
		&r->draw_gb.obj_rect_tree,&min,&max);

	ret = 0;
	for ( olp = ol ; olp ; olp = olp->next )
		if ( get_point_object(gf,r,olp->obj,w) )
			ret = 1;
	unlock_pdb_lock(r);
	free_rt_obj_list(ol);

	if ( ret == 0 )
		return 0;
	in = _search_indicate(gf,&r->h.entry);
	if ( in == 0 )
		return 0;
	if ( in->flags&IF_COORDINATE ) {
		in->result = w->pt;
		in->status = IS_COORDINATE;
	}
	return 0;
}


void
divide_ol(RT_OBJ_LIST * ol,RT_OBJ_LIST ** ret1,RT_OBJ_LIST ** ret2)
{
RT_OBJ_LIST * ol2;
	*ret1 = 0;
	*ret2 = 0;
	for ( ; ol ; ) {
		ol2 = ol;
		ol = ol->next;

		ol2->next = *ret1;
		*ret1 = ol2;

		if ( ol == 0 )
			break;

		ol2 = ol;
		ol = ol->next;

		ol2->next = *ret2;
		*ret2 = ol2;
	}
}

int
cmp_ol(RT_OBJ_LIST * ol1,RT_OBJ_LIST * ol2)
{
OBJ * o1,* o2;
	o1 = ol1->obj;
	o2 = ol2->obj;
	if ( o1->h.code < o2->h.code )
		return -1;
	if ( o1->h.code > o2->h.code )
		return 1;
	return 0;
}


RT_OBJ_LIST *
marge_ol(RT_OBJ_LIST * ol1,RT_OBJ_LIST * ol2)
{
RT_OBJ_LIST * ret;
RT_OBJ_LIST ** retp;
int r;
RT_OBJ_LIST * ol3;
	ret = 0;
	retp = &ret;
	for ( ; ol1 && ol2 ; ) {
		r = cmp_ol(ol1,ol2);
		if ( r < 0 ) {
			ol3 = ol1;
			ol1 = ol1->next;

			ol3->next = 0;
			*retp = ol3;
			retp = &ol3->next;
		}
		else {
			ol3 = ol2;
			ol2 = ol2->next;

			ol3->next = 0;
			*retp = ol3;
			retp = &ol3->next;
		}
	}
	if ( ol1 )
		*retp = ol1;
	else	*retp = ol2;
	return ret;
}

void
check_obj_list(RT_OBJ_LIST * ol)
{
	for ( ; ol ; ol = ol->next ) {
		if ( ol->next == 0 )
			break;
		if ( cmp_ol(ol,ol->next) > 0 )
			printf("check_obj error\n");
	}
}

RT_OBJ_LIST *
sort_obj_list(RT_OBJ_LIST * ol)
{
RT_OBJ_LIST * ol2, * ol3;
	if ( ol == 0 )
		return 0;
	if ( ol->next == 0 )
		return ol;
	if ( ol->next->next == 0 ) {
		ol2 = ol->next;
		if ( cmp_ol(ol,ol2) < 0 )
			return ol;
		ol2->next = ol;
		ol->next = 0;
		return ol2;
	}
	divide_ol(ol,&ol2,&ol3);
	ol2 = sort_obj_list(ol2);
	ol3 = sort_obj_list(ol3);
	return marge_ol(ol2,ol3);
}

void
draw_draw_gb(
	GBVIEW_FLAME * gf,
	RESOURCE* r,
	DRAW_WORK * dw)
{
OBJ * o;
int i;
GB_RECT rct;
GB_RECT * rp;
int rp_len;
int rr;
double reso,reso2;
int lev;
GB_POINT pt;
int size;
RT_OBJ_LIST * ol, * olp, ** olpp;
GB_RECT min,max;
REAL1 serf1,serf2;
double pitch;
int olcnt;

	if ( dw->method == 0 )
		return; 
	rp = get_surp_rect_rate(&rp_len,&dw->surp,0.1,0);
	for ( rr = 0 ; rr < rp_len ; rr ++ )  {
		rct = rp[rr];

		dw->draw_rect = rct;
		dw->draw_lod = 0;

		dw->limit_reso = r->draw_gb.resolution; 
		dw->limit_ptr = p_add(rct.tl,rct.br);
		dw->limit_ptr.x /= 2;
		dw->limit_ptr.y /= 2;

		if ( lock_pdb_lock(r,1) < 0 )
			continue;

		if ( r->draw_gb.type == DGT_LOAD )
			goto draw;
		reso2 = r->draw_gb.resolution;
		reso = get_surp_reso(&dw->surp);
/*
	if ( reso > reso2*LIMIT_RESOLUTION_RATE )
		goto end;
*/
		for ( lev = 0; lev < r->draw_gb.level ; lev ++, reso2 = reso2/2 )
			if ( reso > reso2*PDB_RESO )
				break;
		r->draw_gb.hit_level = lev;
		if ( lev == r->draw_gb.level )
			goto end;
		r->draw_gb.loop_no ++;
		pitch = ((rct.br.x - rct.tl.x)/r->draw_gb.pitch_list[lev].x) *
				((rct.br.y - rct.tl.y)/r->draw_gb.pitch_list[lev].y );
		if ( pitch > 1000 ) {
ss_printf("PITCH WARNING ============================ %f",pitch);
			for ( ; pitch > 1000 ; pitch /= 2 , lev ++ );
		}
		digging_matrix(dw->wfid,r,&rct,lev);
		dw->draw_lod = lev;

	draw:

		serf1 = (rct.br.x - rct.tl.x)*(rct.br.y - rct.tl.y);
		serf2 = (r->h.minrect.br.x - r->h.minrect.tl.x)*
				(r->h.minrect.br.y - r->h.minrect.tl.y);
		min.tl.x = r->h.minrect.tl.x;
		min.tl.y = r->h.minrect.tl.y;
		min.br.x = rct.tl.x;
		min.br.y = rct.tl.y;

		max.tl.x = rct.br.x;
		max.tl.y = rct.br.y;
		max.br.x = r->h.minrect.br.x;
		max.br.y = r->h.minrect.br.y;

		ol = search_rect_tree(&r->draw_gb.obj_rect_tree,
			&min,&max);


		dw->resource = r;
/*
printf("r minrect (%f %f) - (%f %f)\n",
r->h.minrect.tl.x,
r->h.minrect.tl.y,
r->h.minrect.br.x,
r->h.minrect.br.y);
printf("r rect (%f %f) - (%f %f)\n",
rct.tl.x,
rct.tl.y,
rct.br.x,
rct.br.y);
*/

		for ( olpp = &ol ; *olpp ;) {
			o = (*olpp)->obj;
			if ( o->h.lod_min < 0 ) {
				olpp = &(*olpp)->next;
				continue;
			}
			else if ( o->h.lod_min <= lev &&
					lev <= o->h.lod_max ) {
				olpp = &(*olpp)->next;
				continue;
			}
			olp = *olpp;
			*olpp = olp->next;
			olp->next = 0;
			free_rt_obj_list(olp);
		}


		ol = sort_obj_list(ol);
	check_obj_list(ol);
		for ( olp = ol ; olp ; olp = olp->next ) {
			draw_object(gf,olp->obj,dw);
			dw->flags |= WFF_DRAW;
		}

		free_rt_obj_list(ol);
	end:

		unlock_pdb_lock(r);
	}
}


int
select_draw_gb_func(AVT_NODE * a,SELECT_WORK * sw)
{
	return select_object(a->data,sw);
}

int
select_draw_gb(
	RESOURCE * r,
	SELECT_WORK * sw)
{
	return avt_trace_from_large(
		r->draw_gb.obj_code_tree,
		select_draw_gb_func,
		sw);
}

int
check_vector(RESOURCE * r,CHECK_WORK * chk)
{
int ret;
	ret = check_default(r,chk);
	if ( ret != 0 )
		return ret;
	chk->opt[r->h.type] |= r->draw_gb.flags;
	return 0;
}

int
exit_lock_vector(RESOURCE * r,int data)
{
	pdb_err_sensitive(r,data);
	return 0;
}



