/**********************************************************************
 
	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	"xlerror.h"
#include	"xl.h"
#include	"netmapper.h"

extern void gc_gb_sexp();
XL_SEXP * xl_WellKnownPoint();
int loading_target;

void
init_WellKnownPoint(XLISP_ENV * env)
{
	set_env(env,l_string(std_cm,"WellKnownPoint"),
		get_func_prim(xl_WellKnownPoint,FO_APPLICATIVE,0,3,3));
}

typedef struct sv_work {
	double		tol;
	NAME_PTR	p;
	NM_VERTEX *	ret;
} SV_WORK;

int
search_vertex_ptr_func(AVT_NODE * a,SV_WORK * w)
{
NM_VERTEX * v;
NAME_PTR * pp;
	v = a->data;
	pp = v->name;
	if ( pp->x < w->p.x - w->tol )
		return 0;
	if ( pp->x > w->p.x + w->tol )
		return 0;
	if ( pp->y < w->p.y - w->tol )
		return 0;
	if ( pp->y > w->p.y + w->tol )
		return 0;
	w->ret = v;
	return 1;
}

NM_VERTEX *
search_vertex_ptr(XL_SEXP ** retp,int target,XL_SEXP * name,XL_SEXP * s)
{
int len;
XL_SEXP * el;
NAME_PTR p;
NM_VERTEX v;
SV_WORK svw;
AVT_NODE * a;
	*retp = 0;
	if ( get_type(name) != XLT_PAIR )
		goto type_missmatch;
	len = list_length(name);
	if ( len < 0 ) {
		*retp = list_error(name);
		return 0;
	}
	if ( len != 2 )
		goto type_missmatch;
	el = get_el(name,0);
	switch ( get_type(el) ) {
	case XLT_INTEGER:
		p.x = el->integer.data;
		break;
	case XLT_FLOAT:
		p.x = el->floating.data;
		break;
	default:
		goto type_missmatch;
	}
	el = get_el(name,1);
	switch ( get_type(el) ) {
	case XLT_INTEGER:
		p.y = el->integer.data;
		break;
	case XLT_FLOAT:
		p.y = el->floating.data;
		break;
	default:
		goto type_missmatch;
	}
	if ( net_target[target].tolerance == 0 ) {
		v.name = &p;
		a = avt_search(net_target[target].tree,
			&v,
			net_target[target].avt_cmp);
		if ( a == 0 )
			return 0;
		return a->data;
	}
	svw.ret = 0;
	svw.tol = net_target[target].tolerance;
	svw.p = p;
	avt_trace_from_small(net_target[target].tree,
		search_vertex_ptr_func,&svw);
	return svw.ret;
type_missmatch:
	*retp = get_error(
		s->h.file,
		s->h.line,		
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"WellKnownPoint"),
		List(n_get_string("type missmatch"),
			-1));
	return 0;
}

NM_VERTEX *
search_vertex_str(XL_SEXP ** retp,int target,XL_SEXP * name,XL_SEXP * s)
{
NM_VERTEX v;
AVT_NODE * a;
	*retp = 0;
	if ( get_type(name) != XLT_STRING )
		goto type_missmatch;
	v.name = name->string.data;
	a = avt_search(net_target[target].tree,
		&v,
		net_target[target].avt_cmp);
	if ( a == 0 )
		return 0;
	return a->data;
type_missmatch:
	*retp = get_error(
		s->h.file,
		s->h.line,		
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"WellKnownPoint"),
		List(n_get_string("type missmatch"),
			-1));
	return 0;
}

XL_SEXP *
xl_WellKnownPoint(XLISP_ENV * env,XL_SEXP * s,
	XLISP_ENV * a,XL_SYM_FIELD * sf)
{
NM_VERTEX * v1, * v2;
XL_SEXP * n1,* n2;
char * e_param;
XL_SEXP * ret;
	n1 = get_el(s,1);
	n2 = get_el(s,2);
	switch ( net_target[0].name_type ) {
	case 0:
		e_param = "target=1";
		goto undef_target;
	case NMT_PTR:
		v1 = search_vertex_ptr(&ret,0,n1,s);
		if ( v1 )
			printf("WellKnown(target=1) (%lf %lf)\n",
				((NAME_PTR*)v1->name)->x,
				((NAME_PTR*)v1->name)->y);
		break;
	case NMT_STR:
		v1 = search_vertex_str(&ret,0,n1,s);
		if ( v1 ) 
			printf("WellKnown(target=1) (%s)\n",
				n_string(std_cm,v1->name));
		break;
	default:
		er_panic("xl_WellKnownPoint(1)");
	}
	if ( ret )
		return ret;
	if ( v1 == 0 ) {
		e_param = "target=1";
		goto no_obj;
	}
	if ( v1->co ) {
		e_param = "target=1";
		goto exist;
	}
	switch ( net_target[1].name_type ) {
	case 0:
		e_param = "target=2";
		goto undef_target;
	case NMT_PTR:
		v2 = search_vertex_ptr(&ret,1,n2,s);
		if ( v2 )
			printf("WellKnown(target=2) (%lf %lf)\n",
				((NAME_PTR*)v2->name)->x,
				((NAME_PTR*)v2->name)->y);
		break;
	case NMT_STR:
		v2 = search_vertex_str(&ret,1,n2,s);
		printf("WellKnown(target=2) (%s)\n",
			n_string(std_cm,v2->name));
		break;
	default:
		er_panic("xl_WellKnownPoint(2)");
	}
	if ( ret )
		return ret;
	if ( v2 == 0 ) {
		e_param = "target=2";
		goto no_obj;
	}
	if ( v2->co ) {
		e_param = "target=2";
		goto exist;
	}
	v1->co = v2;
	v2->co = v1;
/*
	insert_vertex_list(v1);
*/
	return 0;
no_obj:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_UNDEF_RESOURCE,
		l_string(std_cm,"WellKnownPoint"),
		List(n_get_string("no vertex"),
			n_get_string(e_param),
			-1));
undef_target:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_REQ_PRESET,
		l_string(std_cm,"WellKnownPoint"),
		List(n_get_string("undefined target"),
			n_get_string(e_param),
			-1));
exist:
	return get_error(
		s->h.file,
		s->h.line,		
		XLE_PROTO_INV_OBJECT,
		l_string(std_cm,"WellKnownPoint"),
		List(n_get_string("duplicate correspond"),
			n_get_string(e_param),
			-1));
}


