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

#include "v/VxlEditLine.h"
#include "v/vobj_utils.h"

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

int cmp_xlel_str(L_CHAR * f,char * str);
int get_xlel_flags(
	char ** ret,
	VxlEditLineStatus * sts,
	XL_SEXP * arg,
	XL_SYM_FIELD * sf);
char * setup_xlel_data_from_sexp(VxlEditLineStatus * ests,XL_SEXP * d);
int get_flag_VxlEditLine(L_CHAR * fname);
L_CHAR * l_add_string(L_CHAR *d,char * str);
XL_SEXP * get_VxlEditLineStatus_sexp(VxlEditLineStatus * ests,int flags);
XL_SEXP * vobj_get_VxlEditLine(XLISP_ENV * env,XL_SEXP * arg,XLISP_ENV * a,XL_SYM_FIELD * sf);
XL_SEXP * vobj_VxlEditLine(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);


int
cmp_xlel_str(L_CHAR * f,char * str)
{
int s_len;
	s_len = strlen(str);
	if ( memcmp(f,l_string(std_cm,str),s_len*sizeof(L_CHAR)) )
		return -1;
	switch ( f[s_len] ) {
	case ':':
		return s_len+1;
	case 0:
		return s_len;
	}
	return -1;
}

int
get_xlel_flags(
	char ** ret,
	VxlEditLineStatus * sts,
	XL_SEXP * arg,
	XL_SYM_FIELD * sf)
{
L_CHAR * d;
int flags;
int p;
L_CHAR * pp;
	flags = 0;
	d = get_sf_attribute(sf,l_string(std_cm,"xleditline.Items"));
	if ( d ) {
		sts->items = 0;
		pp = d;
		for ( ; *pp ; ) {
			p = cmp_xlel_str(pp,"edit");
			if ( p > 0 ) {
				sts->items |= VEL_ITEM_EDIT_TEXT;
				pp += p;
				continue;
			}
			p = cmp_xlel_str(pp,"tree");
			if ( p > 0 ) {
				sts->items |= VEL_ITEM_TREE_VIEW;
				pp += p;
				continue;
			}
			p = cmp_xlel_str(pp,"file");
			if ( p > 0 ) {
				sts->items |= VEL_ITEM_FILE_INPUT;
				pp += p;
				continue;
			}
			*ret = "xleditline.Items";
			return 0;
		}
		flags |= VSF_EL_ITEMS;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xleditline.WritingDirection"));
	if ( d ) {
		if ( l_strcmp(d,l_string(std_cm,"H-L2R")) == 0 )
			sts->writing_direction = VSD_H_L2R;
		else if ( l_strcmp(d,l_string(std_cm,"H-R2L")) == 0 )
			sts->writing_direction = VSD_H_R2L;
		else {
			*ret = "xleditline.WritingDirection";
			return 0;
		}
		flags |= VSF_EL_WRITING_DIRECTION;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xleditline.FileConvert"));
	if ( d ) {
		if ( l_strcmp(d,l_string(std_cm,"none")) == 0 )
			sts->writing_direction = VEL_FC_NONE;
		else if ( l_strcmp(d,l_string(std_cm,"url")) == 0 )
			sts->writing_direction = VEL_FC_URL;
		else if ( l_strcmp(d,l_string(std_cm,"dir")) == 0 )
			sts->writing_direction = VEL_FC_DIR;
		else {
			*ret = "xleditline.FileConvert";
			return 0;
		}
		flags |= VSF_EL_FILE_CONVERT;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xleditline.AddDescriptor"));
	if ( d ) {
		sts->add_descriptor = d;
		flags |= VSF_EL_ADD_DESCRIPTOR;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xleditline.DelDescriptor"));
	if ( d ) {
		sts->del_descriptor = d;
		flags |= VSF_EL_DEL_DESCRIPTOR;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xleditline.BroDescriptor"));
	if ( d ) {
		sts->bro_descriptor = d;
		flags |= VSF_EL_BRO_DESCRIPTOR;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xleditline.EditText.MaxLen"));
	if ( d ) {
		sts->max_len = atoi(n_string(std_cm,d));
		flags |= VSF_EL_EDIT_TEXT_MAX_LEN;
	}
	*ret = 0;
	return flags;
}


char *
setup_xlel_data_from_sexp(VxlEditLineStatus * ests,XL_SEXP * d)
{
L_CHAR ** ptr;
XL_SEXP * item;
int len;

	ptr = (L_CHAR**)d_alloc(sizeof(L_CHAR**));
	len = 0;
	for ( ; get_type(d) == XLT_PAIR ; d = cdr(d) ) {
		item = car(d);
		if ( get_type(item) != XLT_STRING )
			return "string is required";
		ptr = (L_CHAR**)d_re_alloc(ptr,sizeof(L_CHAR**)*(len+1));
		ptr[len++] = item->string.data;
	}
	ptr = (L_CHAR**)d_re_alloc(ptr,sizeof(L_CHAR**)*(len+1));
	ptr[len] = 0;
	ests->data = ptr;
	return 0;
}


int
get_flag_VxlEditLine(L_CHAR * fname)
{
#define RET_FLAG(value, ff)  if ( l_strcmp(fname, l_string(std_cm, #value)) == 0 ) return ff
	RET_FLAG(xleditline.Items,VSF_EL_ITEMS);
	RET_FLAG(xleditline.WritingDirection,VSF_EL_WRITING_DIRECTION);
	RET_FLAG(xleditline.FileConvert,VSF_EL_FILE_CONVERT);
	RET_FLAG(xleditline.AddDescriptor,VSF_EL_ADD_DESCRIPTOR);
	RET_FLAG(xleditline.DelDescriptor,VSF_EL_DEL_DESCRIPTOR);
	RET_FLAG(xleditline.BroDescriptor,VSF_EL_BRO_DESCRIPTOR);
	RET_FLAG(xleditline.EditText.MaxLen,VSF_EL_EDIT_TEXT_MAX_LEN);
	RET_FLAG(Arguments,VSF_EL_DATA);
	return 0;
}

char *
get_writing_direction(int dir);


L_CHAR * 
l_add_string(L_CHAR *d,char * str)
{
int len;
int len_str;
L_CHAR * _str;
	len = l_strlen(d);
	_str = l_string(std_cm,str);
	len_str = l_strlen(_str);
	d = (L_CHAR*)d_re_alloc(d,(len + len_str+1)*sizeof(L_CHAR));
	memcpy(&d[len],_str,(len_str+1)*sizeof(L_CHAR));
	return d;
}

XL_SEXP *
get_VxlEditLineStatus_sexp(VxlEditLineStatus * ests,int flags)
{
XL_SEXP * ret;
L_CHAR * d;
char * data;
XL_SEXP * ptr;
int i;
	ret = 0;
	if ( flags & VSF_EL_EDIT_TEXT_MAX_LEN ) {
		ret = cons(
			List(n_get_symbol("xleditline.EditText.MaxLen"),
				get_integer(ests->max_len,0),
				-1),
			ret);
	}
	if ( flags & VSF_EL_BRO_DESCRIPTOR ) {
		ret = cons(
			List(n_get_symbol("xleditline.BroDescriptor"),
				get_string(ests->bro_descriptor),
				-1),
			ret);
	}
	if ( flags & VSF_EL_DEL_DESCRIPTOR ) {
		ret = cons(
			List(n_get_symbol("xleditline.DelDescriptor"),
				get_string(ests->del_descriptor),
				-1),
			ret);
	}
	if ( flags & VSF_EL_ADD_DESCRIPTOR ) {
		ret = cons(
			List(n_get_symbol("xleditline.AddDescriptor"),
				get_string(ests->add_descriptor),
				-1),
			ret);
	}
	if ( flags & VSF_EL_DATA ) {
		ptr = 0;
		for ( i = 0 ; ests->data[i] ; i ++ )
			ptr = cons(get_string(ests->data[i]),ptr);
		ret = cons(
			List(n_get_symbol("Arguments"),reverse(ptr),-1),
			ret);
	}
	if ( flags & VSF_EL_FILE_CONVERT ) {
		switch ( ests->file_convert ) {
		case VEL_FC_NONE:
			data = "none";
			break;
		case VEL_FC_URL:
			data = "url";
			break;
		case VEL_FC_DIR:
			data = "dir";
			break;
		}
		ret = cons(
			List(n_get_symbol("xleditline.FileConvert"),
				n_get_string(data),
				-1),
			ret);
	}
	if ( flags & VSF_EL_WRITING_DIRECTION ) {
		ret = cons(
			List(n_get_symbol("xleditline.WritingDirection"),
				n_get_string(get_writing_direction(
					ests->writing_direction)),
				-1),
			ret);
	}
	if ( flags & VSF_EL_ITEMS ) {
		d = nl_copy_str(std_cm,"");
		if ( ests->items & VEL_ITEM_EDIT_TEXT )
			d = l_add_string(d,"edit");
		if ( ests->items & VEL_ITEM_TREE_VIEW )
			d = l_add_string(d,"tree");
		if ( ests->items & VEL_ITEM_FILE_INPUT )
			d = l_add_string(d,"file");
		ret = cons(
			List(n_get_symbol("xleditline.Items"),
				get_string(d),
				-1),
			ret);
		d_f_ree(d);
	}
	return ret;
}



XL_SEXP *
vobj_get_VxlEditLine(XLISP_ENV * env,XL_SEXP * arg,XLISP_ENV * a,XL_SYM_FIELD * sf)
{
XL_SEXP * ret,* ret2;
VStatusFlagsFromFS vsffs[2];
VxlEditLineStatus xsts;
VObject * obj;
VxlEditLine * eobj;
VExError err;
	vsffs[0].get_flag = get_flag_VxlEditLine;
	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;
	eobj = dynamic_cast<VxlEditLine*>(obj);
	err = eobj->get_xlel_status(&xsts,vsffs[0].flags);
	if ( err.code ) {
		return vobj_get_error(err,arg);
	}
	ret2 = get_VxlEditLineStatus_sexp(&xsts,vsffs[0].flags);
	if ( get_type(ret2) == XLT_ERROR )
		return ret2;
	return append(ret,ret2);
}


XL_SEXP *
vobj_VxlEditLine(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
VExError ex_er;
VObjectStatus sts;
XL_SEXP * _ref;
VxlEditLine * obj;
VxlEditLineStatus ests;
char * param_ret;
VObjectAppStatusAry ar[2];
XL_SEXP * _data;

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

	ar[0].sts = (void*)&ests;
	ar[1].sts = 0;
	ar[1].flags = 0;

	ar[0].flags = get_xlel_flags(&param_ret,&ests,arg,sf);
	if ( param_ret )
		goto param_err;
	ests.data = 0;
	if ( list_length(arg) == 2 ) {
		_data = get_el(arg,1);
		param_ret = setup_xlel_data_from_sexp(&ests,_data);
		if ( param_ret )
			goto param_err;
		ar[0].flags |= VSF_EL_DATA;
	}

	_ref = get_refered_object<VxlEditLine>(&obj,env,arg,sf,VO_XELN,"VxlEditLine",
		&sts,0,(void*)ar);
	if ( get_type(_ref) == XLT_ERROR )
		goto end;

	if ( get_type(_ref) == XLT_INTEGER ) {
		_ref = vobj_get_id_list(_ref->integer.data, 0, sf,OIF_INTERNAL);
	}
	else {
		ex_er = obj->set_xlel_status(&ests,ar[0].flags);
		if ( ex_er.code != V_ER_NO_ERR )
			goto err1;
		_ref = 0;
	}
end:
	if ( ests.data )
		d_f_ree(ests.data);
	return _ref;
	obj->destroy();
err1:
	return vobj_get_error(ex_er, arg);
param_err:
	return get_error(
		arg->h.file,
		arg->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"VxlEditLine"),
		List(n_get_string("invalid param of attribute ::"),
			n_get_string(param_ret),
			-1));
}

void
init_vobj_VxlEditLine(XLISP_ENV *env)
{
	set_env(env,l_string(std_cm,"VxlEditLine"),
		get_func_prim((XL_SEXP*(*)())vobj_VxlEditLine,FO_APPLICATIVE,0,1,2));
}


} // extern "C"
