/**********************************************************************
 
	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.

**********************************************************************/



#ifndef ___VOBJ_UTILS_H___
#define ___VOBJ_UTILS_H___

#include "v/v_types.h"
#include "v/v_errors.h"

#ifdef __cplusplus
extern "C" {
#endif

#include "xl.h"
#include "xlerror.h"
#include "machine/include.h"

extern XLISP_ENV *	vobj_env;

XL_SEXP * vobj_get_object_by_name(XL_SEXP *s, L_CHAR *name, XL_SEXP *arg);
VObject * get_object_from_name(XLISP_ENV * env,L_CHAR * name);

V_CALLBACK_D(vobj_callback_glue);
typedef struct VSysArgTranslator {
	L_CHAR	sig;	// always 0;
	L_CHAR	*func;
	XL_SEXP*(*translator)(VObject*, void*);
	XLISP_ENV *	env;
	struct VSysArgTranslator *	next;
} VSysArgTranslator;

typedef struct VStatusFlagsFromFS {
	int			flags;
	int			(*get_flag)(L_CHAR *);
} VStatusFlagsFromFS;

void insert_vsat_list(VSysArgTranslator * vsat);
void delete_vsat_list(VSysArgTranslator * vsat);
VSysArgTranslator * get_vsat(XLISP_ENV * arg_env,L_CHAR * v);


unsigned char	vobj_get_align_by_name(L_CHAR *attr);		// VALIGN_xxx --> L_CHAR
L_CHAR * vobj_get_align_name(unsigned align, bool vert_flag);	// VALIGN_xxx <-- L_CHAR
int vobj_sts_flag_by_name(L_CHAR *flag);			// VSF_xxx <-- L_CHAR
int vobj_status_flag_from_fs(XL_SEXP *arg, XL_SYM_FIELD *sf, int *out_flags,
		VStatusFlagsFromFS *);	// VSF_xxx <-- SYM_FIELD
XL_SEXP * vobj_get_error(VExError err, XL_SEXP *arg);		// V_ER_xxx --> XL_SEXP
char v_modkey_by_name(L_CHAR *lname);		// V_MODKEY_XXX <-- L_CHAR

XL_SEXP * vobj_get_children_list(VObjectList *list);		// VObjectList --> XL_SEXP
XL_SEXP * vobj_get_status_list(VObjectStatus *s, int flags);	// VObjectStatus --> XL_SEXP
#ifdef __cplusplus
int get_sts_from_sf(XLISP_ENV * a,VObjectStatus *s,int flags, XL_SYM_FIELD *sf, VObject::FreeList **free_list);	// VObjectStatus <-- SYM_FIELD
XL_SEXP *
_vobj_GetStatus(VObject ** po,XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf,
		VStatusFlagsFromFS * vsffs);
#endif

void vobj_delete_children(XLISP_ENV * env,VObject * obj);
XL_SEXP *	vobj_eval_child(int parent, XLISP_ENV *env, XL_SEXP *arg);
XL_SEXP *	vobj_get_id_list(int id, XL_SEXP *children, XL_SYM_FIELD *sf,
			int flags);
// flags define
#define OIF_INTERNAL	0x00000001

#ifdef __cplusplus

// =================================================
//   reference mechanism of already created object
// =================================================

VRect get_elr(char*,VImage*);
char * get_num(int*,char*);
void get_elr_ary(VRect * elr,char * data,VImage * img);


int
get_default_sts_from_symbol(XLISP_ENV * env,VObjectStatus * sts,
	VObject::FreeList ** fl);
void
get_sf_v(L_CHAR** env,L_CHAR** func,L_CHAR * v);
void
free_VSysArgTranslator(int type,void * ptr);
VSysArgTranslator * copy_vsat(VSysArgTranslator * vsat);




} // extern "C"

template <class V> static XL_SEXP *
get_refered_object (V** ret_obj,XLISP_ENV * env,
	XL_SEXP * arg,XL_SYM_FIELD * sf,
	int gtype,
	char * objectname,
	VObjectStatus * sts_ptr,
	int		sts_flags,
	void * create_arg)
{
L_CHAR * refer,* refer_id;
XL_SEXP * p, * ret;
V* obj;
VObject::FreeList *free_list;
int flags;
VExError ex_er;
VObject * parent;
VObject * v;

	flags = get_default_sts_from_symbol(env,sts_ptr,&free_list);
	flags = get_sts_from_sf(env,sts_ptr,flags, sf, &free_list)|sts_flags;
	refer = get_sf_attribute(sf,l_string(std_cm,"refer"));
	refer_id = get_sf_attribute(sf,l_string(std_cm,"refer.id"));
	if ( refer || refer_id ) {
		if ( refer ) {
			p = eval(env,n_get_symbol("__object_list"));
			if ( get_type(p) == XLT_ERROR )
				return p;
			p = vobj_get_object_by_name(p,refer,arg);
			switch ( get_type(p) ) {
			case XLT_ERROR:
				return p;
			case XLT_INTEGER:
				break;
			default:
				er_panic("get_refered_object");
			}
			v = VObject::get_object_by_id(p->integer.data);
		}
		else {
			v = VObject::get_object_by_id(atoi(
				n_string(std_cm,refer_id)));
		}
		obj = dynamic_cast<V*>(v);
		if ( obj == 0 ) {
			return get_error(
				arg->h.file,
				arg->h.line,
				XLE_PROTO_INV_OBJECT,
				l_string(std_cm,objectname),
				List(n_get_string("invalid referenced object (refer) obj_type ="),
					get_integer(v->get_type(),0),
					-1));
		}
		ex_er = obj->set_status(sts_ptr,flags);
		if ( ex_er.code != V_ER_NO_ERR )
			goto err1;
		ret = get_string(refer);
	}
	else {
		if ( gtype != VO_WIND ) {
			p = eval(env, n_get_symbol("__parent"));
			if ( get_type(p) == XLT_ERROR )
				return p;
			if ( get_type(p) != XLT_INTEGER )
				return vobj_get_error(
					initial_VExError(V_ER_PARENT,0,0), arg);
			parent = VObject::get_object_by_id(p->integer.data);
			
			sts_ptr->parent = parent;
			flags |= VSF_PARENT;
		}
		
		obj = V::create(sts_ptr, flags, create_arg,&ex_er);
		if ( ex_er.code != V_ER_NO_ERR )
			goto err1;
		obj->get_status(sts_ptr, VSF_ID);
		ret = get_integer(sts_ptr->id,0);
	}
	obj->free_on_release_list(free_list);
	*ret_obj = obj;
	return ret;
err1:
	if ( obj )
		obj->destroy();
	return vobj_get_error(ex_er, arg);
}


template <class V> static XL_SEXP *
get_refered_object_int_lc_list (V** ret_obj,XLISP_ENV * env,
	XL_SEXP * arg,XL_SYM_FIELD * sf,
	unsigned int gtype,
	char * objectname,
	const int n,
	const L_CHAR ** lc_list)
{
L_CHAR * refer;
XL_SEXP * p, * ret;
V* obj;
VObjectStatus sts;
VObject::FreeList *free_list;
int flags;
VExError ex_er;
VObject * parent;

	flags = get_default_sts_from_symbol(env,&sts,&free_list);
	flags = get_sts_from_sf(env,&sts,flags , sf, &free_list);
	refer = get_sf_attribute(sf,l_string(std_cm,"refer"));
	if ( refer ) {
		p = eval(env,n_get_symbol("__object_list"));
		if ( get_type(p) == XLT_ERROR )
			return p;
		p = vobj_get_object_by_name(p,refer,arg);
		switch ( get_type(p) ) {
		case XLT_ERROR:
			return p;
		case XLT_INTEGER:
			break;
		default:
			er_panic("get_refered_object");
		}
		obj = (V*)VObject::get_object_by_id(p->integer.data);
		if ( obj->get_type() != gtype ) {
			return get_error(
				arg->h.file,
				arg->h.line,
				XLE_PROTO_INV_OBJECT,
				l_string(std_cm,objectname),
				List(n_get_string("invalid referenced object (refer) obj_type ="),
					get_integer(obj->get_type(),0),
					-1));
		}
		ex_er = obj->set_status(&sts,flags);
		if ( ex_er.code != V_ER_NO_ERR )
			goto err1;
		ret = get_string(refer);
	}
	else {
		p = eval(env, n_get_symbol("__parent"));
		if ( get_type(p) == XLT_ERROR )
			return p;
		if ( get_type(p) != XLT_INTEGER )
			return vobj_get_error(initial_VExError(V_ER_PARENT,0,0), arg);
		parent = VObject::get_object_by_id(p->integer.data);
		
		sts.parent = parent;
		flags |= VSF_PARENT;
		
		obj = V::create(&sts, flags,n,lc_list, &ex_er);
		if ( ex_er.code != V_ER_NO_ERR )
			goto err1;
		obj->get_status(&sts, VSF_ID);
		ret = get_integer(sts.id,0);
	}
	obj->free_on_release_list(free_list);
	*ret_obj = obj;
	return ret;
err1:
	obj->destroy();
	return vobj_get_error(ex_er, arg);
}

#endif

#endif // ___VOBJ_UTILS_H___

