/**********************************************************************
 
	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	<math.h>
#include	"resource.h"
#include	"memory_debug.h"
#include	"memory_routine.h"
#include	"xlerror.h"

extern SEM res_lock;

void
set_param(RESOURCE * r)
{
int cnt;
MAP_POINT_LIST * p, * p2,*p3;
MAP_PARAMETER * mp_f,* mp_r;
REAL1 r1,r2;

	p = R_NEXT(MAP_POINT_LIST*,&r->map.point_list);
	for ( cnt = 0;
		p != (MAP_POINT_LIST*)&r->map.point_list;
		p = R_NEXT(MAP_POINT_LIST*,&p->h) , cnt ++ );

	mp_f = &r->map.param_forward;
	mp_r = &r->map.param_reverse;
	if ( mp_f->type == MT_TRIANGLE )
		return;
	switch ( cnt ) {
	case 0:
		mp_f->type = 0;
		mp_r->type = 0;
		break;
	case 1:
		p = R_NEXT(MAP_POINT_LIST*,&r->map.point_list);
	move:
		mp_f->type = MT_MOVE;
		mp_f->opt.ptr = p_sub(p->dest,p->src);
		mp_r->type = MT_MOVE;
		mp_r->opt.ptr = p_sub(p->src,p->dest);
		break;
	case 2:
		p = R_NEXT(MAP_POINT_LIST*,&r->map.point_list);
		p2 = R_NEXT(MAP_POINT_LIST*,&p->h);	
	rotate:
		mp_f->type = MT_ROTATE;
		if ( get_rol(&mp_f->opt.affen,
				p->src,p->dest,
				p2->src,p2->dest) < 0 )
			goto move;
		r->map.param_reverse.type = MT_ROTATE;
		if ( get_rol(&mp_r->opt.affen,
				p->dest,p->src,
				p2->dest,p2->src) < 0 )
			goto move;
		r1 = mp_f->opt.affen.matrix[0][0];
		r2 = mp_f->opt.affen.matrix[1][0];
		r->map.param_reverse.resolution_rate
			= sqrt(r1*r1 + r2*r2);
		r->map.param_forward.resolution_rate
			= 1/r->map.param_reverse.resolution_rate;
		break;
	default:
		if ( mp_f->type == MT_TRIANGLE )
			break;
	case 3:
		p = R_NEXT(MAP_POINT_LIST*,&r->map.point_list);
		p2 = R_NEXT(MAP_POINT_LIST*,&p->h);
		p3 = R_NEXT(MAP_POINT_LIST*,&p2->h);
		r->map.param_forward.type = MT_LINEAR;
		if ( get_matrix(&mp_f->opt.affen,
				p->src,p->dest,
				p2->src,p2->dest,
				p3->src,p3->dest) < 0 )
			goto rotate;
		r->map.param_reverse.type = MT_LINEAR;
		if ( get_matrix(&mp_r->opt.affen,
				p->dest,p->src,
				p2->dest,p2->src,
				p3->dest,p3->src) < 0 )
			goto rotate;
		r->map.param_reverse.resolution_rate
			= puseudo_rate(mp_f->opt.affen.matrix);
		r->map.param_forward.resolution_rate
			= 1/r->map.param_reverse.resolution_rate;
		break;
	}
}

int
set_reload(RESOURCE * r)
{
/*
RESOURCE * ret;
MAP * m1;
	for ( ret = R_NEXT(RESOURCE*,&resource_h);
			ret != (RESOURCE*)&resource_h;
			ret = R_NEXT(RESOURCE*,&ret->h.h) )
		if ( ret->h.type == RT_COORDINATE ) {
			for ( m1 = R_NEXT(MAP*,&ret->c.map_children);
				m1 != (MAP*)&ret->c.map_children;
				m1 = R_NEXT(MAP*,&m1->h) ) {
				if ( m1 == 0 )
					goto ok;
				if ( m1->map_file == r )
					goto ok;
		       	}
		}
	return 0;
ok:
*/
	return 0;
}

XL_SEXP *
point_map(XLISP_ENV * e,XL_SEXP * s)
{
XL_SEXP * tag;
XL_SEXP * p1;
XL_SEXP * p2;
XL_SEXP * d;
GB_POINT src,dest;
MAP_POINT_LIST * p;
RESOURCE * r;
XLISP_ENV * ee;
int er;
XL_SEXP * ret;

	r = get_resource_ptr(&ret,e,s->h.file,s->h.line);
	if ( r == 0 )
		return ret;
	tag = eval(e,get_el(s,1));
	switch ( get_type(tag) ) {
	case XLT_ERROR:
		return tag;
	case XLT_STRING:
		break;
	default:
		goto type_missmatch;
	}
	p1 = eval(e,get_el(s,2));
	switch ( get_type(p1) ) {
	case XLT_ERROR:
		return p1;
	case XLT_PAIR:
		if ( list_length(p1) != 2 )
			goto type_missmatch;
		break;
	default:
		goto type_missmatch;
	}
	d = get_el(p1,0);
	switch ( get_type(d) ) {
	case XLT_FLOAT:
		src.x = conv_unit(
			&er,
			r->map.cu_src.uenv,
			d->floating.data,
			d->floating.unit,
			r->map.cu_src.unit);
		break;
	case XLT_INTEGER:
		src.x = conv_unit(
			&er,
			r->map.cu_src.uenv,
			d->integer.data,
			d->integer.unit,
			r->map.cu_src.unit);
		break;
	default:
		goto type_missmatch;
	}
	d = get_el(p1,1);
	switch ( get_type(d) ) {
	case XLT_FLOAT:
		src.y = conv_unit(
			&er,
			r->map.cu_src.uenv,
			d->floating.data,
			d->floating.unit,
			r->map.cu_src.unit);
		break;
	case XLT_INTEGER:
		src.y = conv_unit(
			&er,
			r->map.cu_src.uenv,
			d->integer.data,
			d->integer.unit,
			r->map.cu_src.unit);
		break;
	default:
		goto type_missmatch;
	}
	p2 = eval(e,get_el(s,3));
	switch ( get_type(p2) ) {
	case XLT_ERROR:
		return p2;
	case XLT_PAIR:
		if ( list_length(p2) != 2 )
			goto type_missmatch;
		break;
	default:
		goto type_missmatch;
	}
	d = get_el(p2,0);
	switch ( get_type(d) ) {
	case XLT_FLOAT:
		dest.x = conv_unit(
			&er,
			r->map.cu_dest.uenv,
			d->floating.data,
			d->floating.unit,
			r->map.cu_dest.unit);
		break;
	case XLT_INTEGER:
		dest.x = conv_unit(
			&er,
			r->map.cu_dest.uenv,
			d->integer.data,
			d->integer.unit,
			r->map.cu_dest.unit);
		break;
	default:
		goto type_missmatch;
	}
	d = get_el(p2,1);
	switch ( get_type(d) ) {
	case XLT_FLOAT:
		dest.y = conv_unit(
			&er,
			r->map.cu_dest.uenv,
			d->floating.data,
			d->floating.unit,
			r->map.cu_dest.unit);
		break;
	case XLT_INTEGER:
		dest.y = conv_unit(
			&er,
			r->map.cu_dest.uenv,
			d->integer.data,
			d->integer.unit,
			r->map.cu_dest.unit);
		break;
	default:
		goto type_missmatch;
	}
	p = d_alloc(sizeof(*p));
	p->tag = tag->string.data;
	p->src = src;
	p->dest = dest;
	lock_task(res_lock);
	INSERT_RING(&r->map.point_list,&p->h);
	set_param(r);
	set_reload(r);
	unlock_task(res_lock,"map_point_map");
	return 0;
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"point-map"),
		list(n_get_string("type missmatch"),0));
}

