/**********************************************************************
 
	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	"xl.h"
#include	"memory_debug.h"
#include	"gbview.h"
#include	"xlerror.h"
#include	"jpeg.h"

void
copy_buf_p(unsigned long * buf,
	char * ptr,
	int w,int h)
{
int i;
unsigned char col[3];
unsigned long a;

	for ( i = w*h ; i > 0 ; i -- ) {
		col[0] = *ptr++;
		col[1] = *ptr++;
		col[2] = *ptr++;
		a = (col[0]<<(COL_BIT-8)) +
			((col[1]<<(COL_BIT-8))
				<<COL_BIT) +
			((col[2]<<(COL_BIT-8))
				<<(COL_BIT*2));
		*buf++ = a;
	}
}

void
copy_buf_g(unsigned long * buf,
	char * ptr,
	int w,int h)
{
int i;
unsigned char col;
unsigned long a;

	for ( i = w*h ; i > 0 ; i -- ) {
		col = *ptr++;
		a = (col<<(COL_BIT-8)) +
			((col<<(COL_BIT-8))
				<<COL_BIT) +
			((col<<(COL_BIT-8))
				<<(COL_BIT*2));
		*buf++ = a;
	}
}

int
get_query_r64(
	XL_SEXP ** query_p,
	XL_SEXP ** tmp_p,
	I_RECT * ir,
	TREE_CACHE * 	tc,
	TREE_NODE *	tn)
{
L_CHAR * f;
	*query_p = List(n_get_symbol("Get"),
		get_string(f=get_url_filepath(&tc->r->h.target)),
		get_integer(tn->level,0),
		List(n_get_symbol("List"),
			List(n_get_symbol("List"),
				get_integer(ir->tl.x,0),
				get_integer(ir->tl.y,0),
				-1),
			List(n_get_symbol("List"),
				get_integer(ir->br.x,0),
				get_integer(ir->br.y,0),
				-1),
			-1),
		-1);
	*tmp_p = 0;
	d_f_ree(f);
	return 0;
}

int
get_pixel_r64(
	TREE_CACHE * 	tc,
	TREE_NODE *	tn,
	XL_SEXP *	reply,
	XL_SEXP *	tmp)
{

int w,h;
unsigned long * buf;
int i;
	w = tn->w;
	h = tn->h;

	touch_obj_mem(w*h*sizeof(long)); 
	buf = d_alloc(w*h*sizeof(long),66);
	for ( i = 0 ; i < w*h ; i ++ )
		buf[i] = C_TRANSPARENT;
	if ( tc->r->pr64.type == 'P' )
		copy_buf_p(buf,reply->raw.data,w,h);
	else	copy_buf_g(buf,reply->raw.data,w,h);
	tn->pixels = buf;
	return 0;
}

/*
int
get_pixel_r64(
	unsigned long ** pixels,
	int ses,
	int * width,
	int * height,
	int x,
	int y,
	int level,
	TREE_NODE * parent,
	RESOURCE * r)
{
unsigned long * buf;
int w,h;
int i;

XL_SEXP * ret;
I_RECT ir;
int er;
L_CHAR * f;

	er = 0;
	ir.tl.x = x;
	ir.tl.y = y;
	if ( r->pr64.width[level] >= x + RECT_SIZE )
		w = RECT_SIZE;
	else	w = r->pr64.width[level] - x;
	if ( r->pr64.height[level] >= y + RECT_SIZE )
		h = RECT_SIZE;
	else	h = r->pr64.height[level] - y;
	ir.br.x = x + w;
	ir.br.y = y + h;

	set_inc_status(r,RS_LOAD);
	gc_push(0,0,"pixel_cache");
	ret = remote_session(
		gblisp_top_env0,
		ses,
		&r->h.target,
		l_string(std_cm,"gbr64"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Get"),
		List(List(get_symbol(l_string(std_cm,"Get")),
			get_string(f=get_url_filepath(&r->h.target)),
			get_integer(level,0),
			List(get_symbol(l_string(std_cm,"List")),
				List(get_symbol(l_string(std_cm,"List")),
					get_integer(ir.tl.x,0),
					get_integer(ir.tl.y,0),
					-1),
				List(get_symbol(l_string(std_cm,"List")),
					get_integer(ir.br.x,0),
					get_integer(ir.br.y,0),
					-1),
				-1),
			-1),
			-1),
		0,0);
	d_f_ree(f);
	switch ( get_type(ret) ) {
	case XLT_ERROR:
		fprintf(stderr,"r64 get error ");
		print_sexp(s_stderr,ret,0);

		set_inc_status_error(r,ret);

		fprintf(stderr,"\n");
		er = -1;
		break;
	case XLT_RAW:
		set_inc_status(r,RS_IDLE);
		break;
	default:

		set_inc_status_error(r,
			get_error(
				0,
				0,
				XLE_SEMANTICS_TYPE_MISSMATCH,
				l_string(std_cm,"Get(r64)"),
			n_get_string("server return invalid type data")));

		fprintf(stderr,"r64 get: type missmatch return\n");
		print_sexp(s_stderr,ret,PF_RAW_DISABLE);
		fprintf(stderr,"\n");
		er = -1;
		break;
	}
	gc_pop(0,0);
	if ( er < 0 )
		return er;
	touch_obj_mem(w*h*sizeof(long)); 
	buf = d_alloc(w*h*sizeof(long),66);
	for ( i = 0 ; i < w*h ; i ++ )
		buf[i] = C_TRANSPARENT;
	if ( r->pr64.type == 'P' )
		copy_buf_p(buf,ret->raw.data,w,h);
	else	copy_buf_g(buf,ret->raw.data,w,h);
	*width = w;
	*height = h;
	*pixels = buf;
	return 0;
}

*/

unsigned long *
get_cr_buf(
	I_RECT * ir,
	TREE_NODE * parent,
	XL_SEXP * ret,
	XL_SEXP * query,
	int ww,int hh)
{
unsigned long * buf;
int i;
XL_SEXP * raw, * t, * _x, * _y;
unsigned char * _raw;
int w,h;
unsigned char * dst;
int x,y;
int col[3];
unsigned int pcol[3],pc;
int ix,tix,pix;
int xx,yy,xxx,yyy;

	touch_obj_mem(ww*hh*sizeof(long)); 
	buf = d_alloc(ww*hh*sizeof(long),67);
	for ( i = 0 ; i < ww*hh ; i ++ )
		buf[i] = C_TRANSPARENT;
	for ( ; get_type(ret) == XLT_PAIR ; ret = cdr(ret) , 
				query = cdr(query) ) {
		t = car(query);
		_x = get_el(t,0);
		_y = get_el(t,1);
		xx = _x->integer.data;
		yy = _y->integer.data;
		_x = get_el(t,2);
		_y = get_el(t,3);
		xxx = _x->integer.data;
		yyy = _y->integer.data;

		raw = car(ret);
		if ( get_type(raw) != XLT_RAW )
{
ss_printf("RAW %i\n",get_type(raw));
if ( get_type(raw) == XLT_ERROR ) {
print_sexp(s_stdout,raw,0);
ss_printf("\n");
}
			continue;
}
		_raw = raw->raw.data;
		switch ( _raw[0] ) {
		case 'n':
			dst = none_uncompress(
				&w,&h,&_raw[4],
				raw->raw.size - 4);
			break;
		case 'j':
			dst = jpeg_uncompress(
				&w,&h,&_raw[4],
				raw->raw.size - 4);
			break;
		default:
			printf("get_cr_buf unsupport type %c\n",_raw[0]);
			continue;
		}
		if ( dst == 0 )
			continue;
		if ( parent ) {
			for ( x = 0 ; x < w ; x ++ )
				for ( y = 0 ; y < h ; y ++ ) {
					ix = x + y*w;
					tix = x + xx + (y + yy)*ww;
					pix = (((x + xxx)>>1)
							%RECT_SIZE)
						+ (((y + yyy)>>1)
							%RECT_SIZE)*
						parent->w;

					col[0] = cr_inv_cal(dst[ix*4],
						_raw[1]);
					col[1] = cr_inv_cal(dst[ix*4 + 1],
						_raw[2]);
					col[2] = cr_inv_cal(dst[ix*4 + 2],
						_raw[3]);


					pc = parent->pixels[pix];
					pcol[0] = pc&COL_MASK;
					pcol[1] = (pc>>COL_BIT)&COL_MASK;
					pcol[2] = (pc>>(COL_BIT*2))
							&COL_MASK;
					pcol[0] >>= COL_BIT-8;
					pcol[1] >>= COL_BIT-8;
					pcol[2] >>= COL_BIT-8;

					col[0] = (pcol[0] + col[0]);
					col[1] = (pcol[1] + col[1]);
					col[2] = (pcol[2] + col[2]);


					if ( col[0] >= 256 )
						col[0] = 255;
					if ( col[1] >= 256 )
						col[1] = 255;
					if ( col[2] >= 256 )
						col[2] = 255;
					if ( col[0] < 0 )
						col[0] = 0;
					if ( col[1] < 0 )
						col[1] = 0;
					if ( col[2] < 0 )
						col[2] = 0;

					col[0] <<= COL_BIT-8;
					col[1] <<= COL_BIT-8;
					col[2] <<= COL_BIT-8;

					buf[tix]
						= col[0] +
						(col[1]<<COL_BIT) +
						(col[2]<<(COL_BIT*2));
			}
		}
		else {
			for ( x = 0 ; x < w ; x ++ )
				for ( y = 0 ; y < h ; y ++ ) {
					ix = x + y*w;
					tix = x + xx + (y + yy)*ww;

					col[0] = dst[ix*4];
					col[1] = dst[ix*4 + 1];
					col[2] = dst[ix*4 + 2];

					col[0] <<= COL_BIT-8;
					col[1] <<= COL_BIT-8;
					col[2] <<= COL_BIT-8;

					buf[tix]
						= col[0] +
						(col[1]<<COL_BIT) +
						(col[2]<<(COL_BIT*2));
			}
		}
		free(dst);
	}
	return buf;
}

int
get_query_cr(
	XL_SEXP ** query_p,
	XL_SEXP ** tmp_p,
	I_RECT * ir,
	TREE_CACHE * 	tc,
	TREE_NODE *	tn)
{
RESOURCE * r;
XL_SEXP * query,* query_tmp;
int rect_size;
L_CHAR * f;
int _x,_y;
int xx,yy;
int level;
XL_SEXP * ret;
void gc_gb_sexp();
	r = tc->r;
	level = tn->level;
	switch ( r->pr64.type ) {
	case '0':
		rect_size = 64;
		break;
	case '1':
		rect_size = 128;
		break;
	case '2':
		rect_size = 256;
		break;
	default:
		er_panic("get_pixel_cr(1)");
	}

	gc_push(0,0,"get_pixel_cr");
	query = 0;
	query_tmp = 0;
	f = get_url_filepath(&r->h.target);
	for ( _x = 0 ; _x < RECT_SIZE ; _x += rect_size )
		for ( _y = 0 ; _y < RECT_SIZE ; _y += rect_size ) {
			xx = ir->tl.x + _x;
			if ( xx >= ir->br.x )
				continue;
			yy = ir->tl.y + _y;
			if ( yy >= ir->br.y )
				continue;

			query = cons(
				List(n_get_symbol("Get"),
					get_string(f),
					get_integer(level,0),
					get_integer(xx,0),
					get_integer(yy,0),
					-1),
				query);
			query_tmp = cons(
				List(
					get_integer(_x,0),
					get_integer(_y,0),
					get_integer(xx,0),
					get_integer(yy,0),
					-1),
				query_tmp);
		}
	d_f_ree(f);
	query = cons(n_get_symbol("List"),query);

	*query_p = query;
	*tmp_p = query_tmp;
	ret = List(query,query_tmp,-1);
	gc_pop(ret,gc_gb_sexp);
	return 0;
}


int
get_pixel_cr(
	TREE_CACHE * 	tc,
	TREE_NODE *	tn,
	XL_SEXP *	reply,
	XL_SEXP *	tmp)
{
TREE_NODE * parent;
I_RECT ir;
int w,h;

	if ( tc->rt != tn ) {
		parent = tn->parent;
		if ( parent->pixels == 0 ) {
			tn->flags |= TNF_ERROR;
ss_printf("CR ERR %x (%x) %i %x\n",tn,parent,parent->lock,parent->flags);
			return -1;
		}
	}
	else	parent = 0;
	ir.tl.x = tn->ofs_x;
	ir.tl.y = tn->ofs_y;
	w = tn->w;
	h = tn->h;
	ir.br.x = tn->ofs_x + w;
	ir.br.y = tn->ofs_y + h;
	tn->pixels = get_cr_buf(&ir,parent,reply,tmp,w,h);
if ( tn->pixels == 0 )
ss_printf("CR ZERO\n");
	tn->flags &= ~TNF_ERROR;
	return 0;
}

/*
int
get_pixel_cr(
	unsigned long ** pixels,
	int ses,
	int * width,
	int * height,
	int x,
	int y,
	int level,
	TREE_NODE * parent,
	RESOURCE * r)
{
unsigned long * buf;
int w,h;
int i;

XL_SEXP * ret;
I_RECT ir;
int er;
int rect_size;
int _x,_y,xx,yy;
XL_SEXP * query;
XL_SEXP * query_tmp;
L_CHAR * f;

	er = 0;
	ir.tl.x = x;
	ir.tl.y = y;
	if ( r->pr64.width[level] >= x + RECT_SIZE )
		w = RECT_SIZE;
	else	w = r->pr64.width[level] - x;
	if ( r->pr64.height[level] >= y + RECT_SIZE )
		h = RECT_SIZE;
	else	h = r->pr64.height[level] - y;
	ir.br.x = x + w;
	ir.br.y = y + h;

	switch ( r->pr64.type ) {
	case '0':
		rect_size = 64;
		break;
	case '1':
		rect_size = 128;
		break;
	case '2':
		rect_size = 256;
		break;
	default:
		er_panic("get_pixel_cr(1)");
	}

	gc_push(0,0,"get_pixel_cr");
	query = 0;
	query_tmp = 0;
	f = get_url_filepath(&r->h.target);
	for ( _x = 0 ; _x < RECT_SIZE ; _x += rect_size )
		for ( _y = 0 ; _y < RECT_SIZE ; _y += rect_size ) {
			xx = ir.tl.x + _x;
			if ( xx >= ir.br.x )
				continue;
			yy = ir.tl.y + _y;
			if ( yy >= ir.br.y )
				continue;

			query = cons(
				List(n_get_symbol("Get"),
					get_string(f),
					get_integer(level,0),
					get_integer(xx,0),
					get_integer(yy,0),
					-1),
				query);
			query_tmp = cons(
				List(
					get_integer(_x,0),
					get_integer(_y,0),
					get_integer(xx,0),
					get_integer(yy,0),
					-1),
				query_tmp);
		}
	d_f_ree(f);
	query = cons(n_get_symbol("List"),query);

	set_inc_status(r,RS_LOAD);
	ret = remote_session(
		gblisp_top_env0,
		ses,
		&r->h.target,
		l_string(std_cm,"gbr64"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Get"),
		List(query,-1),
		0,0);
	switch ( get_type(ret) ) {
	case XLT_ERROR:
		fprintf(stderr,"CR get error ");
		print_sexp(s_stderr,ret,0);

		set_inc_status_error(r,ret);

		fprintf(stderr,"\n");
		er = -1;
		break;
	case XLT_PAIR:
		set_inc_status(r,RS_IDLE);

		break;
	default:

		set_inc_status_error(r,
			get_error(
				0,
				0,
				XLE_SEMANTICS_TYPE_MISSMATCH,
				l_string(std_cm,"Get(CR)"),
			n_get_string("server return invalid type data")));

		fprintf(stderr,"CR get: type missmatch return\n");
		print_sexp(s_stderr,ret,PF_RAW_DISABLE);
		fprintf(stderr,"\n");
		er = -1;
		break;
	}

	if ( er < 0 ) {
		gc_pop(0,0);
		return er;
	}
	buf = get_cr_buf(&ir,parent,ret,query_tmp,w,h);

	gc_pop(0,0);
	*width = w;
	*height = h;
	*pixels = buf;
	return 0;
}


*/


