/**********************************************************************
 
	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomoki SEKIYAMA <sekiyama@yahoo.co.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 <fcntl.h>
#include <stdlib.h>

#include "v/VexDraw.h"
#include "v/vobj_utils.h"
#include "StDisposer.h"

extern "C" {
#include "xl.h"
#include "memory_debug.h"

VImage * get_image_from_sf(XL_SEXP ** retp,XLISP_ENV * env,L_CHAR *,XL_SYM_FIELD * sf);
int sf2v_ex_draw_attr(XL_SYM_FIELD *sf);
XL_SEXP* make_partial_images_from_list(XL_SEXP *q, VImage *img, VImage **imgs, int *n);
XL_SEXP * vobj_VexDraw(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);


int
sf2v_ex_draw_attr(XL_SYM_FIELD *sf)
{

#define SET_IF(cat,value) if ( l_strcmp(lc, l_string(std_cm,#value)) == 0 )	attr |= VexDraw::cat##value

	L_CHAR *lc;
	int attr = 0;

	lc = get_sf_attribute(sf, l_string(std_cm, "mouse_over"));
	if ( lc ) {
		SET_IF(over_, hilight);
		else SET_IF(over_, hilight_b);
		else SET_IF(over_, img_zero);
	}
	
	lc = get_sf_attribute(sf, l_string(std_cm, "mouse_press"));
	if ( lc ) {
		SET_IF(press_, hilight);
		else SET_IF(press_, hilight_b);
		else SET_IF(press_, img_zero);
	}
	
	lc = get_sf_attribute(sf, l_string(std_cm, "mouse_click"));
	if ( lc ) {
		SET_IF(click_, stay);
		else SET_IF(click_, rotate);
		else SET_IF(click_, rotate_zero);
	}
	
	lc = get_sf_attribute(sf, l_string(std_cm, "disabled"));
	if ( lc ) {
		SET_IF(disabled_, ignore);
		else SET_IF(disabled_, hilight);
		else SET_IF(disabled_, img_zero);
	}
	
	return attr;
}

XL_SEXP*
make_partial_images_from_list(XL_SEXP *q, VImage *img, VImage **imgs, int *n)
{
	XL_SEXP *ret = 0;
	int i = *n;
	for ( ; get_type(q) == XLT_PAIR ; q = cdr(q) ) {
		XL_SEXP *pr = car(q);
		if ( get_type(pr) != XLT_PAIR )
			goto type_missmatch;
		pr = car(pr);
		if ( get_type(pr) != XLT_SYMBOL ||
				l_strcmp(pr->symbol.data, l_string(std_cm,"Area")) ) {
			ret = get_error(
				pr->h.file,
				pr->h.line,
				XLE_SEMANTICS_TYPE_MISSMATCH,
				l_string(std_cm, "VImage"),
				n_get_string("Area is expected"));
			break;
		}

		short x, y, w, h;
		L_CHAR *lx, *ly, *lw, *lh;
		lx = get_symbol_field(pr, l_string(std_cm,"x"));
		ly = get_symbol_field(pr, l_string(std_cm,"y"));
		lw = get_symbol_field(pr, l_string(std_cm,"w"));
		lh = get_symbol_field(pr, l_string(std_cm,"h"));
		if ( ! lx || ! ly || ! lw || ! lh ) {
			ret = get_error(
				pr->h.file,
				pr->h.line,
				XLE_PROTO_INV_PARAM,
				l_string(std_cm, "Area"),
				n_get_string("x/y/w/h is not specified"));
			break;
		}
		x = atoi(n_string(std_cm,lx));
		y = atoi(n_string(std_cm,ly));
		w = atoi(n_string(std_cm,lw));
		h = atoi(n_string(std_cm,lh));
		
		VRect r = {x,y,x+w,y+h};
		VImage *imgp = v_image_partial(img, &r);
		if ( imgp )
			imgs[i++] = imgp;
		else {
			ret = get_error(
				pr->h.file,
				pr->h.line,
				XLE_PROTO_INV_PARAM,
				l_string(std_cm, "Area"),
				n_get_string("x/y/w/h out of range"));
			break;
		}
			
	}
	
	if ( ret )
		for ( int k = 0 ; k < i ; k++ )
			v_image_unref(imgs[k]);
	else
		*n = i;
	return ret;
type_missmatch:
	return get_error(
		q->h.file,
		q->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm, "VexDraw"),
		n_get_string("type missmatch"));
}

XL_SEXP *
vobj_VexDraw(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
XL_SEXP *_ref, *img_ret, *ret = 0;
VObjectStatus sts;
VImage * img;
VImage **imgs = 0;
int flags = 0;
int num = 0, i = 0;
XL_SEXP * p;
VexDraw *obj;
L_CHAR *use_alpha;

	sts.attr = sf2v_ex_draw_attr(sf);
	use_alpha = get_sf_attribute(sf, l_string(std_cm, "use_alpha"));
	if ( use_alpha && atoi(n_string(std_cm, use_alpha)) )
		sts.attr |= VDraw::use_alpha;
	flags = VSF_ATTR;

	img = get_image_from_sf(&img_ret,env,arg->h.file->name,sf);
	if ( img ) {
		sts.min_size = sts.size = img->size;
		flags |= VSF_SIZE|VSF_MIN_SIZE;
	}

	_ref = get_refered_object<VexDraw>
			(&obj,env,arg,sf,VO_EDRW,"VexDraw",&sts,flags,0);
	if  ( get_type(_ref) == XLT_ERROR ) {
		ret = _ref;
		goto err1;
	}


	if ( img )
		if ( obj->set_image(img) != V_ER_NO_ERR )
			er_panic("1");

	// count imgs
	for ( p = cdr(arg) ; get_type(p) == XLT_PAIR ; p = cdr(p) ) {
		if ( get_type(car(p)) != XLT_PAIR )
			goto type_missmatch;
		int k = list_length(car(p));
		if ( k < 0 )
			goto type_missmatch;
		num += k == 0 ? 1 : k;
	}
	if ( get_type(p) )
		goto type_missmatch;
	
	if ( num > 0 ) {
		imgs = new VImage*[num];

		for ( p = cdr(arg) ; get_type(p) == XLT_PAIR ; p = cdr(p) ) {
			XL_SEXP *im = car(car(p));
			if ( get_type(im) != XLT_SYMBOL ||
					l_strcmp(im->symbol.data, l_string(std_cm,"VImage")) ) {
				ret = get_error(
					arg->h.file,
					arg->h.line,
					XLE_SEMANTICS_TYPE_MISSMATCH,
					l_string(std_cm, "VexDraw"),
					n_get_string("VImage is expected"));
				goto err2;
			}
			
			VImage *img0 = get_image_from_sf(&ret,env,arg->h.file->name,im->symbol.field);
			if ( img0 == 0 ) {
				ret = vobj_get_error(initial_VExError(V_ER_PARAM,0,0), arg);
				goto err2;
			}

			XL_SEXP *q = cdr(car(p));
			if ( get_type(q) == XLT_PAIR ) {
				ret = make_partial_images_from_list(q, img0, imgs, &i);
				if ( ret ) {
					v_image_unref(img0);	// the other imgs unref'ed in make_partial...()
					goto err2;
				}
				v_image_unref(img0);
			}
			else
				imgs[i++] = img0;
			
			if ( i > num )
				er_panic("vobj_VexDraw");
		}

		if ( img ) {
			obj->set_images(i, imgs);
			obj->set_image(img);
		}
		else
			obj->set_images(i, imgs, imgs[0]->size);
		while ( --i >= 0 )
			v_image_unref(imgs[i]);
		delete imgs;
	}
	
	return vobj_get_id_list(sts.id, 0, sf,0);

type_missmatch:
	ret = get_error(
		arg->h.file,
		arg->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm, "VexDraw"),
		n_get_string("type missmatch"));
err2:
	obj->destroy();
	if ( imgs ) {
		while ( --i >= 0 )
			v_image_unref(imgs[i]);
		delete imgs;
	}
err1:
	if ( img )
		v_image_unref(img);
	if ( ret == 0 )
		return vobj_get_error(initial_VExError(V_ER_PARAM,0,0),arg);
	else	return ret;

}

void
init_VexDraw(XLISP_ENV *env)
{
	set_env(env,l_string(std_cm,"VexDraw"),
		get_func_prim((XL_SEXP*(*)())vobj_VexDraw,FO_NORMAL,0,1,-1));
}


} // extern "C"
