/**********************************************************************
 
	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	"memory_debug.h"
#include 	"v.h"
#include	"long_char.h"
#include	"change_endian.h"

void
get_strbuf(char ** bufp,XChar2b ** buf16p,int * lenp,L_CHAR * str,int len,
	L_CHAR mask)
{
int i,j;
char * buf;
XChar2b * buf16;
char * b1;
L_CHAR * b2;
int dst;
	buf16 = d_alloc(sizeof(XChar2b)*len);
	buf = d_alloc(len);
	dst = 0;

		for ( i = 0 ; i < len ; i ++ ) {
			buf16[dst].byte2 = str[i]&0xff;
			buf16[dst].byte1 = (str[i]>>8)&0xff;
			if ( mask == LCZM_7b_TYPE )
				buf[dst++] = str[i]&0x7f;
			else	buf[dst++] = str[i];
		}
	*bufp = buf;
	*buf16p = buf16;
	*lenp = dst;
}

void
_text_minrect(VRECT * r,int * width,char * str,XChar2b * str2,
	int len,VFONT * vf)
{
int dir,ascent,descent;
XCharStruct cs;

	if ( vf->fs->min_byte1 == 0 && vf->fs->max_byte1 == 0 ) {
		XTextExtents(vf->fs,str,len,
			&dir,
			&ascent,
			&descent,
			&cs);
		*width = XTextWidth(vf->fs,str,len);
	}
	else {
		XTextExtents16(vf->fs,str2,len,
			&dir,
			&ascent,
			&descent,
			&cs);
		*width = XTextWidth16(vf->fs,str2,len);
	}
	switch ( dir ) {
	case FontRightToLeft:
		r->br.x = -cs.lbearing;
		r->tl.x = -cs.rbearing;
		break;
	case FontLeftToRight:
		r->tl.x = cs.lbearing;
		r->br.x = cs.rbearing;
		break;
	}
	r->tl.y = -ascent;
	r->br.y = descent;
}


typedef struct _v_gsp {
	V_STRING_PIC * p;
	VDISPLAY * disp;
	L_CHAR * str;
	int	len;
	int	size;
	int 	dir;
	VFONT *	vf;
	L_CHAR mask;
} _V_GSP;

int
_v_get_string_pic(
	_V_GSP	* v)
{
V_STRING_PIC * p;
VDISPLAY * disp;
L_CHAR * str;
int	size;
int 	dir;
char * buf;
XChar2b * buf16;
int len;
int i,j,x,y;
int w,h;
Pixmap pm;
GC gc;
int st_x,st_y;
XImage * xi;
VFONT * vf;
int width;
int index,um,dm;

	p = v->p;
	disp = v->disp;
	str = v->str;
	size = v->size;
	dir = v->dir;
	vf = v->vf;

	get_strbuf(&buf,&buf16,&len,str,v->len,v->mask);
	_text_minrect(&p->r,&width,buf,buf16,len,
		vf);
	p->width = width;
	w = p->r.br.x - p->r.tl.x;
	h = p->r.br.y - p->r.tl.y;
	if ( h == 0 ) {
		p->pic = 0;
		goto err;
	}
	if ( w == 0 ) {
		p->pic = d_alloc(h*h);
		for ( x = 0 ; x < h*h ; x ++ )
			p->pic[x] = 0;
		goto err;
	}
	pm = XCreatePixmap(disp->d,disp->for_string_pic->w,w,h,1);
	gc = XCreateGC(disp->d,pm,0,0);
	XSetForeground(
		disp->d,
		gc,
		1); /* color */
	XFillRectangle(disp->d,pm,gc,0,0,w,h); 
    	XSetFont(disp->d,
		gc,
		vf->fs->fid);
	XSetForeground(
		disp->d,
		gc,
		0); /* color */
	st_x = - p->r.tl.x;
	st_y = - p->r.tl.y;
	if ( vf->fs->min_byte1 == 0 && vf->fs->max_byte1 == 0 ) {
		XDrawString(
			disp->d,
			pm,
			gc,
			st_x,
			st_y,
			buf,
			len);
	}
	else {
		XDrawString16(
			disp->d,
			pm,
			gc,
			st_x,
			st_y,
			buf16,
			len);
	}

	d_f_ree(buf);
	d_f_ree(buf16);

	xi = XGetImage(disp->d,pm,0,0,w,h,1,ZPixmap);
	if ( xi == 0 )
		er_panic("xi\n");
/*
printf("(%i %i)\n",w,h);
printf("f (%i %i) %i %i %i %i %i\n",
xi->byte_order,LSBFirst,
xi->bitmap_unit,
xi->bitmap_bit_order,
xi->bitmap_pad,
xi->depth,
xi->bytes_per_line);
*/

	p->pic = d_alloc(w*h);
	if ( xi->byte_order == MSBFirst && endian_flag == 0 ||
			xi->byte_order == LSBFirst && endian_flag == 1 ||
			xi->bitmap_unit == 8 ) {
		if ( xi->bitmap_bit_order == LSBFirst ) {
			for ( y = 0 ; y < h ; y ++ )
				for ( x = 0 ; x < w ; x ++ ) {
					if ( xi->data
					   [y*xi->bytes_per_line + x/8] &
							(1<<(x%8)) )
						p->pic[x + y*w] = 255;
					else	p->pic[x + y*w] = 0;
				}
		}
		else {
			for ( y = 0 ; y < h ; y ++ )
				for ( x = 0 ; x < w ; x ++ ) {
					if ( xi->data
					   [y*xi->bytes_per_line + x/8] &
							(1<<(7- (x%8))) )
						p->pic[x + y*w] = 255;
					else	p->pic[x + y*w] = 0;
				}
		}
	}
	else {
		switch ( xi->bitmap_unit ) {
		case 16:
			um = 0xfffffffe;
			dm = 0x00000001;
			break;
		case 32:
			um = 0xfffffffc;
			dm = 0x00000003;
			break;
		default:
			er_panic("v_get_string_pic(1)");
		}
		if ( xi->bitmap_bit_order == LSBFirst ) {
			for ( y = 0 ; y < h ; y ++ )
				for ( x = 0 ; x < w ; x ++ ) {
					index = y*xi->bytes_per_line + x/8;
					index = (um&index) +
						dm - (dm&index);
					if ( xi->data[index] & (1<<(x%8)) )
						p->pic[x + y*w] = 255;
					else	p->pic[x + y*w] = 0;
				}
		}
		else {
			for ( y = 0 ; y < h ; y ++ )
				for ( x = 0 ; x < w ; x ++ ) {
					index = y*xi->bytes_per_line + x/8;
					index = (um&index) +
						dm - (dm&index);
					if ( xi->data[index]&(1<<(7- (x%8))) )
						p->pic[x + y*w] = 255;
					else	p->pic[x + y*w] = 0;
				}
		}
	}
	p->dir = VSD_L2R;
	XDestroyImage(xi);
	XFreeGC(disp->d,gc);
	XFreePixmap(disp->d,pm);
err:
	return 0;
}


void
v_get_string_pic_call(
	V_STRING_PIC * p,
	VDISPLAY * disp,
	L_CHAR * str,
	int len,
	VFONT * vf,
	int	size,
	int 	dir,
	L_CHAR mask)
{
_V_GSP	v;
	v.p = p;
	v.disp = disp;
	v.str = str;
	v.len = len;
	v.size = size;
	v.dir = dir;
	v.vf = vf;
	v.mask = mask;
	ms_do(_v_get_string_pic,&v,"v_get_string_pic");
}


void
compose_pic(V_STRING_PIC * p,V_STRING_PIC * pp)
{
V_STRING_PIC ppp;
int w,h,ww,hh;
int x,y,i;
int y_ofs,x_ofs;
	ppp.width = p->width + pp->width;
	ppp.dir = p->dir;
	ppp.r.tl.x = p->r.tl.x;
	if ( p->r.tl.y < pp->r.tl.y )
		ppp.r.tl.y = p->r.tl.y;
	else	ppp.r.tl.y = pp->r.tl.y;
	ppp.r.br.x = p->width + pp->r.br.x;
	if ( p->r.br.y < pp->r.br.y )
		ppp.r.br.y = pp->r.br.y;
	else	ppp.r.br.y = p->r.br.y;
	w = ppp.r.br.x - ppp.r.tl.x;
	h = ppp.r.br.y - ppp.r.tl.y;
	ppp.pic = d_alloc(w*h);
	for ( i = 0 ; i < w*h ; i ++ )
		ppp.pic[i] = 255;
	ww = p->r.br.x - p->r.tl.x;
	hh = p->r.br.y - p->r.tl.y;
	y_ofs = p->r.tl.y - ppp.r.tl.y;
	i = 0;
	for ( y = y_ofs ; y < hh+y_ofs ; y ++ )
		for ( x = 0 ; x < ww ; x ++ )
			ppp.pic[x + y*w] = p->pic[i++];
	x_ofs = -ppp.r.tl.x+p->width+pp->r.tl.x;
	y_ofs = pp->r.tl.y - ppp.r.tl.y;
	ww = pp->r.br.x - pp->r.tl.x;
	hh = pp->r.br.y - pp->r.tl.y;
	i = 0;
	for ( y = y_ofs ; y < hh+y_ofs ; y ++ )
		for ( x = x_ofs ; x < ww+x_ofs ; x ++ ){
			if ( pp->pic[i] != 255 )
				ppp.pic[x + y*w] = pp->pic[i];
			i ++;
		}
	d_f_ree(p->pic);
	d_f_ree(pp->pic);
	*p = ppp;
}


void
v_get_string_pic(
	V_STRING_PIC * p,
	VDISPLAY * disp,
	L_CHAR * str,
	int	size,
	int 	dir)
{
int len;
int i,j;
V_STRING_PIC pp;
L_CHAR unknown;
int f;
WRITABLE_CODE_TABLE * t;
	len = l_strlen(str);
	unknown = '?';
	f = 0;
	for ( i = 0 ; i < len ; ) {
		t = get_wct(disp->font_work,str[i]);
		if ( t ) {
			for ( j = i ; j < len &&
				(str[j]&t->mask) == t->lcz ; j ++ );
			v_get_string_pic_call(
				&pp,
				disp,
				&str[i],
				j-i,
				t->work,
				size,
				dir,
				t->mask);
			i = j;
			if ( pp.pic == 0 ) {
				v_get_string_pic_call(
					&pp,
					disp,
					&unknown,
					1,
					&disp->iso8859_1,
					size,
					dir,
					LCZM_1B_TYPE);
			}
		}
		else {
			v_get_string_pic_call(
				&pp,
				disp,
				&unknown,
				1,
				&disp->iso8859_1,
				size,
				dir,
				LCZM_1B_TYPE);
			i ++;
		}
		if ( f == 0 ) {
			*p = pp;
			f = 1;
		}
		else {
			compose_pic(p,&pp);
		}
	}
}

