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

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

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

XL_SEXP * vobj_VPushButton(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);
XL_SEXP * vobj_VCheckBox(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);
XL_SEXP * vobj_VRadioButton(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);
XL_SEXP * vobj_SetRadioGroup(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);
int get_flag_VPopupButton(L_CHAR * fname);
XL_SEXP * vobj_get_VPopupButton(XLISP_ENV * env,XL_SEXP * arg,XLISP_ENV * a,XL_SYM_FIELD * sf);
XL_SEXP * vobj_VPopupButton(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);
XL_SEXP * vobj_SetPopupList(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);


XL_SEXP *
vobj_VPushButton(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
	XL_SEXP * _ref;
	VPushButton * obj;
	VObjectStatus _sts;
	int flags = 0;
	L_CHAR *attr;

	_ref = get_refered_object<VPushButton>
			(&obj,env,arg,sf,VO_PUSH,"VPushButton",&_sts,0,0);
	if  ( get_type(_ref) == XLT_ERROR )
		return _ref;
	
	obj->get_status(&_sts, VSF_ATTR);

	attr = get_sf_attribute(sf, l_string(std_cm, "default_button"));
	if ( attr ) {
		flags = VSF_ATTR;
		if ( atoi(n_string(std_cm, attr)) )
			_sts.attr |= VPushButton::default_button;
		else
			_sts.attr &= ~VPushButton::default_button;
	}

	attr = get_sf_attribute(sf, l_string(std_cm, "cancel_button"));
	if ( attr ) {
		flags = VSF_ATTR;
		if ( atoi(n_string(std_cm, attr)) )
			_sts.attr |= VPushButton::cancel_button;
		else
			_sts.attr &= ~VPushButton::cancel_button;
	}
	
	if ( flags )
		obj->set_status(&_sts, flags);

	switch ( get_type(_ref) ) {
	case XLT_INTEGER:
		return vobj_get_id_list(_ref->integer.data,0,sf,0);
	}
	return 0;
}

XL_SEXP *
vobj_VCheckBox(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
	VCheckBox *obj;
	XL_SEXP *_ref;
	VObjectStatus _sts;
	
	_ref = get_refered_object<VCheckBox>
			(&obj,env,arg,sf,VO_CHKB,"VCheckBox",&_sts,0,0);

	switch ( get_type(_ref) ) {
	case XLT_INTEGER:
		return vobj_get_id_list(_ref->integer.data,0,sf,0);
	case XLT_ERROR:
		return _ref;
	}
	return 0;
}

XL_SEXP *
vobj_VRadioButton(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
XL_SEXP * _ref;
VObjectStatus _sts;
VRadioButton * obj;

	_ref = get_refered_object<VRadioButton>
			(&obj,env,arg,sf,VO_RADB,"VRadioButton",&_sts,0,0);
	if ( get_type(_ref) == XLT_ERROR )
		return _ref;

	L_CHAR *group = get_sf_attribute(sf, l_string(std_cm, "group"));
	if ( group ) {
		XL_SEXP *id = vobj_get_object_by_name(
				eval(env,n_get_symbol("__object_list")),group,arg);
		if ( get_type(id) == XLT_ERROR )
			return id;
		if ( get_type(id) != XLT_INTEGER )
			return vobj_get_error(initial_VExError(V_ER_NOT_FOUND,0,0), arg);
		VRadioButton *btn = dynamic_cast<VRadioButton*>(
				VObject::get_object_by_id(id->integer.data));
		if ( btn == 0 )
			return get_error(
				arg->h.file,
				arg->h.line,
				XLE_PROTO_INV_PARAM,
				l_string(std_cm,"VRadioButton"),
				n_get_string("group object type missmatch"));
		obj->set_radio_group(btn);
	}

	switch ( get_type(_ref) ) {
	case XLT_INTEGER:
		return vobj_get_id_list(_ref->integer.data,0,sf,0);
	}
	return 0;
}

XL_SEXP *
vobj_SetRadioGroup(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
	VRadioButton *btn1 = 0;
	XL_SEXP *t;
	for ( XL_SEXP *s = cdr(arg) ; get_type(s) == XLT_PAIR ; s = cdr(s) ) {
		 t = car(s);
		if ( get_type(t) == XLT_ERROR )
			return t;
		if ( get_type(t) != XLT_INTEGER )
			goto type_missmatch;
		
		VObject *obj = VObject::get_object_by_id(t->integer.data);
		if ( obj == 0 )
			return vobj_get_error(initial_VExError(V_ER_NOT_FOUND,0,0), arg);
		
		VRadioButton *btn = dynamic_cast<VRadioButton*>(obj);
		if ( btn == 0 )
			goto object_type_missmatch;
		
		if ( btn1 == 0 )
			btn1 = btn;
		else
			btn->set_radio_group(btn1);
	};
	return 0;

type_missmatch:
	return get_error(
		arg->h.file,
		arg->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"VRadioButtonSetGroup"),
		n_get_string("type missmatch"));
object_type_missmatch:
	return get_error(
		arg->h.file,
		arg->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"SetRadioGroup"),
		n_get_string("object type missmatch"));
}


int
get_flag_VPopupButton(L_CHAR * fname)
{
#define RET_FLAG(value, ff)  if ( l_strcmp(fname, l_string(std_cm, #value)) == 0 ) return ff
	RET_FLAG(Arguments,1);
	return 0;
}

XL_SEXP *
vobj_get_VPopupButton(XLISP_ENV * env,XL_SEXP * arg,XLISP_ENV * a,XL_SYM_FIELD * sf)
{
XL_SEXP * ret,* ret2;
VStatusFlagsFromFS vsffs[2];
VObject * obj;
L_CHAR ** data_list;
const LC_WRITING_STYLE ** ws_list;
int num;
int i;
VPopupButton * b;
VObjectStatus sts;
	vsffs[0].get_flag = get_flag_VPopupButton;
	vsffs[1].get_flag = 0;
	ret = _vobj_GetStatus(&obj,env,arg,a,sf,vsffs);
	if ( ret == 0 && obj == 0 )
		return ret;
	if ( get_type(ret) == XLT_ERROR || vsffs[0].flags == 0 )
		return ret;
/*
	Get the menu list operation if (vsffs[0].flags & 1) != 0
*/
	ret2 = 0;
	if ( vsffs[0].flags & 1 ) {
		b = dynamic_cast<VPopupButton*>(obj);
		b->get_list(&num,&data_list,&ws_list);
		ret2 = 0;
		if ( ws_list ) {
			for ( i = 0 ; i < num ; i ++ ) {
				if ( ws_list[i] )
					ret2 = cons(
						List(get_string(data_list[i]),
							get_string(ws_list[i]->stylename),
							-1),
						ret2);
				else	ret2 = cons(get_string(data_list[i]),
						ret2);
			}
		}
		else {
			for ( i = 0 ; i < num ; i ++ )
				ret2 = cons(get_string(data_list[i]),ret2);
		}
		obj->get_status(&sts,VSF_VALUE);
		if ( sts.value >= num || sts.value < 0 )
			er_panic("vobj_get_VPopupButton");
		
		ret2 = List(n_get_string("Argumnets"),
				reverse(ret2),
				get_string(data_list[sts.value]),
				-1);
	}

	return append(ret,ret2);
}

XL_SEXP *
vobj_VPopupButton(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
	VPopupButton * obj;

	XL_SEXP * _ref;
	XL_SEXP * item_list, *il, * t;
	int n;
	const L_CHAR ** list_buf;
	const LC_WRITING_STYLE ** ws_buf;
	char buf[30];
	int i;
	VObjectStatus _sts;

	_ref = vobj_get_VPopupButton(env,arg,a,sf);
	if ( get_type(_ref) != 0 )
		return _ref;

	_ref = get_refered_object<VPopupButton>
			(&obj,env,arg,sf,VO_POPB,"VPopupButton",&_sts,0,0);
	if ( get_type(_ref) == XLT_ERROR )
		return _ref;

	if ( list_length(arg) == 2 ) {
		item_list = get_el(arg,1);
		n = list_length(item_list);
		list_buf = new const L_CHAR*[n];
		ws_buf = new const LC_WRITING_STYLE*[n];
		StDisposer<const L_CHAR*> st1(list_buf);
		StDisposer<const LC_WRITING_STYLE*> st2(ws_buf);

		i= 0;
		for ( il = item_list ; get_type(il) == XLT_PAIR ; il = cdr(il) , i ++) {
			t = car(il);
			ws_buf[i] = 0;
			if ( get_type(t) == XLT_PAIR && list_length(t) == 2 ) {
				XL_SEXP *t2 = car(cdr(t));
				if ( get_type(t2) == XLT_STRING )
					ws_buf[i] = get_ws(t2->string.data);
				t = car(t);
			}
			switch ( get_type(t) ) {
			case XLT_ERROR:
				_ref = t;
				n = i;
				goto end;
			case XLT_STRING:
				list_buf[i] = ll_copy_str(t->string.data);
				break;
			case XLT_INTEGER:
				sprintf(buf, I64_FORMAT, t->integer.data);
				list_buf[i] = nl_copy_str(std_cm,buf);
				break;
			case XLT_FLOAT:
				sprintf(buf,"%f",(double)t->integer.data);
				list_buf[i] = nl_copy_str(std_cm,buf);
				break;
			case XLT_NULL:
				list_buf[i] = 0;
				break;
			default:
				_ref = get_error(
					arg->h.file,
					arg->h.line,
					XLE_SEMANTICS_TYPE_MISSMATCH,
					l_string(std_cm,"VRadioButtonSetGroup"),
					n_get_string("type missmatch"));
				n = i;
				goto end;
			}
		}
		obj->set_list(n,list_buf,ws_buf);
	end:
		for ( i = 0; i < n ; i ++ )
			if ( list_buf[i] )
				d_f_ree((void*)list_buf[i]);
	}
	L_CHAR * v = get_sf_attribute(sf,l_string(std_cm,"VALUE"));

	if ( v ) {
	int num;
	L_CHAR ** data_list;
	int vp;
		obj->get_list(&num,&data_list);
		for ( vp = 0 ; vp < num ; vp ++ ) {
			if ( l_strcmp(data_list[vp],v) )
				continue;
			_sts.value = vp;
			obj->set_status(&_sts,VSF_VALUE);
			break;
		}
	}
	switch ( get_type(_ref) ) {
	case XLT_INTEGER:
		return vobj_get_id_list(_ref->integer.data,0,sf,0);
	case XLT_ERROR:
		return _ref;
	}
	return 0;
}


XL_SEXP *
vobj_SetPopupList(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
	int i = 0, n = 0;
	const L_CHAR ** list;
	VObject *obj;
	VPopupButton *btn;
	XL_SEXP *id = get_el(arg, 1), *s_list = get_el(arg, 2), *t, *s;
	
	if ( get_type(id) != XLT_INTEGER )
		goto type_missmatch;
	obj = VObject::get_object_by_id(id->integer.data);
	if ( obj == 0 )
		return vobj_get_error(initial_VExError(V_ER_NOT_FOUND,0,0), arg);
	btn = dynamic_cast<VPopupButton*>(obj);
	if ( btn == 0 )
		goto object_type_missmatch;
	
	for ( s = s_list ; get_type(s) == XLT_PAIR ; s = cdr(s) ) {
		t = car(s);
		if ( get_type(t) == XLT_ERROR )
			return t;
		if ( get_type(t) && get_type(t) != XLT_STRING )
			goto type_missmatch;
		n++;
	}
	if ( get_type(s) )
			goto type_missmatch;
	
	list = new const L_CHAR*[n];
	for ( s = s_list ; get_type(s) == XLT_PAIR ; s = cdr(s) ) {
		t = car(s);
		list[i++] = get_type(t) == XLT_STRING ? t->string.data : 0;
	}
	btn->set_list(n, list);
	delete[] list;
	return 0;

type_missmatch:
	return get_error(
		arg->h.file,
		arg->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"VRadioButtonSetGroup"),
		n_get_string("type missmatch"));
object_type_missmatch:
	return get_error(
		arg->h.file,
		arg->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"SetRadioGroup"),
		n_get_string("object type missmatch"));
}

void
init_VButton(XLISP_ENV *env)
{
	set_env(env,l_string(std_cm,"VPushButton"),
		get_func_prim((XL_SEXP*(*)())vobj_VPushButton,FO_NORMAL,0,1,1));
	set_env(env,l_string(std_cm,"VCheckBox"),
		get_func_prim((XL_SEXP*(*)())vobj_VCheckBox,FO_NORMAL,0,1,1));
	set_env(env,l_string(std_cm,"VRadioButton"),
		get_func_prim((XL_SEXP*(*)())vobj_VRadioButton,FO_NORMAL,0,1,1));
	set_env(env,l_string(std_cm,"VPopupButton"),
		get_func_prim((XL_SEXP*(*)())vobj_VPopupButton,FO_APPLICATIVE,0,1,2));

	set_env(env,l_string(std_cm,"SetRadioGroup"),
		get_func_prim((XL_SEXP*(*)())vobj_SetRadioGroup,FO_APPLICATIVE,0,3,-1));
	set_env(env,l_string(std_cm,"SetPopupList"),
		get_func_prim((XL_SEXP*(*)())vobj_SetPopupList,FO_APPLICATIVE,0,3,3));
}


} // extern "C"
