/**********************************************************************
 
	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	<stdio.h>
#include	<stdlib.h>
#include	<X11/Xatom.h>
#include	"memory_debug.h"
#include	"utils.h"
#include	"v.h"
#include	"long_char.h"

VDISPLAY * disp_list;

char * display_key = 0;

int _err_handler(
    Display*		/* display */,
    XErrorEvent*	/* error_event */
);


void
v_set_display_key(char * key)
{
	display_key = copy_str(key);
}

void
get_mask_info(int * mul,int * max,int * shift,unsigned int mask)
{
int msb,lsb;
	if ( mask == 0 ) {
		*mul = 0;
		*max = 0;
		*shift = 0;
		return;
	}
	for ( lsb = 0 ; lsb < 32 && (mask&(1<<lsb)) == 0 ; lsb ++ );
	for ( msb = lsb ; msb < 32 && (mask&(1<<msb)) != 0 ; msb ++ );
	*mul = 1<<lsb;
	*max = 1<<(msb-lsb);
	*shift = 0xffff / ((1<<(msb-lsb))-1);
}

int
set_gb2m(unsigned int * table,unsigned int mask)
{
int msb,lsb;
int shift;
int i;

	if ( mask == 0 )
		return -1;
	for ( lsb = 0 ; lsb < 32 && (mask&(1<<lsb)) == 0 ; lsb ++ );
	for ( msb = lsb ; msb < 32 && (mask&(1<<msb)) != 0 ; msb ++ );
	if ( msb < COL_BIT ) {
		shift = COL_BIT - msb;
		for ( i = 0 ; i < (1<<COL_BIT) ; i ++ )
			table[i] = (i>>shift)&mask;
	}
	else if ( msb == COL_BIT ) {
		for ( i = 0 ; i < (1<<COL_BIT) ; i ++ )
			table[i] = i&mask;
	}
	else {
		shift = msb - COL_BIT;
		for ( i = 0 ; i < (1<<COL_BIT) ; i ++ )
			table[i] = (i<<shift)&mask;
	}
	return 0;
}

void
get_gb2m_mul_shift(unsigned long *mul,char * shift,int mask)
{
int lsb,msb;
	for ( lsb = 0 ; lsb < 32 && (mask&(1<<lsb)) == 0 ; lsb ++ );
	for ( msb = lsb ; msb < 32 && (mask&(1<<msb)) != 0 ; msb ++ );
	*shift = lsb;
	*mul = COL_MASK / ((1<<(msb-lsb))-1);
}

void v_get_font();

typedef struct v_open_disp_s {
	VDISPLAY *		ret;
	VERROR *		err;
} V_OPEN_DISP_S;

int
_v_open_disp(V_OPEN_DISP_S * buf)
{
VDISPLAY * d;
XVisualInfo tmp, * v;
int match;
XColor * acolor;
int i,er;
char * dis;
XStandardColormap smap;
int max,mul,shift;
int fbm;
char * z;
int s;
V_OPEN_WIN_S ow;

	acolor = d_alloc(sizeof(XColor)*0x10000,122); 
	d = d_alloc(sizeof(*d),155);
	d->font_flag = 0;
	d->next = disp_list;
	disp_list = d;
/*
	(void*)XSetErrorHandler(_err_handler);
*/
	if ( display_key == 0 )
		dis = getenv("DISPLAY");
	else	dis = display_key;
	if ( dis == 0 ) {
		fprintf(stderr,"undefined env variable DISPLAY\n");
		exit(1);
	}
	d->d = XOpenDisplay(dis);
	if ( d->d == 0 ) {
		fprintf(stderr,"cannot open the display \"%s\"\n",
			dis);
		exit(1);
	}

	d->depth = 24;

	tmp.screen = 0;
	tmp.depth = d->depth;
	tmp.class = DirectColor;
	v = XGetVisualInfo(
		d->d,
		VisualClassMask|VisualScreenMask|VisualDepthMask,
		&tmp,
		&match);
	if ( match )
		goto next;

	tmp.screen = 0;
	tmp.depth = d->depth;
	tmp.class = TrueColor;
	v = XGetVisualInfo(
		d->d,
		VisualClassMask|VisualScreenMask|VisualDepthMask,
		&tmp,
		&match);
	if ( match )
		goto next;


	d->depth = 16;

	tmp.screen = 0;
	tmp.depth = d->depth;
	tmp.class = DirectColor;
	v = XGetVisualInfo(
		d->d,
		VisualClassMask|VisualScreenMask|VisualDepthMask,
		&tmp,
		&match);
	if ( match )
		goto next;

	tmp.screen = 0;
	tmp.depth = d->depth;
	tmp.class = TrueColor;
	v = XGetVisualInfo(
		d->d,
		VisualClassMask|VisualScreenMask|VisualDepthMask,
		&tmp,
		&match);
	if ( match )
		goto next;


	d->depth = 8;

	tmp.screen = 0;
	tmp.depth = d->depth;
	tmp.class = DirectColor;
	v = XGetVisualInfo(
		d->d,
		VisualClassMask|VisualScreenMask|VisualDepthMask,
		&tmp,
		&match);
	if ( match )
		goto next;

	tmp.screen = 0;
	tmp.depth = d->depth;
	tmp.class = TrueColor;
	v = XGetVisualInfo(
		d->d,
		VisualClassMask|VisualScreenMask|VisualDepthMask,
		&tmp,
		&match);
	if ( match )
		goto next;

	fprintf(stderr,"cannot open the display\n");
	fprintf(stderr,"the DirectColor and TrueColor is not support\n");
	exit(1);
next:


	d->visual = v[0].visual;
switch ( d->visual->class ) {
case TrueColor:
	printf("class = TrueColor ");
	break;
case DirectColor:
	printf("class = DirectColor ");
	break;
default:
	er_panic("other class");
}
printf("red %x green %x blue %x\n",
d->visual->red_mask,
d->visual->green_mask,
d->visual->blue_mask);
printf("-- %i\n",d->visual->bits_per_rgb);

	d->r = RootWindow(d->d,0);

	d->gb2m_map.map[GB2M_R] = d_alloc(sizeof(int)*(1<<COL_BIT),234);
	d->gb2m_map.map[GB2M_G] = d_alloc(sizeof(int)*(1<<COL_BIT),33);
	d->gb2m_map.map[GB2M_B] = d_alloc(sizeof(int)*(1<<COL_BIT),34);
	if ( d->depth > 16 )
		d->gb2m_map.pixel_bits = 32;
	else if ( d->depth > 8 )
		d->gb2m_map.pixel_bits = 16;
	else	d->gb2m_map.pixel_bits = 8;
	set_gb2m(d->gb2m_map.map[GB2M_R],d->visual->red_mask);
	set_gb2m(d->gb2m_map.map[GB2M_G],d->visual->green_mask);
	set_gb2m(d->gb2m_map.map[GB2M_B],d->visual->blue_mask);
printf("RGB %x %x %x\n",
d->gb2m_map.map[GB2M_R][0x3ff],
d->gb2m_map.map[GB2M_G][0x3ff],
d->gb2m_map.map[GB2M_B][0x3ff]);
	d->gb2m_map.red_mask = d->visual->red_mask;
	d->gb2m_map.green_mask = d->visual->green_mask;
	d->gb2m_map.blue_mask = d->visual->blue_mask;
	get_gb2m_mul_shift(
		&d->gb2m_map.red_mul,
		&d->gb2m_map.red_shift,
		d->visual->red_mask);
	get_gb2m_mul_shift(
		&d->gb2m_map.green_mul,
		&d->gb2m_map.green_shift,
		d->visual->green_mask);
	get_gb2m_mul_shift(
		&d->gb2m_map.blue_mul,
		&d->gb2m_map.blue_shift,
		d->visual->blue_mask);

	d->cmap = 0;

	if ( tmp.class == DirectColor ) {
		d->cmap = XCreateColormap(d->d,d->r,d->visual,AllocAll);
		get_mask_info(&mul,&max,&shift,d->visual->blue_mask);
		for ( i = 0 ; i < max ; i ++ ) {
			acolor[i].pixel = i*mul;
			acolor[i].red = acolor[i].green = acolor[i].blue
					= i*shift;
			acolor[i].flags = DoBlue;
		}
		acolor[max-1].red = acolor[max-1].green = acolor[max-1].blue
					= 0xffff;
		XStoreColors(d->d,d->cmap,acolor,max);

		get_mask_info(&mul,&max,&shift,d->visual->red_mask);
		for ( i = 0 ; i < max ; i ++ ) {
			acolor[i].pixel = i*mul;
			acolor[i].red = acolor[i].green = acolor[i].blue
					= i*shift;
			acolor[i].flags = DoRed;
		}
		acolor[max-1].red = acolor[max-1].green = acolor[max-1].blue
					= 0xffff;
		XStoreColors(d->d,d->cmap,acolor,max);
		get_mask_info(&mul,&max,&shift,d->visual->green_mask);
		for ( i = 0 ; i < max ; i ++ ) {
			acolor[i].pixel = i*mul;
			acolor[i].red = acolor[i].green = acolor[i].blue
				= i*shift;
			acolor[i].flags = DoGreen;
		}
		acolor[max-1].red = acolor[max-1].green = acolor[max-1].blue
					= 0xffff;
		XStoreColors(d->d,d->cmap,acolor,max);
		XInstallColormap(d->d,d->cmap);
	}

	d_f_ree(acolor);

	/* for string_pic usable character set search */

	d->wct = new_wct();
	d->font_work = new_wct();

	d->win_list = 0;

	v_get_font(&d->jisx0201,d,"*-medium-r-*-%s-*-jisx0201-*");
	v_get_font(&d->jisx0208_1978,d,"*-medium-r-*-%s-*-jisx0208.1978-*");
	v_get_font(&d->jisx0208_1983,d,"*-medium-r-*-%s-*-jisx0208.1983-*");
	v_get_font(&d->jisx0208_1990,d,"*-medium-r-*-%s-*-jisx0208.1990-*");
	v_get_font(&d->jisx0212_1990,d,"*-medium-r-*-%s-*-jisx0212.1990-*");
	v_get_font(&d->iso8859_1,d,"*-medium-i-*-%s-*-iso8859-1*");
	v_get_font(&d->iso8859_2,d,"*-%s-*-iso8859-2*");
	v_get_font(&d->iso8859_3,d,"*-%s-*-iso8859-3*");
	v_get_font(&d->iso8859_4,d,"*-%s-*-iso8859-4*");
	v_get_font(&d->iso8859_5,d,"*-%s-*-iso8859-5*");
	v_get_font(&d->iso8859_6,d,"*-%s-*-iso8859-6*");
	v_get_font(&d->iso8859_7,d,"*-%s-*iso8859-7*");
	v_get_font(&d->iso8859_8,d,"*-%s-*iso8859-8*");
	v_get_font(&d->iso8859_9,d,"*-%s-*iso8859-9*");
	v_get_font(&d->iso8859_10,d,"*-%s-*iso8859-10*");
	v_get_font(&d->iso8859_11,d,"*-%s-*iso8859-11*");
	v_get_font(&d->iso8859_12,d,"*-%s-*iso8859-12*");
	v_get_font(&d->iso8859_13,d,"*-%s-*iso8859-13*");
	v_get_font(&d->iso8859_14,d,"*-%s-*iso8859-14*");
	v_get_font(&d->iso8859_15,d,"*-%s-*iso8859-15*");

	/* latin-1 */

	fbm = 0;
	if ( d->iso8859_1.fontname ) {
		set_wct(d->font_work,
			0,
			LCZM_1B_TYPE,
			0,&d->iso8859_1);
		fbm |= LCB_ISO8859_1;
	}
	if ( d->iso8859_2.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_2,
			LCZM_1B_TYPE,
			0,&d->iso8859_2);
		fbm |= LCB_ISO8859_2;
	}
	if ( d->iso8859_3.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_3,
			LCZM_1B_TYPE,
			0,&d->iso8859_3);
		fbm |= LCB_ISO8859_3;
	}
	if ( d->iso8859_4.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_4,
			LCZM_1B_TYPE,
			0,&d->iso8859_4);
		fbm |= LCB_ISO8859_4;
	}
	if ( d->iso8859_5.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_5,
			LCZM_1B_TYPE,
			0,&d->iso8859_5);
		fbm |= LCB_ISO8859_5;
	}
	if ( d->iso8859_6.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_6,
			LCZM_1B_TYPE,
			0,&d->iso8859_6);
		fbm |= LCB_ISO8859_6;
	}
	if ( d->iso8859_7.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_7,
			LCZM_1B_TYPE,
			0,&d->iso8859_7);
		fbm |= LCB_ISO8859_7;
	}
	if ( d->iso8859_8.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_8,
			LCZM_1B_TYPE,
			0,&d->iso8859_8);
		fbm |= LCB_ISO8859_8;
	}
	if ( d->iso8859_9.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_9,
			LCZM_1B_TYPE,
			0,&d->iso8859_9);
		fbm |= LCB_ISO8859_9;
	}
	if ( d->iso8859_10.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_10,
			LCZM_1B_TYPE,
			0,&d->iso8859_10);
		fbm |= LCB_ISO8859_10;
	}
	if ( d->iso8859_13.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_13,
			LCZM_1B_TYPE,
			0,&d->iso8859_13);
		fbm |= LCB_ISO8859_13;
	}
	if ( d->iso8859_14.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_14,
			LCZM_1B_TYPE,
			0,&d->iso8859_14);
		fbm |= LCB_ISO8859_14;
	}
	if ( d->iso8859_15.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_ISO8859_15,
			LCZM_1B_TYPE,
			0,&d->iso8859_15);
		fbm |= LCB_ISO8859_15;
	}

	wct_latin(d->wct,fbm);

	/* jp domain font */

	fbm = 0;
	if ( d->jisx0201.fontname ) {
		set_wct(d->font_work,
			LCZ_1BC_JISX0201,
			LCZM_1B_TYPE,
			0,&d->jisx0201);
		fbm |= LCB_JISX0201;
	}
	if ( d->jisx0208_1978.fontname ) {
		set_wct(d->font_work,
			LCZ_2BC_JISX0208_1978,
			LCZM_2B_TYPE,
			0,&d->jisx0208_1978);
		fbm |= LCB_JISX0208_1978;
	}
	if ( d->jisx0208_1983.fontname ) {
		set_wct(d->font_work,
			LCZ_2BC_JISX0208_1983,
			LCZM_2B_TYPE,
			0,&d->jisx0208_1983);
		fbm |= LCB_JISX0208_1983;
	}
	if ( d->jisx0208_1990.fontname ) {
		set_wct(d->font_work,
			LCZ_2BC_JISX0208_1990,
			LCZM_2B_TYPE,
			0,&d->jisx0208_1990);
		fbm |= LCB_JISX0208_1990;
	}
	if ( d->jisx0212_1990.fontname ) {
		set_wct(d->font_work,
			LCZ_2BC_JISX0212_1990,
			LCZM_2B_TYPE,
			0,&d->jisx0212_1990);
		fbm |= LCB_JISX0212_1990;
	}
	wct_jp(d->wct,fbm);

	/* unicode */

	wct_unicode(d->wct);

	d->font_flag = 1;

	buf->err->err1 = E_OK;
	buf->ret = d;
	ow.ret = 0;
	ow.err = buf->err;
	ow.d = d;
	ow.x = ow.y = 0;
	ow.w = ow.h = 100;
	ow.map = 0;

	_v_open_win(&ow);

	if ( ow.err->err1 != E_OK )
		return 0;

	d->for_string_pic = ow.ret;

	return 0;
}


int _err_handler(Display * dd,XErrorEvent * ev)
{
VDISPLAY * d;
char str[64];
	for ( d = disp_list ; d ; d = d->next )
		if ( d->d == dd )
			break;
	XGetErrorText(dd,ev->error_code,str,64);
	fprintf(stderr,"error Message = %s\n",str);
	fprintf(stderr,"serial = %d\n",ev->serial);
	fprintf(stderr,"error code = %d\n",ev->error_code);
	fprintf(stderr,"request code = %d\n",ev->request_code);
/*
	fprintf(stderr,"minor code = %d\n".ev->minor_code);
*/
	return 0;
}


VDISPLAY *
v_open_disp(VERROR * err)
{
V_OPEN_DISP_S v;
	v.err = err;
	v.ret = 0;
	ms_do(_v_open_disp,&v,"v_open_disp");
	return v.ret;
}
