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

void clear_line(VIMAGE * obj,VPOINT st,VPOINT end,int mode);



int
_v_redraw_image(void * arg)
{
VIMAGE * vi;
	vi = (VIMAGE *)arg;

	XPutImage(
		vi->_h.win->d->d,
		vi->_h.win->w,
		vi->_h.win->gc,
		vi->ximage,
		0,0,
		vi->x,
		vi->y,
		vi->w,
		vi->h);

	if ( vi->select_flag ) {
	VPOINT st,end;
		st = vi->select[0];
		end = st;
		end.x = vi->select[1].x;
		clear_line(vi,st,end,1);
		st = end;
		end = vi->select[1];
		clear_line(vi,st,end,1);
		st = end;
		end.x = vi->select[0].x;
		clear_line(vi,st,end,1);
		st = end;
		end = vi->select[0];
		clear_line(vi,st,end,1);
	}
	return 0;
}

void
v_redraw_image(VIMAGE * vi)
{
	ms_do(_v_redraw_image, (void *)vi, "v_redraw_image");
}

void
v_image_handler(
	VOBJECT *	obj,
	int		cmd)
{
	switch ( cmd ) {
	case VE_REDRAW:
		v_redraw_image(&obj->vimage);
		break;
	case VE_BUTTON:
		break;
	default:
		fprintf(stderr,"v_image::unsupport cmd %i\n",cmd);
	}
}


typedef struct v_create_image_s {
	VERROR *	err;
	VOBJECT *	ret;

	VWINDOW *	win;
	int		x;
	int 		y;
	int		w;
	int		h;
} V_CREATE_IMAGE_S;


int
_v_create_image(V_CREATE_IMAGE_S * v)
{
VOBJECT * obj;
VWINDOW *	win;
int		x;
int 		y;
int		w;
int		h;

	win = v->win;
	x = v->x;
	y = v->y;
	w = v->w;
	h = v->h;

	obj = d_alloc(sizeof(VIMAGE),200);
	obj->vimage.select_flag = 0;
	obj->vimage.ximage = XCreateImage(
			win->d->d,
			win->d->visual,
			win->d->depth,
			ZPixmap,
			0,
			0,
			w,
			h,
			win->d->gb2m_map.pixel_bits,
			0);
	free(obj->vimage.ximage->data);
	obj->vimage.buf_8 = 0;
	obj->vimage.buf_16 = 0;
	obj->vimage.buf_32 = 0;
	obj->vimage.ximage->data = d_alloc(
		win->d->gb2m_map.pixel_bits/8 * w*h,211);
	switch ( win->d->gb2m_map.pixel_bits ) {
	case 8:
		obj->vimage.buf_8 = 
			(char*)obj->vimage.ximage->data;
		break;
	case 16:
		obj->vimage.buf_16 = 
			(short*)obj->vimage.ximage->data;
		break;
	case 32:
		obj->vimage.buf_32 = 
			(long*)obj->vimage.ximage->data;
		break;
	default:
		er_panic("pixelbytes");
	}
	obj->vimage.ximage->xoffset = 0;
	
printf("aaa %x %i %i %i %i %i %i- %i\n",
obj->vimage.ximage->data,
obj->vimage.ximage->byte_order,
obj->vimage.ximage->bitmap_unit,
obj->vimage.ximage->bitmap_bit_order,
obj->vimage.ximage->bitmap_pad,
obj->vimage.ximage->bytes_per_line,
obj->vimage.ximage->bits_per_pixel,
MSBFirst);
	obj->vimage.w = w;
	obj->vimage.h = h;
	obj->vimage.x = x;
	obj->vimage.y = y;
	obj->vimage.w_border = w;
	obj->header.type = VT_IMAGE;
	obj->header.handler = v_image_handler;
	obj->header.win = win;
	obj->header.next = win->obj_list;
	win->obj_list = obj;

	v->err->err1 = E_OK;
	v->ret = obj;
	return 0;
}


VOBJECT *
v_create_image(VERROR * err,
	VWINDOW *	win,
	int		x,
	int 		y,
	int		w,
	int		h)
{
V_CREATE_IMAGE_S v;
	v.win = win;
	v.x = x;
	v.y = y;
	v.w = w;
	v.h = h;

	v.ret = 0;
	v.err = err;
	ms_do(_v_create_image,&v,"v_create_image");
	return v.ret;
}

void
v_set_image(VERROR * err,
	VOBJECT *	obj,
	int		x,
	int 		y,
	int		w,
	int		h)
{
int size1,size2;
long * buf_32;
short * buf_16;
char * buf_8;
int i,j,minh;
int pixelbits;
	pixelbits = obj->header.win->d->gb2m_map.pixel_bits;

	if ( h != obj->vimage.h || w != obj->vimage.w )
		obj->vimage.select_flag = 0;
	size1 = obj->vimage.w*obj->vimage.h;
	size2 = w*h;
	minh = h < obj->vimage.h ? h : obj->vimage.h;
	switch ( pixelbits ) {
	case 32:
		if ( size1 < size2 )
			buf_32 = d_re_alloc(obj->vimage.buf_32,size2*
					sizeof(long));
		else	buf_32 = obj->vimage.buf_32;
		if ( w < obj->vimage.w ) {
			for ( i = 1 ; i < minh ; i ++ )
				for ( j = 0 ; j < w ; j ++ )
					buf_32[i*w+j] 
						= buf_32[i*obj->vimage.w+j];
		}
		else if ( w > obj->vimage.w ) {
			for ( i = minh-1 ; i >= 0 ; i -- )
				for ( j = obj->vimage.w-1;
						j >= 0;
						j -- )
					buf_32[i*w+j] 
						= buf_32[i*obj->vimage.w+j];
		}
		if ( size1 > size2 )
			buf_32 = d_re_alloc(buf_32,size2*sizeof(long));
		obj->vimage.buf_32 = buf_32;
		obj->vimage.ximage->data
			= (char*)obj->vimage.buf_32;
		obj->vimage.ximage->bytes_per_line = w*sizeof(long);
		break;
	case 16:
		if ( size1 < size2 )
			buf_16 = d_re_alloc(obj->vimage.buf_16,size2*
					sizeof(short));
		else	buf_16 = obj->vimage.buf_16;
		if ( w < obj->vimage.w ) {
			for ( i = 1 ; i < minh ; i ++ )
				for ( j = 0 ; j < w ; j ++ )
					buf_16[i*w+j] 
						= buf_16[i*obj->vimage.w+j];
		}
		else if ( w > obj->vimage.w ) {
			for ( i = minh-1 ; i >= 0 ; i -- )
				for ( j = obj->vimage.w-1;
						j >= 0;
						j -- )
					buf_16[i*w+j] 
						= buf_16[i*obj->vimage.w+j];
		}
		if ( size1 > size2 )
			buf_16 = d_re_alloc(buf_16,size2*sizeof(short));
		obj->vimage.buf_16 = buf_16;
		obj->vimage.ximage->data
			= (char*)obj->vimage.buf_16;
		obj->vimage.ximage->bytes_per_line = w*sizeof(short);
		break;
	case 8:
		if ( size1 < size2 )
			buf_8 = d_re_alloc(obj->vimage.buf_8,size2*
					sizeof(char));
		else	buf_8 = obj->vimage.buf_8;
		if ( w < obj->vimage.w ) {
			for ( i = 1 ; i < minh ; i ++ )
				for ( j = 0 ; j < w ; j ++ )
					buf_8[i*w+j] 
						= buf_8[i*obj->vimage.w+j];
		}
		else if ( w > obj->vimage.w ) {
			for ( i = minh-1 ; i >= 0 ; i -- )
				for ( j = obj->vimage.w-1;
						j >= 0;
						j -- )
					buf_8[i*w+j] 
						= buf_8[i*obj->vimage.w+j];
		}
		if ( size1 > size2 )
			buf_8 = d_re_alloc(buf_8,size2*sizeof(char));
		obj->vimage.buf_8 = buf_8;
		obj->vimage.ximage->data
			= (char*)obj->vimage.buf_8;
		obj->vimage.ximage->bytes_per_line = w*sizeof(char);
		break;
	default:
		er_panic("v_set_image");
	}
	obj->vimage.w = w;
	obj->vimage.h = h;
	obj->vimage.x = x;
	obj->vimage.y = y;
	obj->vimage.w_border = w;

	obj->vimage.ximage->width = w;
	obj->vimage.ximage->height = h;
	obj->vimage.ximage->xoffset = 0;
	
	err->err1 = E_OK;
}

int
v_image_minrect(VRECT * r,VOBJECT * obj)
{
	r->tl.x = obj->vimage.x;
	r->tl.y = obj->vimage.y;
	r->br.x = obj->vimage.x + obj->vimage.w;
	r->br.y = obj->vimage.y + obj->vimage.h;
	return 0;
}


typedef struct v_select_box_s {
	VIMAGE * 	obj;
	int		select_flag;
	VPOINT		select[2];
} V_SELECT_BOX_S;

void
clear_line(VIMAGE * obj,VPOINT st,VPOINT end,int mode)
{
XImage * xi;
int length;
VPOINT pt;
int x,y,i;
int w,h;
long * data_32;
short * data_16;
char * data_8;
long mask;
	if ( st.x == end.x ) {
		if ( end.y < st.y ) {
			pt = st;
			st = end;
			end = pt;
		}
		length = end.y - st.y + 1;
		w = 1;
		h = length;
	}
	else if ( st.y == end.y ) {
		if ( end.x < st.x ) {
			pt = st;
			st = end;
			end = pt;
		}
		length = end.x - st.x + 1;
		w = length;
		h = 1;
	}
	else	er_panic("clear_line");
	mask = obj->_h.win->d->gb2m_map.red_mask|
		obj->_h.win->d->gb2m_map.green_mask|
		obj->_h.win->d->gb2m_map.blue_mask;
	xi = XCreateImage(
			obj->_h.win->d->d,
			obj->_h.win->d->visual,
			obj->_h.win->d->depth,
			ZPixmap,
			0,
			0,
			w,
			h,
			obj->_h.win->d->gb2m_map.pixel_bits,
			0);
	free(xi->data);

	switch ( obj->_h.win->d->gb2m_map.pixel_bits ) {
	case 32:
		data_32 = d_alloc(sizeof(long)*length,212);
		xi->data = (char*)data_32;

		i = 0;
		if ( st.x == end.x ) {
			i = 0;
			for ( y = st.y ; y <= end.y ; y ++ )
				data_32[i++] = obj->buf_32[st.x + y*obj->w];
		}
		else {
			i = 0;
			for ( x = st.x ; x <= end.x ; x ++ )
				data_32[i++] = obj->buf_32[x + st.y*obj->w];
		}
		xi->width = w;
		xi->height = h;
		if ( mode )
			for ( i = 0 ; i < length ; i ++ )
				data_32[i] = (~data_32[i])&mask;
		break;
	case 16:
		data_16 = d_alloc(sizeof(short)*length,212);
		xi->data = (char*)data_16;

		i = 0;
		if ( st.x == end.x ) {
			i = 0;
			for ( y = st.y ; y <= end.y ; y ++ )
				data_16[i++] = obj->buf_16[st.x + y*obj->w];
		}
		else {
			i = 0;
			for ( x = st.x ; x <= end.x ; x ++ )
				data_16[i++] = obj->buf_16[x + st.y*obj->w];
		}
		xi->width = w;
		xi->height = h;
		if ( mode )
			for ( i = 0 ; i < length ; i ++ )
				data_16[i] = (~data_16[i])&mask;
		break;
	case 8:
		data_8 = d_alloc(sizeof(char)*length,212);
		xi->data = (char*)data_8;

		i = 0;
		if ( st.x == end.x ) {
			i = 0;
			for ( y = st.y ; y <= end.y ; y ++ )
				data_8[i++] = obj->buf_8[st.x + y*obj->w];
		}
		else {
			i = 0;
			for ( x = st.x ; x <= end.x ; x ++ )
				data_8[i++] = obj->buf_8[x + st.y*obj->w];
		}
		xi->width = w;
		xi->height = h;
		if ( mode )
			for ( i = 0 ; i < length ; i ++ )
				data_8[i] = (~data_8[i])&mask;
		break;
	default:
		er_panic("clear_line");
	}
	XPutImage(
		obj->_h.win->d->d,
		obj->_h.win->w,
		obj->_h.win->gc,
		xi,
		0,0,
		st.x,
		st.y,
		w,
		h);
	d_f_ree(xi->data);
	xi->data = 0;
	XDestroyImage(xi);
}


int
_v_select_box(V_SELECT_BOX_S * v)
{
VPOINT st,end;

	if ( v->obj->select_flag ) {
		st = end = v->obj->select[0];
		end.x = v->obj->select[1].x;
		clear_line(v->obj,st,end,0);
		st = end;
		end = v->obj->select[1];
		clear_line(v->obj,st,end,0);
		st = end;
		end.x = v->obj->select[0].x;
		clear_line(v->obj,st,end,0);
		st = end;
		end = v->obj->select[0];
		clear_line(v->obj,st,end,0);
	}
	if ( v->select_flag ) {
		v->obj->select_flag = 1;
		st = v->select[0];
		if ( st.x < v->obj->x )
			st.x = v->obj->x;
		if ( st.x >= v->obj->x + v->obj->w )
			st.x = v->obj->x + v->obj->w - 1;
		if ( st.y < v->obj->y )
			st.y = v->obj->y;
		if ( st.y >= v->obj->y + v->obj->h )
			st.y = v->obj->y + v->obj->h - 1;
		end = v->select[1];
		if ( end.x < v->obj->x )
			end.x = v->obj->x;
		if ( end.x >= v->obj->x + v->obj->w )
			end.x = v->obj->x + v->obj->w - 1;
		if ( end.y < v->obj->y )
			end.y = v->obj->y;
		if ( end.y >= v->obj->y + v->obj->h )
			end.y = v->obj->y + v->obj->h - 1;
		v->obj->select[0] = st;
		v->obj->select[1] = end;
		end = st;
		end.x = v->obj->select[1].x;
		clear_line(v->obj,st,end,1);
		st = end;
		end = v->obj->select[1];
		clear_line(v->obj,st,end,1);
		st = end;
		end.x = v->obj->select[0].x;
		clear_line(v->obj,st,end,1);
		st = end;
		end = v->obj->select[0];
		clear_line(v->obj,st,end,1);
	}
	else	v->obj->select_flag = 0;
	XFlush(v->obj->_h.win->d->d);
	return 0;
}


int
v_select_box(VOBJECT * obj,VPOINT st,VPOINT end,int flag)
{
V_SELECT_BOX_S v;
	v.obj = &obj->vimage;
	v.select[0] = st;
	v.select[1] = end;
	v.select_flag = flag;
	ms_do(_v_select_box,&v,"v_select_box");
	return 0;
}

typedef struct v_part_redraw_image {
	VOBJECT * 	obj;
	int		x;
	int		y;
	int		w;
	int		h;
} V_PART_REDRAW_IMAGE;


int
_v_part_redraw_image(V_PART_REDRAW_IMAGE * v)
{
	XPutImage(
		v->obj->header.win->d->d,
		v->obj->header.win->w,
		v->obj->header.win->gc,
		v->obj->vimage.ximage,
		v->x,v->y,
		v->obj->vimage.x + v->x,
		v->obj->vimage.y + v->y,
		v->w,
		v->h);
	XFlush(v->obj->header.win->d->d);
	return 0;
}


void
v_part_redraw_image(VOBJECT * obj,int x,int y,int w,int h)
{
V_PART_REDRAW_IMAGE v;
	v.obj = obj;
	v.x = x;
	v.y = y;
	v.w = w;
	v.h = h;
	ms_do(_v_part_redraw_image,&v,"v_part_redraw_image");
}

typedef struct v_scroll_image {
	VOBJECT *	obj;
	int		dx;
	int		dy;
} V_SCROLL_IMAGE;

int
_v_scroll_image(V_SCROLL_IMAGE * v)
{
int w,h,src_x,src_y,dest_x,dest_y;
int dx,dy;
VRECT r1,r2;
VOBJECT * obj;
	dx = v->dx;
	dy = v->dy;
	obj = v->obj;
	if ( dx < 0 ) {
		if ( -dx >= obj->vimage.w )
			goto all;
		w = obj->vimage.w + dx;
		src_x = -dx;
		dest_x = 0;
		r1.tl.x = w;
		r1.tl.y = 0;
		r1.br.x = obj->vimage.w;
		r1.br.y = obj->vimage.h;
	}
	else {
		if ( dx >= obj->vimage.w )
			goto all;
		w = obj->vimage.w - dx;
		src_x = 0;
		dest_x = dx;
		r1.tl.x = 0;
		r1.tl.y = 0;
		r1.br.x = dx;
		r1.br.y = obj->vimage.h;
	}
	if ( dy < 0 ) {
		if ( -dy >= obj->vimage.h )
			goto all;
		h = obj->vimage.h + dy;
		src_y = -dy;
		dest_y = 0;
		r1.br.y = h;

		r2.tl.x = 0;
		r2.tl.y = h;
		r2.br.x = obj->vimage.w;
		r2.br.y = obj->vimage.h;
	}
	else {
		if ( dy >= obj->vimage.h )
			goto all;
		h = obj->vimage.h - dy;
		src_y = 0;
		dest_y = dy;

		r1.tl.y = dy;

		r2.tl.x = 0;
		r2.tl.y = 0;
		r2.br.x = obj->vimage.w;
		r2.br.y = dy;
	}
	XCopyArea(obj->header.win->d->d,
		obj->header.win->w,
		obj->header.win->w,
		obj->header.win->gc,	
		src_x,src_y,
		w,h,
		dest_x,dest_y);
	v_part_redraw_image(obj,
		r1.tl.x,
		r1.tl.y,
		r1.br.x - r1.tl.x,
		r1.br.y - r1.tl.y);
	v_part_redraw_image(obj,
		r2.tl.x,
		r2.tl.y,
		r2.br.x - r2.tl.x,
		r2.br.y - r2.tl.y);
	XFlush(v->obj->header.win->d->d);
	return 0;
all:
	v_redraw_image(&obj->vimage);
	return 0;
}

void
v_scroll_image(VOBJECT * obj,int dx,int dy)
{
V_SCROLL_IMAGE v;
	v.obj = obj;
	v.dx = dx;
	v.dy = dy;
	ms_do(_v_scroll_image,&v,"v_scroll_image");
}


typedef struct v_gn {
	void *		buf;
	int		element_size;
	VOBJECT * 	obj;
} V_GN;

int
_v_get_and_new_image(void * arg)
{
V_GN * v;
	v = arg;
	if ( v->obj->vimage.buf_32 ) {
		v->buf = v->obj->vimage.buf_32;
		v->element_size = sizeof(long);
		v->obj->vimage.buf_32 = d_alloc(sizeof(long)*
				v->obj->vimage.w*
				v->obj->vimage.h,125);
		v->obj->vimage.ximage->data = (char*)v->obj->vimage.buf_32;
	}
	else if ( v->obj->vimage.buf_16 ) {
		v->buf = v->obj->vimage.buf_16;
		v->element_size = sizeof(short);
		v->obj->vimage.buf_16 = d_alloc(sizeof(short)*
				v->obj->vimage.w*
				v->obj->vimage.h,125);
		v->obj->vimage.ximage->data = (char*)v->obj->vimage.buf_16;
	}
	else if ( v->obj->vimage.buf_8 ) {
		v->buf = v->obj->vimage.buf_8;
		v->element_size = sizeof(char);
		v->obj->vimage.buf_8 = d_alloc(sizeof(char)*
				v->obj->vimage.w*
				v->obj->vimage.h,125);
		v->obj->vimage.ximage->data = (char*)v->obj->vimage.buf_8;
	}
	else {
		er_panic("_v_get_and_new_image");
	}
	return 0;
}

void *
v_get_and_new_image(int * element_size,VOBJECT * obj)
{
V_GN v;
	v.buf = 0;
	v.element_size = 0;
	v.obj = obj;
	ms_do(_v_get_and_new_image, (void *)&v, "v_get_and_new_image");
	if ( element_size )
		*element_size = v.element_size;
	return v.buf;
}


