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

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


#define STREAM_LIB

#include	<fcntl.h>
#include	<string.h>

extern "C" {

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

} // extern "C"


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

extern "C" {

void
sp_get_sequence_pic(PIC * pi,TR_SEQUENCE * sq);

STREAM * s_error_stream();
int s_error();

extern TR_BOX_OP string_pic_op,vobj_tr_op;

typedef struct s_VxlText {
	S_HEADER	h;
	VxlText *	txt;
} S_VxlText;

typedef struct attr_stack {
	struct attr_stack *	next;
	int			o_flags;
	int			t_flags;
	VObjectStatus *		o_sts;
	VxlTextStatus *		t_sts;
} ATTR_STACK;


int s_write_VxlText(STREAM * s,void * data,int len);
int s_read_VxlText(STREAM * s,void * data,int len);
int s_flush_VxlText(STREAM * s,void * data,int len);
int s_close_VxlText(STREAM * s);
STREAM * initial_VxlText_stream(VxlText * obj);
void make_img_VxlText(short w, short h, VImage *img);
void VxlText_VDraw_cb(
	TR_SEQUENCE * sq,
	void * arg);
void default_VxlTextStatus(VxlTextStatus * s);
void VxlText_copyin(VImage * img,PIC * pi,PIC_ELEMENT * pe);
void VxlText_loop(XLISP_ENV * env,VxlText * obj,XL_SEXP * p,int ps_flags);
void vobj_VxlTextPop(ATTR_STACK ** atp,VxlText * obj);
void 
vobj_VxlTextAttr(ATTR_STACK ** atp,
	VxlText * obj,
	XLISP_ENV * env,
	XL_SYM_FIELD * sf);



int
s_write_VxlText(STREAM * s,void * data,int len)
{
S_VxlText * _s;
	_s = (S_VxlText*)s;
	return _s->txt->_s_write(s,data,len);
}

int
s_read_VxlText(STREAM * s,void * data,int len)
{
S_VxlText * _s;
	_s = (S_VxlText*)s;
	return _s->txt->_s_read(s,data,len);
}

int
s_flush_VxlText(STREAM * s,void * data,int len)
{
	return 0;
}

int
s_close_VxlText(STREAM * s)
{
S_VxlText * _s;
	_s = (S_VxlText*)s;
	_s->txt->st = 0;
	return 0;
}


S_TABLE s_VxlText = {
	'v',
	0,
	{0,0},
	0,
	s_error_stream,
	(int (*)())s_close_VxlText,
	(int (*)())s_write_VxlText,
	(int (*)())s_read_VxlText,
	(int (*)())s_flush_VxlText,
	s_error,
	s_error_stream,
	(int (*)())s_error_stream
};


STREAM *
initial_VxlText_stream(VxlText * obj)
{
S_VxlText * _s;
STREAM * ret;
//void _s_open(STREAM*,int);
	_s = (S_VxlText*)d_alloc(sizeof(*_s));
	_s->h.tbl = &s_VxlText;
	_s->txt = obj;
	ret = (STREAM*)_s;
	_s_open(ret,O_RDWR);
	s_set_cm(ret,&int_cm);
	return ret;
}

} // extern "C"


int
VxlText::_s_write(STREAM * s,void * data,int len)
{
int _len;
	_len = len/sizeof(L_CHAR);
	if ( lock_d(__FILE__,__LINE__) )
		return -1;
	tx_curret = tr_insert_string(
		tx_sq,
		tx_curret,
		_len,
		tx_ws,
		tx_attr,
		0,
		tx_size,
		(L_CHAR*)data);
	unlock(this);
	return _len*sizeof(L_CHAR);
}

int
VxlText::_s_read(STREAM * s,void * data,int len)
{
int _len;
	if ( lock_d(__FILE__,__LINE__) )
		return -1;
	_len = len/sizeof(L_CHAR);
	_len = tr_copyout(tx_sq,tx_curret,(L_CHAR*)data,_len);
	tx_curret.ptr += _len;
	tr_ptr_regulation(tx_sq,&tx_curret);
	unlock(this);
	return _len*sizeof(L_CHAR);
}




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

void
make_img_VxlText(short w, short h, VImage *img)
{
	for ( int x = 0 ; x < w ; x++ ) {
		for ( int y = 0 ; y < h ; y++ ) {
			SET_RGB8_32(img->buf_32[x+img->w_border*y],
				RGB8_MAX,RGB8_MAX,RGB8_MAX,RGB8_MAX);
		}
	}
}



void
VxlText_VDraw_cb(
	TR_SEQUENCE * sq,
	void * arg)
{
VxlText * text;
	text = (VxlText*)arg;
	text->_text_cb();
}

void
default_VxlTextStatus(VxlTextStatus * s)
{
	s->algorism = 0;
	s->editable = 0;
	_tr_set_default_lattr(&s->battr.default_lattr);
	s->battr.max_line_pixels = -1;
	s->battr.max_doc_dir_pixels = -1;
	s->curret = 0;
}


VExError
VxlText::create_do_VDraw()
{
VExError err;
VObjectStatus ss;

	ss.size = b_sts.size;
	VImage *img = v_image_new(ss.size.w,ss.size.h, 32);
	v_image_draw_start(img, 0);
	make_img_VxlText(ss.size.w,ss.size.h,img);
	v_image_draw_end(img);

	ss.parent = this;
	ss.attr = VDraw::mouse_move_wait;
	ss.min_size = ss.size;
	tx_object.draw = VDraw::create(&ss, VSF_PARENT | VSF_ATTR | 
			VSF_SIZE| VSF_MIN_SIZE, &err);
	if ( err.code ) {
		return err;
	}
	VError e = tx_object.draw->set_image(img, img->size);
	if ( e != V_ER_NO_ERR ) {
		err = initial_VExError(e,0,0);
		tx_object.draw->destroy();
		return err;
	}
	v_image_unref(img);

	tx_sq = tr_new_sequence(&string_pic_op,PRI_TR,(void*)0);
	tr_set_callback(tx_sq,VxlText_VDraw_cb,(void*)this);
	tr_new_box(tx_sq,0,&tx_sts.battr);
	tx_object.draw->redraw();
	st = initial_VxlText_stream(this);

	return err;
}

VExError
VxlText::create_do_VText()
{
VExError err;
VObjectStatus ss;
VTR_SEQUENCE vtr_sq;

	ss.padding = sts.padding;
	ss.spacing = sts.spacing;
	ss.size = b_sts.size;
	ss.parent = this;
	ss.min_size = b_sts.size;
	ss.alignh = ss.alignv = VALIGN_FILL;
	ss.visible = 1;
	tx_object.halign = VHAlignView::create(&ss,
			VSF_PARENT| 
			VSF_SIZE|
			VSF_MIN_SIZE|
			VSF_VISIBLE|
			VSF_PADDING|
			VSF_SPACING|
			VSF_ALIGN,
			&err);
	if ( err.code ) {
		return err;
	}
	vtr_sq.new_box_vobj = 0;
	vtr_sq.base_obj = tx_object.halign;
	tx_sq = tr_new_sequence(&vobj_tr_op,PRI_TR,(void*)&vtr_sq);
/*
	tr_set_callback(tx_sq,VxlText_VDraw_cb,(void*)this);
*/
	tr_new_box(tx_sq,0,&tx_sts.battr);
	tx_object.halign->redraw();
	st = initial_VxlText_stream(this);

	return err;
}


VExError
VxlText::create_do(const VObjectStatus* s, int flags,VObject * nmp, void * arg)
{
VObjectAppStatusAry * app;
VxlTextStatus ss;
int ss_flags;

	info = 0;

	tx_sq = 0;
	memset(&tx_curret,0,sizeof(tx_curret));
	tx_ws = get_ws(l_string(std_cm,"DefaultStyle"));
	tx_size = 160;
	tx_attr = 0;
	tx_object.obj = 0;
	b_sts = v_default_sts;
	b_sts.size.w = 1;
	b_sts.size.h = 1;
	b_sts.min_size = b_sts.size;
	copy_vobject_status(&b_sts,s,flags);

	sts.alignh = v_default_sts.alignh;
	sts.alignv = v_default_sts.alignv;
	sts.spacing = v_default_sts.spacing;
	sts.padding = v_default_sts.padding;
	default_VxlTextStatus(&tx_sts);

	if ( arg ) {
		app = (VObjectAppStatusAry*)arg;
		ss = *(VxlTextStatus*)app[0].sts;
		ss_flags = app[0].flags;
		if ( (app[0].flags & VSF_XLTEXT_ALGORISM) == 0 ||
				ss.algorism == 0 ) {
			ss.algorism = VXLT_A_DRAW;
			ss_flags |= VSF_XLTEXT_ALGORISM;
		}
	}
	else {
		ss.algorism = VXLT_A_DRAW;
		ss_flags = VSF_XLTEXT_ALGORISM;
	}
	return this->set_xltext_status(
			(const VxlTextStatus*)&ss,
			ss_flags);
}



void
VxlText::destroy_do(VObject * nmp)
{
	_tr_free_attr(tx_attr);
	tx_object.obj = 0;
	free_vobject_status_copy(&b_sts);
}

void
VxlText::destroy_do_out_of_lock(VObject * nmp)
{
TR_SEQUENCE * sq;
	if ( tx_sq ) {
		sq = tx_sq;
		tx_sq = 0;
		tr_close_sequence(sq);
	}
}


VExError
VxlText::get_status(VObjectStatus * s,int flags) const
{
VExError err;

	err = initial_VExError(V_ER_NO_ERR,flags,0);

	if ( flags & (VSF_WS|VSF_FSIZE) ) {
		VM_OP_START_EX
		if ( flags & VSF_WS ) {
			s->ws = tx_ws;
			flags &= ~VSF_WS;
		}
		if ( flags & VSF_FSIZE ) {
			s->fsize = tx_size;
			flags &= ~VSF_FSIZE;
		}
		VM_OP_END
	}
	err.subcode1 = flags;
	err = merge_VExError_vstatus_type(err,VMacro::get_status(s,flags));
	if ( err.code == V_ER_NO_ERR && err.subcode1 ) {
		copy_vobject_status(s,&b_sts,err.subcode1);
		err = initial_VExError(V_ER_NO_ERR,0,0);
	}
	return err;
}

VExError
VxlText::set_status(const VObjectStatus * s,int flags)
{
VExError err;
	err = initial_VExError(V_ER_NO_ERR,flags,0);
	if ( flags & (VSF_WS|VSF_FSIZE) ) {
		VM_OP_START_EX
		if ( flags & VSF_WS ) {
			if ( s->ws == 0 )
				tx_ws = get_ws(l_string(std_cm,"DefaultStyle"));
			else	tx_ws = (LC_WRITING_STYLE*)s->ws;
			err.subcode1 &= ~ VSF_WS;
		}
		if ( flags & VSF_FSIZE ) {
			tx_size = s->fsize;
			err.subcode1 &= ~ VSF_FSIZE;
		}
		VM_OP_END;
	}
	err = merge_VExError_vstatus_type(err,VMacro::set_status(s,flags));
	return err;
}

VxlText::~VxlText()
{
}


VExError
VxlText::get_xltext_status(
		VxlTextStatus * xsts,
		int flags) const
{
	VM_OP_START_EX
	if ( flags & VSF_XLTEXT_ALGORISM ) {
		xsts->algorism = tx_sts.algorism;
		flags &= ~VSF_XLTEXT_ALGORISM;
	}
	if ( flags & VSF_XLTEXT_EDITABLE ) {
		xsts->editable = tx_sts.editable;
		flags &= ~VSF_XLTEXT_EDITABLE;
	}
	if ( flags & VSF_XLTEXT_BATTR ) {
		xsts->battr = tx_sts.battr;
		flags &= ~VSF_XLTEXT_BATTR;
	}
	if ( flags & VSF_XLTEXT_CURRET ) {
		xsts->curret = tx_sts.curret;
		flags &= ~VSF_XLTEXT_CURRET;
	}
	VM_OP_END
	return initial_VExError(V_ER_NO_ERR,flags,0);
}

VExError
VxlText::set_xltext_status(
		const VxlTextStatus * xsts,
		int flags)
{
VExError err;
TR_SEQUENCE * destroy_sq;

	VM_OP_START_EX
	destroy_sq = 0;
	err.code = V_ER_NO_ERR;
	err.subcode1 = 0;
	err.subcode2 = 0;
	if ( flags & VSF_XLTEXT_ALGORISM ) {
		if ( tx_sts.algorism != xsts->algorism ) {
			tx_sts.algorism = xsts->algorism;
			if ( tx_object.obj ) {
				err.subcode1 = flags;
				err.subcode2 = VSF_XLTEXT_ALGORISM;
				err.code = V_ER_PARAM;
				goto end;
			}
			tx_object.obj = 0;
			switch ( tx_sts.algorism ) {
			case VXLT_A_DRAW:
				err = this->create_do_VDraw();
				break;
			case VXLT_A_TEXT:
				err = this->create_do_VText();
				break;
			default:
				er_panic("VxlText");
			}
		}
		flags &= ~VSF_XLTEXT_ALGORISM;
	}
	if ( flags & VSF_XLTEXT_EDITABLE ) {
		tx_sts.editable = xsts->editable;
		flags &= ~VSF_XLTEXT_EDITABLE;
	}
	if ( flags & VSF_XLTEXT_BATTR ) {
		tx_sts.battr = xsts->battr;
		_tr_copy_line_attr(&tx_sts.battr.default_lattr,
			(TR_LINE_ATTR*)&xsts->battr.default_lattr);
		flags &= ~VSF_XLTEXT_BATTR;
	}
	if ( flags & VSF_XLTEXT_CURRET ) {
		tx_sts.curret = xsts->curret;
		flags &= ~VSF_XLTEXT_CURRET;
	}
end:
	VM_OP_END
	return initial_VExError(V_ER_NO_ERR,flags,0);
}

void
VxlText_copyin(VImage * img,PIC * pi,PIC_ELEMENT * pe)
{
int x,y;
unsigned int * dp;
unsigned char * ap;
int ww,hh,wp;
INTEGER64 src_r,src_g,src_b,src_a;
INTEGER64 dest_r,dest_g,dest_b,dest_a;
INTEGER64 r,g,b,a;
int w;
long * tp;
long target;
unsigned int org;



	dp = pe->data;
	ap = pe->alpha;
	ww = pe->p.r.br.x - pe->p.r.tl.x;
	hh = pe->p.r.br.y - pe->p.r.tl.y;
	w = img->w_border;
	if ( ap ) {
		for ( y = pe->p.r.tl.y - pi->rect.tl.y ;
				hh ;
				y ++ , hh -- ) {
			wp = ww;
			for ( x = pe->p.r.tl.x - pi->rect.tl.x;
					wp;
					x ++ , wp -- ) {
				tp = &img->buf_32[x + y*w];
				target = *tp;
				GET_RGB8_32(target,
					dest_r,
					dest_g,
					dest_b,
					dest_a);
				dest_r <<= COL_BIT - 8;
				dest_g <<= COL_BIT - 8;
				dest_b <<= COL_BIT - 8;
				if ( dest_a == RGB8_MAX )
					dest_a = COL_MASK;
				else	dest_a <<= COL_BIT - 8;
				GET_COL(*dp,src_r,src_g,src_b);
				src_a = (255 - *ap);
				if ( src_a == 255 )
					src_a = COL_MASK;
				else	src_a <<= COL_BIT - 8;
				BREND_ALPHA(
					r,
					dest_r,
					dest_a,
					src_r,
					src_a);
				BREND_ALPHA(
					g,
					dest_g,
					dest_a,
					src_g,
					src_a);
				BREND_ALPHA(
					b,
					dest_b,
					dest_a,
					src_b,
					src_a);
				BREND_ALPHA_A(a,dest_a,src_a);
				a >>= COL_BIT - 8;
				b >>= COL_BIT - 8;
				r >>= COL_BIT - 8;
				g >>= COL_BIT - 8;
				SET_RGB8_32(*tp,r,g,b,a);

				dp ++;
				ap ++;
			}
		}
 	}
	else {
		for ( y = pe->p.r.tl.y - pi->rect.tl.y ;
				hh ;
				y ++ , hh -- ) {
			wp = ww;
			for ( x = pe->p.r.tl.x - pi->rect.tl.x;
					wp;
					x ++ , wp -- ) {
				tp = &img->buf_32[x + y*w];
				org = *dp;
				if ( org != C_TRANSPARENT ) {
					GET_COL(org,src_r,src_g,src_b);
					src_b >>= COL_BIT - 8;
					src_r >>= COL_BIT - 8;
					src_g >>= COL_BIT - 8;
					SET_RGB8_32(*tp,src_r,src_g,src_b,
							RGB8_MAX);
				}

				dp ++;
			}
		}
	}
}

void
VxlText::_text_cb()
{
PIC pi;
VImage * img;
int h,w;
PIC_ELEMENT * pe;
VObjectStatus s;
	if ( lock_d(__FILE__,__LINE__) )
		return;
	sp_get_sequence_pic(&pi,tx_sq);

	w = pi.rect.br.x - pi.rect.tl.x;
	h = pi.rect.br.y - pi.rect.tl.y;
	if ( h <= 0 || w <= 0 )
		goto end;

	img = v_image_new(w,h, 32);
	v_image_draw_start(img, 0);
	make_img_VxlText(w,h,img);
	for ( pe = pi.list ; pe ; pe = pe->next ) {
		VxlText_copyin(img,&pi,pe);
	}
	v_image_draw_end(img);
	tx_object.draw->set_image(img, img->size);
	v_image_unref(img);
	s.size.w = w;
	s.size.h = h;
	tx_object.draw->set_status(&s,VSF_SIZE);
end:
	unlock(this);
}


VError
VxlText::set_xl_sexp(XLISP_ENV * e,XL_SEXP * s)
{
VError ret;
VTR_OBJECT ob;
	VM_OP_START
	if ( tx_sts.algorism != VXLT_A_TEXT ) {
		ret = V_ER_INVALID_MODE;
		goto end;
	}
	ob.env = e;
	ob.sexp = s;
	tx_curret = tr_insert_string(
		tx_sq,
		tx_curret,
		1,
		0,
		tx_attr,
		&ob,
		0,
		0);
	ret = V_ER_NO_ERR;
end:
	VM_OP_END
	return ret;
}
char *
VxlText_get_xltext_from_sf(
	VxlTextStatus * xsts,int * flags,
	XLISP_ENV * env,
	XL_SYM_FIELD * sf)
{
L_CHAR * d;
char * ret;
	*flags = 0;
	ret = 0;
	xsts->battr.max_line_pixels = -1;
	xsts->battr.max_doc_dir_pixels = -1;
	xsts->battr.default_lattr.flags = 0;
	d = get_sf_attribute(sf,l_string(std_cm,"xltext.Algorism"));
	if ( d ) {
		if ( l_strcmp(d,l_string(std_cm,"VDraw")) == 0 )
			xsts->algorism = VXLT_A_DRAW;
		else if ( l_strcmp(d,l_string(std_cm,"VText")) == 0 )
			xsts->algorism = VXLT_A_TEXT;
		else {
			ret = "algorism";
			return ret;
		}
		(*flags) |= VSF_XLTEXT_ALGORISM;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xltext.Editable"));
	if ( d ) {
		xsts->editable = atoi(n_string(std_cm,d));
		(*flags) |= VSF_XLTEXT_EDITABLE;
	}
	d = get_sf_attribute(sf,l_string(std_cm,
		"xltext.battr.LineAttr.Align"));
	if ( d ) {
		if ( l_strcmp(d,l_string(std_cm,"Center")) == 0 )
			xsts->battr.default_lattr.align
				= TRT_CENTER;
		else if ( l_strcmp(d,l_string(std_cm,"CapitaBasisAll")) == 0 )
			xsts->battr.default_lattr.align
				= TRT_CAPITA_BASIS_ALL;
		else if ( l_strcmp(d,l_string(std_cm,"LineStart")) == 0 )
			xsts->battr.default_lattr.align
				= TRT_LINE_START;
		else if ( l_strcmp(d,l_string(std_cm,"LineEnd")) == 0 )
			xsts->battr.default_lattr.align
				= TRT_LINE_END;
		else if ( l_strcmp(d,l_string(std_cm,"CapitaBasis")) == 0 )
			xsts->battr.default_lattr.align
				= TRT_CAPITA_BASIS;
		else {
			ret = "LineAttr.Align";
			return ret;
		}
		(*flags) |= VSF_XLTEXT_BATTR;
		xsts->battr.default_lattr.flags |= TRLF_ALIGN;	
	}
	d = get_sf_attribute(sf,l_string(std_cm,
		"xltext.battr.LineAttr.DefaultDir"));
	if ( d ) {
		if ( l_strcmp(d,l_string(std_cm,"VirticalLeftToRight")) == 0 )
			xsts->battr.default_lattr.default_dir = VSD_V_L2R;
		else if ( l_strcmp(d,l_string(std_cm,"VirticalRightToLeft")) == 0 )
			xsts->battr.default_lattr.default_dir = VSD_V_R2L;
		else if ( l_strcmp(d,l_string(std_cm,"HorizontalLeftToRight")) == 0 )
			xsts->battr.default_lattr.default_dir = VSD_H_L2R;
		else if ( l_strcmp(d,l_string(std_cm,"HorizontalRightToLeft")) == 0 )
			xsts->battr.default_lattr.default_dir = VSD_H_R2L;
		else {
			ret = "LineAttr.DefaultDir";
			return ret;
		}
		(*flags) |= VSF_XLTEXT_BATTR;
		xsts->battr.default_lattr.flags |= TRLF_DEFAULT_DIR;	
	}
	d = get_sf_attribute(sf,
		l_string(std_cm,"xltext.battr.LineAttr.Pitch"));
	if ( d ) {
		xsts->battr.default_lattr.pitch = atoi(n_string(std_cm,d));
		(*flags) |= VSF_XLTEXT_BATTR;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xltext.battr.MaxLinePixels"));
	if ( d ) {
		xsts->battr.max_line_pixels = 
				atoi(n_string(std_cm,d));
		(*flags) |= VSF_XLTEXT_BATTR;
	}
	d = get_sf_attribute(sf,l_string(std_cm,"xltext.battr.MaxDocDirPixels"));
	if ( d ) {
		xsts->battr.max_doc_dir_pixels = 
				atoi(n_string(std_cm,d));
		(*flags) |= VSF_XLTEXT_BATTR;
	}
	return 0;
}

void 
vobj_VxlTextAttr(ATTR_STACK ** atp,
	VxlText * obj,
	XLISP_ENV * env,
	XL_SYM_FIELD * sf)
{
VxlTextStatus t_sts;
int t_flags;
int o_flags;
VObjectStatus o_sts;
VObject::FreeList * free_list;
L_CHAR * stack;
ATTR_STACK * at;
	stack = get_sf_attribute(sf,l_string(std_cm,"stack"));
	o_flags = get_sts_from_sf(env,&o_sts,0,sf,&free_list);
	VxlText_get_xltext_from_sf(&t_sts,&t_flags,env,sf);
	if ( stack ) {
		at = (ATTR_STACK*)d_alloc(sizeof(*at));
		at->t_flags = t_flags;
		at->o_flags = o_flags;
		if ( t_flags ) {
			at->t_sts = (VxlTextStatus*)d_alloc(sizeof(t_sts));
			memset(at->t_sts,0,sizeof(t_sts));
			obj->get_xltext_status(at->t_sts,t_flags);
		}
		if ( o_flags ) {
			at->o_sts = (VObjectStatus*)d_alloc(sizeof(o_sts));
			memset(at->o_sts,0,sizeof(o_sts));
			obj->get_status(at->o_sts,o_flags);
		}
		at->next = *atp;
		*atp = at;
	}
	if ( o_flags )
		obj->set_status(&o_sts,o_flags);
	if ( t_flags )
		obj->set_xltext_status(&t_sts,t_flags);
}

void
vobj_VxlTextPop(ATTR_STACK ** atp,VxlText * obj)
{
ATTR_STACK * at;
	at = *atp;
	if ( at == 0 )
		return;
	*atp = at->next;
	if ( at->o_flags ) {
		obj->set_status(at->o_sts,at->o_flags);
		d_f_ree(at->o_sts);
	}
	if ( at->t_flags ) {
		obj->set_xltext_status(at->t_sts,at->t_flags);
		free_VxlTextStatus(at->t_sts);
	}
	d_f_ree(at);
}

void
VxlText_loop(XLISP_ENV * env,VxlText * obj,XL_SEXP * p,int ps_flags)
{
XL_SEXP * el,* sym;
int space;
ATTR_STACK * at;
	space = 0;
	at = 0;
	for ( ; get_type(p) ; p = cdr(p) ) {
		el = car(p);
		if ( get_type(el) == XLT_PAIR ) {
			sym = car(el);
			if ( get_type(sym) == XLT_SYMBOL ) {
				if ( l_strcmp(sym->symbol.data,l_string(std_cm,"VxlTextAttr"))
							== 0 ) {
					vobj_VxlTextAttr(&at,obj,env,sym->symbol.field);
				}
				else if ( l_strcmp(sym->symbol.data,
							l_string(std_cm,"VxlTextPop"))
							== 0 ) {
					vobj_VxlTextPop(&at,obj);
				}
				else {
					if ( obj->set_xl_sexp(env,el) < 0 )
						break;
				}
			}
			else {
				if ( space )
					s_printf(obj->st," ");
				VxlText_loop(env,obj,el,ps_flags);
			}
		}
		else if ( get_type(el) != XLT_NULL ) {
			if ( space )
				s_printf(obj->st," ");
			print_sexp(obj->st,el,ps_flags);
			space = 1;
			if ( get_type(el) == XLT_ERROR )
				break;
		}
	}
	for ( ; at ; )
		vobj_VxlTextPop(&at,obj);
}

VError
VxlText::set_xl_sexp_loop(XLISP_ENV* env,XL_SEXP * p,int ps_flags)
{
	waitsync_sexp = p;
	VxlText_loop(env,this,p,ps_flags);
	waitsync_sexp = 0;
	return V_ER_NO_ERR;
}

XL_SEXP *
VxlText::get_object_by_name(L_CHAR * name)
{
XL_SEXP * ret;

	_VM_OP_START(0)
	ret = vtr_get_object_by_name(tx_sq,name);
	VM_OP_END
	return ret;
}

void
VxlText::waitsync(WAITSYNC_CLIENT * c,int type)
{
TR_SEQUENCE * sq;
	sq = tx_sq;
	if ( sq == 0 )
		return;
	if ( type == WST_FORCE_STOP )
		kill_thread(waitsync_sexp);
	tr_waitsync(sq,c,type);
}


void
free_VxlTextStatus(VxlTextStatus* sts)
{
}
