/**********************************************************************
 
	Copyright (C) 2004 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	"gbgraph.h"
#include	"gbview.h"
#include	"gb.h"

typedef struct gm_type {
	char *		category;
	char *		category_symbol;
	XL_SEXP *	(*get_meta)(
				struct gm_type*,
				XLISP_ENV*,
				XL_SEXP *,
				XL_SEXP*,
				XL_FILE*,
				int);
} GM_TYPE;

XL_SEXP * get_meta_vector(struct gm_type*,XLISP_ENV*,XL_SEXP *,XL_SEXP*,
			  XL_FILE*,int);
XL_SEXP * get_meta_raster(struct gm_type*,XLISP_ENV*,XL_SEXP *,XL_SEXP*,
			  XL_FILE*,int);
XL_SEXP * get_meta_map(struct gm_type*,XLISP_ENV*,XL_SEXP*,XL_SEXP *,
			  XL_FILE*,int);
XL_SEXP * get_meta_coordinate(struct gm_type*,XLISP_ENV*,XL_SEXP*,XL_SEXP*,
			  XL_FILE*,int);
XL_SEXP * get_meta_vector_xl(GM_TYPE * gmp,XLISP_ENV * env,
		   XL_SEXP * dd,XL_SEXP * meta,
		   XL_FILE * file,int line);
XL_SEXP * get_core_data(GM_TYPE ** gmpp,XL_SEXP * s,XL_FILE * file,int line);

GM_TYPE gm_list[] = {
	{"vector","vector",get_meta_vector},
	{"luster","luster",get_meta_raster},
	{"raster","luster",get_meta_raster},
	{"map","map",0},
	{"coordinate","coordinate",get_meta_coordinate},
	{0}
};

XL_SEXP *
get_meta_vector_xl(GM_TYPE * gmp,XLISP_ENV * env,
		   XL_SEXP * dd,XL_SEXP * meta,
		   XL_FILE * file,int line)
{
XL_SEXP * el;
XL_SEXP * sym;
XL_SEXP * ptr;
XL_SEXP * _x, * _y;
L_CHAR * unit_x,* unit_y;
GB_RECT r;
GB_POINT pt;
int er;
	unit_x = unit_y = 0;
	r.tl.x = r.tl.y = 0;
	r.br.x = r.br.y = -1;
	for ( ; get_type(dd) == XLT_PAIR ; dd = cdr(dd) ) {
		el = car(dd);
		if ( get_type(el) != XLT_PAIR )
			continue;
		sym = car(el);
		if ( get_type(sym) != XLT_SYMBOL )
			continue;
		if ( l_strcmp(sym->string.data,
				l_string(std_cm,"mark")) == 0 ) {
			ptr = get_el_by_symbol(
					el,
					l_string(std_cm,"point"),
					0);
			if ( ptr == 0 )
				continue;
			_x = get_el(ptr,1);
			_y = get_el(ptr,2);
			switch ( get_type(_x) ) {
			case XLT_INTEGER:
				if ( unit_x == 0 )
					unit_x = _x->integer.unit;
				pt.x = conv_unit(&er,
						get_uenv(env),
						_x->integer.data,
						unit_x,
						_x->integer.unit);
				break;
			case XLT_FLOAT:
				if ( unit_x == 0 )
					unit_x = _x->floating.unit;
				pt.x = conv_unit(&er,
						get_uenv(env),
						_x->floating.data,
						unit_x,
						_x->floating.unit);
				break;
			default:
				continue;
			}
			switch ( get_type(_y) ) {
			case XLT_INTEGER:
				if ( unit_y == 0 )
					unit_y = _y->integer.unit;
				pt.y = conv_unit(&er,
						get_uenv(env),
						_y->integer.data,
						unit_y,
						_y->integer.unit);
				break;
			case XLT_FLOAT:
				if ( unit_y == 0 )
					unit_y = _y->floating.unit;
				pt.y = conv_unit(&er,
						get_uenv(env),
						_y->floating.data,
						unit_y,
						_y->floating.unit);
				break;
			default:
				continue;
			}
			insert_rect(&r,pt);
		}
	}
	return append(meta,
		List(List(n_get_symbol("mr"),
			List(	List(
				get_floating(r.tl.x,unit_x),
				get_floating(r.tl.y,unit_y),
				-1),
				List(
				get_floating(r.br.x,unit_x),
				get_floating(r.br.y,unit_y),
				-1),
				-1)),-1));
}

XL_SEXP *
get_meta_vector(GM_TYPE * gmp,XLISP_ENV* env,XL_SEXP * dd,XL_SEXP * meta,
		XL_FILE * _file,int _line)
{
XL_SEXP * file;
XL_SEXP * file_sym;
L_CHAR * attr;
	file = get_el_by_symbol(meta,
			l_string(std_cm,"file"),
			0);
	if ( file == 0 )
		return meta;
	file_sym = car(file);
	attr = get_sf_attribute(file_sym->symbol.field,
			l_string(std_cm,"type"));
	if ( attr == 0 )
		goto format_error;
	if ( l_strcmp(attr,l_string(std_cm,"xl")) == 0 )
		return get_meta_vector_xl(gmp,env,dd,meta,_file,_line);
	er_panic("vector");
	return 0;
format_error:
	return get_error(
		_file,
		_line,
		XLE_SEMANTICS_INV_FORMAT,
		l_string(std_cm,"GetMeta"),
		n_get_string("invalid format(vector:1)"));
}

XL_SEXP *
get_meta_raster(GM_TYPE * gmp,XLISP_ENV * env,XL_SEXP * dd,XL_SEXP * meta,
		XL_FILE*file,int line)
{
	er_panic("raster");
	return 0;
}


XL_SEXP *
get_meta_coordinate(GM_TYPE * gmp,XLISP_ENV * env,
			XL_SEXP * dd,XL_SEXP * meta,
			XL_FILE*file,int line)
{
XL_SEXP * reso;
	reso = get_el_by_symbol(dd,
			l_string(std_cm,"v"),
			0);
	if ( reso == 0 )
		return meta;
	return append(meta,List(reso,-1));
}


XL_SEXP *
get_core_data(GM_TYPE ** gmpp,XL_SEXP * s,XL_FILE * file,int line)
{
XL_SEXP * dd;
GM_TYPE * gmp;
XL_SEXP * d;
	if ( get_type(s) != XLT_PAIR )
		goto format_error;
	dd = car(s);
	*gmpp = 0;
	if ( get_type(dd) == XLT_SYMBOL ) {
		for ( gmp = &gm_list[0] ; gmp->category ; gmp ++ )
			if ( l_strcmp(dd->symbol.data,
				l_string(std_cm,
					gmp->category)) == 0 ) {
				*gmpp = gmp;
				d = s;
				goto ok;
			}
		goto format_error;
	}
	d = 0;
	for ( ; get_type(s) == XLT_PAIR ; s = cdr(s) ) {
		d = get_core_data(gmpp,car(s),file,line);
		if ( get_type(d) != XLT_ERROR )
			break;
	}
	if ( d == 0 )
		goto format_error;
ok:
	return d;
format_error:
	return get_error(
		file,
		line,
		XLE_SEMANTICS_INV_FORMAT,
		l_string(std_cm,"GetMeta"),
		List(
		n_get_string("invalid format(core data search:category)"),
		s,-1));
}

XL_SEXP *
get_meta(XLISP_ENV * env,XL_SEXP * s)
{
XL_SEXP * d;
XL_SEXP * meta;
GM_TYPE * gmp;
	if ( env == 0 )
		env = gblisp_top_env0;
	d = get_core_data(&gmp,s,s->h.file,s->h.line);
	switch ( get_type(d) ) {
	case XLT_ERROR:
		return d;
	case XLT_NULL:
		er_panic("get_meta");
	}
	meta = get_el_by_symbol(
		d,
		l_string(std_cm,"meta"),
		0);
	if ( meta == 0 )
		return 0;
	meta = append(meta,
		List(List(n_get_symbol("category"),
			n_get_string(gmp->category_symbol),
			-1),-1));
	if ( gmp->get_meta == 0 )
		return meta;
	else	return (*gmp->get_meta)(gmp,env,d,meta,
					s->h.file,s->h.line);
}


