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

extern "C" {

#include	"memory_debug.h"
#include	"long_char.h"

} // extern "C"


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


void default_VxlEditLineStatus(VxlEditLineStatus * s);
void copy_EditLineStatus(
	VxlEditLineStatus * dest,
	VxlEditLineStatus * src,
	int flags,int clear_flag);
void clear_tree_view_data(OBJ_ARG * oa);
void set_tree_view_data(OBJ_ARG * oa,L_CHAR ** data);
VTreeView * create_tree_view(OBJ_ARG * oa,VObjectStatus * sts,int flags,VxlEditLineStatus * ests,
		VExError * err);
V_CALLBACK_D(add_btn_handler);
V_CALLBACK_D(del_btn_handler);
V_CALLBACK_D(bro_btn_handler);
void set_object_handler(VObject* obj,OBJ_ARG * oa);


void
VxlEditLine::redraw(VRect * rect) const
{
}


void
default_VxlEditLineStatus(VxlEditLineStatus * s)
{
	s->items = VEL_ITEM_EDIT_TEXT|VEL_ITEM_TREE_VIEW;
	s->writing_direction = VSD_V_L2R;
	s->file_convert = VEL_FC_NONE;
	s->data = 0;
	s->add_descriptor = nl_copy_str(std_cm,"Add");
	s->del_descriptor = nl_copy_str(std_cm,"Delete");
	s->bro_descriptor = nl_copy_str(std_cm,"Browse");
	s->tree_view_title = nl_copy_str(std_cm,"Data");
	s->max_len = 300;
	s->min_len = 20;
	s->col_len = 300;
}

extern "C" void
free_el_data(L_CHAR ** data)
{
int i;
	for ( i = 0; data[i] ; i ++ )
		d_f_ree(data[i]);
	d_f_ree(data);
}

extern "C" L_CHAR **
copy_el_data(L_CHAR ** data)
{
L_CHAR ** ret;
int len;
int i;
	for ( len = 0 ; data[len] ; len ++ );
	ret = (L_CHAR**)d_alloc(sizeof(L_CHAR*)*(len+1));
	ret[len] = 0;
	for ( i = 0 ; i <= len ; i ++ )
		ret[i] = ll_copy_str(data[i]);
	return ret;
}

void
copy_EditLineStatus(
	VxlEditLineStatus * dest,
	VxlEditLineStatus * src,
	int flags,int clear_flag)
{
	if ( VSF_EL_ITEMS & flags )
		dest->items = src->items;
	if ( VSF_EL_WRITING_DIRECTION & flags )
		dest->writing_direction = src->writing_direction;
	if ( VSF_EL_FILE_CONVERT & flags )
		dest->file_convert = src->file_convert;
	if ( VSF_EL_DATA & flags ) {
		if ( clear_flag && dest->data )
			free_el_data(dest->data);
		dest->data = copy_el_data(src->data);
	}
	if ( VSF_EL_ADD_DESCRIPTOR & flags ) {
		if ( clear_flag && dest->add_descriptor )
			d_f_ree(dest->add_descriptor);
		dest->add_descriptor = ll_copy_str(src->add_descriptor);
	}
	if ( VSF_EL_DEL_DESCRIPTOR & flags ) {
		if ( clear_flag && dest->del_descriptor )
			d_f_ree(dest->del_descriptor);
		dest->del_descriptor = ll_copy_str(src->del_descriptor);
	}
	if ( VSF_EL_BRO_DESCRIPTOR & flags ) {
		if ( clear_flag && dest->bro_descriptor )
			d_f_ree(dest->bro_descriptor);
		dest->bro_descriptor = ll_copy_str(src->bro_descriptor);
	}
	if ( VSF_EL_EDIT_TEXT_MAX_LEN & flags )
		dest->max_len = src->max_len;
	if ( VSF_EL_EDIT_TEXT_MIN_LEN & flags )
		dest->min_len = src->min_len;
	if ( VSF_EL_EDIT_TEXT_COL_LEN & flags )
		dest->col_len = src->col_len;
}

void
clear_tree_view_data(OBJ_ARG * oa)
{
VTreeView * tv;
int key;
	tv = oa->tree_view;
	for ( key = 0 ; key < oa->max_node_key ; key ++ )
		tv->remove_row((void*)key);
}

void
set_tree_view_data(OBJ_ARG * oa,L_CHAR ** data)
{
int key;
VTreeView * tv;
	tv = oa->tree_view;
	for ( key = 0 ; data[key] ; key ++ ) {
	VTreeNode node(tv->get_n_cols());
		node.editable = 1;
		node.key = (void*)key;
		node.data[0] = data[key];
		tv->add_row(&node,0,0);
	}
	oa->max_node_key = key;
}

VTreeView *
create_tree_view(OBJ_ARG * oa,VObjectStatus * sts,int flags,VxlEditLineStatus * ests,
		VExError * err)
{
VTreeView * ret;
L_CHAR * titles[1];
char types[1];
short widths[1];
//#define CHECK_BOX_SIZE	30
//	titles[0] = ests->del_descriptor;
//	widths[0] = CHECK_BOX_SIZE;
//	types[0] = VTT_BOOL|VTT_EDITABLE;
	titles[0] = ests->tree_view_title;
	widths[0] = ests->col_len;
	types[0] = VTT_TEXT;
	if ( (flags & VSF_MIN_SIZE) == 0 ) {
		sts->min_size.w = ests->col_len;// + CHECK_BOX_SIZE;
		sts->min_size.h = 40;
		flags |= VSF_MIN_SIZE;
	}
	if ( (flags & VSF_ATTR) == 0 )
		sts->attr =
			VTreeView::scrollbar_v
			//|VTreeView::scrollbar_h
			|VTreeView::select_multi;
	flags |= VSF_ATTR;
	ret = VTreeView::create(
		sts, flags, 
		1, 
		(char*)types, 
		(const L_CHAR**)titles, 
		(short*)widths,
		err);
	oa->tree_view = ret;
	set_tree_view_data(oa,ests->data);
	return ret;		
}

void
VxlEditLine::_push_add_btn()
{
VEditText * et;
VTreeView * tv;
VExError err;
VObjectStatus ss;
VTreeNode node(1);
	if ( lock_d(__FILE__,__LINE__) )
		return;
	if ( (et = _obj_arg.edit_text) == 0 )
		goto end;
	err = et->get_status(&ss,VSF_DESC);
	if ( err.code != V_ER_NO_ERR )
		goto end;
	tv = _obj_arg.tree_view;
	if ( tv == 0 )
		goto end;
	node.editable = 1;
	node.key = (void*)(_obj_arg.max_node_key++);
	node.data[0] = ss.descriptor;
	tv->add_row(&node,0,0);
end:
	unlock(this);
}

V_CALLBACK_D(add_btn_handler)
{
VxlEditLine * obj;
	obj = (VxlEditLine*)user_arg;
	obj->_push_add_btn();
}

void
VxlEditLine::_push_del_btn()
{
VTreeView * tv;
	if ( lock_d(__FILE__,__LINE__) )
		return;
	tv = _obj_arg.tree_view;
	VTreeView::Selection *sel = tv->get_selection();
	for ( int n = 0 ; n < sel->n ; n++ ) {
		tv->remove_row(sel->keys[n]);
	}
	unlock(this);
}

V_CALLBACK_D(del_btn_handler)
{
VxlEditLine * obj;
	obj = (VxlEditLine*)user_arg;
	obj->_push_del_btn();
}


void
VxlEditLine::_push_bro_btn(char * ret)
{
VObjectStatus _sts;
VEditText * et;
	et = _obj_arg.edit_text;
	if ( et == 0 )
		return;
	_sts.descriptor = nl_copy_str(std_cm,ret);
	et->set_status(&_sts,VSF_DESC);
	d_f_ree((void*)_sts.descriptor);
}

V_CALLBACK_D(bro_btn_handler)
{
VxlEditLine * obj;
char  *ret;
	ret = v_choose_file(l_string(std_cm,"FileSelection"),0);
	if ( ret ) {
		obj = (VxlEditLine*)user_arg;
		obj->_push_bro_btn(ret);
		d_f_ree(ret);
	}
	return;
}


void
set_object_handler(VObject* obj,OBJ_ARG * oa)
{
VObjectStatus ss;
	if ( oa->add_btn ) {
		ss.value_event_handler = add_btn_handler;
		ss.value_eh_arg = (void*)obj;
		oa->add_btn->set_status(&ss,VSF_VALUE_EH);
	}
	if ( oa->del_btn ) {
		ss.value_event_handler = del_btn_handler;
		ss.value_eh_arg = (void*)obj;
		oa->del_btn->set_status(&ss,VSF_VALUE_EH);
	}
	if ( oa->bro_btn ) {
		ss.value_event_handler = bro_btn_handler;
		ss.value_eh_arg = (void*)obj;
		oa->bro_btn->set_status(&ss,VSF_VALUE_EH);
	}
}

VExError
VxlEditLine::create_do(const VObjectStatus* s, int flags,VObject * nmp, void * arg)
{
VExError err;
VObjectAppStatusAry * app;
int ss_flags;
VObjectStatus s_sts;
VHAlignView * text_edit_line,* del_line;
VVAlignView * whole, *add_grue;
#define VSF_EL_INVALID_FLAGS	(~(VSF_MIN_SIZE))

	info = 0;

	default_VxlEditLineStatus(&e_sts);

	if ( arg ) {
		app = (VObjectAppStatusAry*)arg;
		ss_flags = app[0].flags;
		copy_EditLineStatus(&e_sts,
			(VxlEditLineStatus*)app[0].sts,ss_flags,1);
	}
	memset(&_obj_arg,0,sizeof(_obj_arg));
	copy_vobject_status(&s_sts,(VObjectStatus*)s,flags);
	s_sts.parent = this;
	switch ( e_sts.items ) {
	case 0:
		return initial_VExError(V_ER_NOT_SUPPORT,0,0);
	case VEL_ITEM_EDIT_TEXT:
		if ( e_sts.data[0] )
			s_sts.descriptor = e_sts.data[0];
		else	s_sts.descriptor = 0;
		_obj_arg.edit_text = VEditText::create(
			(const VObjectStatus*)&s_sts,flags|VSF_PARENT
					|VSF_DESC,
				e_sts.max_len,e_sts.min_len,&err);
		return initial_VExError(V_ER_NO_ERR,0,0);
	case VEL_ITEM_TREE_VIEW:
		return initial_VExError(V_ER_INVALID_MODE,0,0);
	case VEL_ITEM_FILE_INPUT:
		return initial_VExError(V_ER_NOT_SUPPORT,0,0);
	case VEL_ITEM_EDIT_TEXT|VEL_ITEM_TREE_VIEW:
		whole = VVAlignView::create(&s_sts,flags|VSF_PARENT);
		s_sts.parent = whole;
		s_sts.alignv = VALIGN_TOP;
		s_sts.alignh = VALIGN_EXPAND;
		text_edit_line = VHAlignView::create(
					&s_sts,
					(flags|VSF_PARENT|VSF_ALIGN)&
					VSF_EL_INVALID_FLAGS);
		s_sts.parent = text_edit_line;
		s_sts.alignv = VALIGN_FILL;
		s_sts.alignh = VALIGN_FILL;
		if ( s_sts.descriptor )
			d_f_ree((void*)s_sts.descriptor);
		switch ( e_sts.writing_direction ) {
		case VSD_H_L2R:
			s_sts.descriptor = s->descriptor;
			s_sts.alignh = VALIGN_FILL;
			_obj_arg.edit_text = VEditText::create(
					&s_sts,
					(flags|VSF_PARENT|VSF_ALIGN)&
					VSF_EL_INVALID_FLAGS,
					e_sts.max_len,e_sts.min_len,&err);
			s_sts.alignh = VALIGN_RIGHT;
			add_grue = VVAlignView::create(
					&s_sts,VSF_PARENT|VSF_ALIGN);
			s_sts.alignh = VALIGN_RIGHT;
			s_sts.parent = add_grue;
			s_sts.descriptor = e_sts.add_descriptor;
			_obj_arg.add_btn = VPushButton::create(
					&s_sts,
					(flags|VSF_PARENT|
						VSF_ALIGN|VSF_DESC)&
					VSF_EL_INVALID_FLAGS);
			break;
		case VSD_H_R2L:
			s_sts.descriptor = e_sts.add_descriptor;
			s_sts.alignv = VALIGN_LEFT;
			add_grue = VVAlignView::create(
					&s_sts,VSF_PARENT|VSF_ALIGN);
			s_sts.parent = add_grue;
			s_sts.alignv = VALIGN_LEFT;
			_obj_arg.add_btn = VPushButton::create(
					&s_sts,
					(flags|VSF_PARENT|
						VSF_ALIGN|VSF_DESC)&
					VSF_EL_INVALID_FLAGS);
			s_sts.alignh = VALIGN_FILL;
			s_sts.descriptor = s->descriptor;
			_obj_arg.edit_text = VEditText::create(
					&s_sts,
					(flags|VSF_PARENT|VSF_ALIGN)&
					VSF_EL_INVALID_FLAGS,
					e_sts.max_len,e_sts.min_len,&err);
			break;
		default:
			return initial_VExError(V_ER_NOT_SUPPORT,0,0);
		}
		s_sts.parent = whole;
		_obj_arg.tree_view = create_tree_view(
					&_obj_arg,
					&s_sts,
					(flags|VSF_PARENT),
					&e_sts,&err);

		s_sts.alignv = VALIGN_FILL;
		s_sts.alignh = VALIGN_FILL;
		del_line = VHAlignView::create(
					&s_sts,
					(flags|VSF_PARENT|VSF_ALIGN)&
					VSF_EL_INVALID_FLAGS);
		s_sts.parent = del_line;
		switch ( e_sts.writing_direction ) {
		case VSD_H_R2L:
			s_sts.alignh = VALIGN_LEFT;
			break;
		default:
			s_sts.alignh = VALIGN_RIGHT;
			break;
		}
		s_sts.alignv = VALIGN_BOTTOM;
		s_sts.descriptor = e_sts.del_descriptor;
		_obj_arg.del_btn = VPushButton::create(
				&s_sts,
				(flags|VSF_PARENT|
					VSF_ALIGN|VSF_DESC)&
				VSF_EL_INVALID_FLAGS);
		set_object_handler(this,&_obj_arg);
		return initial_VExError(V_ER_NO_ERR,0,0);
	case VEL_ITEM_EDIT_TEXT|VEL_ITEM_FILE_INPUT:
		whole = VVAlignView::create(&s_sts,flags|VSF_PARENT);
		s_sts.parent = whole;
		s_sts.alignv = VALIGN_TOP;
		s_sts.alignh = VALIGN_EXPAND;
		text_edit_line = VHAlignView::create(
					&s_sts,
					(flags|VSF_PARENT|VSF_ALIGN)&
					VSF_EL_INVALID_FLAGS);
		s_sts.parent = text_edit_line;
		s_sts.alignv = VALIGN_FILL;
		s_sts.alignh = VALIGN_FILL;
		if ( s_sts.descriptor )
			d_f_ree((void*)s_sts.descriptor);
		switch ( e_sts.writing_direction ) {
		case VSD_H_L2R:
			s_sts.descriptor = s->descriptor;
			s_sts.alignh = VALIGN_FILL;
			_obj_arg.edit_text = VEditText::create(
					&s_sts,
					(flags|VSF_PARENT|VSF_ALIGN)&
					VSF_EL_INVALID_FLAGS,
					e_sts.max_len,e_sts.min_len,&err);
			s_sts.alignh = VALIGN_RIGHT;
			add_grue = VVAlignView::create(
					&s_sts,VSF_PARENT|VSF_ALIGN);
			s_sts.parent = add_grue;
			s_sts.alignh = VALIGN_RIGHT;
			s_sts.descriptor = e_sts.bro_descriptor;
			_obj_arg.bro_btn = VPushButton::create(
					&s_sts,
					(flags|VSF_PARENT|
						VSF_ALIGN|VSF_DESC)&
					VSF_EL_INVALID_FLAGS);
			break;
		case VSD_H_R2L:
			s_sts.descriptor = e_sts.bro_descriptor;
			s_sts.alignv = VALIGN_LEFT;
			add_grue = VVAlignView::create(
					&s_sts,VSF_PARENT|VSF_ALIGN);
			s_sts.parent = add_grue;
			s_sts.alignh = VALIGN_LEFT;
			_obj_arg.bro_btn = VPushButton::create(
					&s_sts,
					(flags|VSF_PARENT|
						VSF_ALIGN|VSF_DESC)&
					VSF_EL_INVALID_FLAGS);
			s_sts.alignh = VALIGN_FILL;
			s_sts.descriptor = s->descriptor;
			_obj_arg.edit_text = VEditText::create(
					&s_sts,
					(flags|VSF_PARENT|VSF_ALIGN)&
					VSF_EL_INVALID_FLAGS,
					e_sts.max_len,e_sts.min_len,&err);
			break;
		default:
			return initial_VExError(V_ER_NOT_SUPPORT,0,0);
		}
		set_object_handler(this,&_obj_arg);
		return initial_VExError(V_ER_NO_ERR,0,0);
	case VEL_ITEM_TREE_VIEW|VEL_ITEM_FILE_INPUT:
		return initial_VExError(V_ER_NOT_SUPPORT,0,0);
	case VEL_ITEM_EDIT_TEXT|VEL_ITEM_TREE_VIEW|VEL_ITEM_FILE_INPUT:
		return initial_VExError(V_ER_NOT_SUPPORT,0,0);
	default:
		return initial_VExError(V_ER_NOT_SUPPORT,0,0);
	}
}



void
VxlEditLine::destroy_do(VObject * nmp)
{
	if ( e_sts.data )
		free_el_data(e_sts.data);
	d_f_ree(e_sts.tree_view_title);
	d_f_ree(e_sts.add_descriptor);
	d_f_ree(e_sts.del_descriptor);
	d_f_ree(e_sts.bro_descriptor);
	memset(&_obj_arg,0,sizeof(_obj_arg));
}

void
VxlEditLine::destroy_do_out_of_lock(VObject * nmp)
{
}


VExError
VxlEditLine::set_status(const VObjectStatus * s,int flags)
{
	return VMacro::set_status(s, flags);
}

VxlEditLine::~VxlEditLine()
{
}


VExError
VxlEditLine::set_xlel_status(const VxlEditLineStatus * ests,int flags)
{
VExError err;
VObjectStatus ss;
#define VSF_EL_INVALID_SET	(VSF_EL_ITEMS|VSF_EL_WRITING_DIRECTION)
	VM_OP_START_EX
	err = initial_VExError(V_ER_NO_ERR,flags,0);
	copy_EditLineStatus((VxlEditLineStatus*)&e_sts,
		(VxlEditLineStatus*)ests,flags&(~VSF_EL_INVALID_SET),1);
	if ( (flags & VSF_EL_DATA) ) {
		if ( _obj_arg.tree_view ) {
			clear_tree_view_data((OBJ_ARG*)&_obj_arg);
			set_tree_view_data((OBJ_ARG*)&_obj_arg,
				(L_CHAR**)e_sts.data);
		}
		else if ( _obj_arg.edit_text ) {
			ss.descriptor = e_sts.data[0];
			_obj_arg.edit_text->set_status(&ss,VSF_DESC);
		}
	}
	if ( (flags & VSF_EL_ADD_DESCRIPTOR) && _obj_arg.add_btn ) {
		ss.descriptor = e_sts.add_descriptor;
		_obj_arg.add_btn->set_status(&ss,VSF_DESC);
	}
	if ( (flags & VSF_EL_DEL_DESCRIPTOR) && _obj_arg.del_btn ) {
		ss.descriptor = e_sts.del_descriptor;
		_obj_arg.del_btn->set_status(&ss,VSF_DESC);
	}
	if ( (flags & VSF_EL_ADD_DESCRIPTOR) && _obj_arg.bro_btn ) {
		ss.descriptor = e_sts.bro_descriptor;
		_obj_arg.bro_btn->set_status(&ss,VSF_DESC);
	}
	VM_OP_END;
	return err;
}

VExError
VxlEditLine::get_xlel_status(VxlEditLineStatus * ests,int flags) const
{
VExError err;
VObjectStatus ss;
int len;
int key;
	VM_OP_START_EX
	err = initial_VExError(V_ER_NO_ERR,flags,0);
	copy_EditLineStatus(
		ests,(VxlEditLineStatus*)&e_sts,flags&(~VSF_EL_DATA),0);
	if ( flags & VSF_EL_DATA ) {
		if ( _obj_arg.tree_view ) {
			ests->data = (L_CHAR**)d_alloc(sizeof(L_CHAR*));
			len = 0;
			for ( key = 0 ; key < _obj_arg.max_node_key ; key ++ ) {
			VTreeNode * node;
				node = _obj_arg.tree_view->get_row((void*)key);
				if ( node == 0 )
					continue;
				ests->data = (L_CHAR**)d_re_alloc(ests->data,
						sizeof(L_CHAR*)*(len+1));
				ests->data[len] = ll_copy_str((L_CHAR*)node->data[0]);
				len ++;
				delete node;
			}
			ests->data = (L_CHAR**)d_re_alloc(ests->data,
					sizeof(L_CHAR*)*(len+1));
			ests->data[len] = 0;
		}
		else if ( _obj_arg.edit_text ) {
			err = _obj_arg.edit_text->get_status(
					&ss,VSF_DESC);
			if ( err.code != V_ER_NO_ERR ) {
				err.subcode1 = flags;
				err.subcode2 = VSF_EL_DATA;
				goto end;
			}
			ests->data = (L_CHAR**)d_alloc(sizeof(L_CHAR*)*2);
			ests->data[0] = (L_CHAR*)ss.descriptor;
			ests->data[1] = 0;
		}
		else {
			ests->data = 0;
		}
		flags &=~VSF_EL_DATA;
	}
end:
	VM_OP_END;
	return err;
}



