/**********************************************************************
 
	Copyright (C) 2005- 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	"matrix.h"
#include	"memory_debug.h"
#include	"jpeg.h"
#include	"r64.h"
#include	"gbparam.h"
#include	"xlerror.h"
#include	"memory_routine.h"

void *
uncompress_cr(
	MATRIX_NODE *	n,
	void *		parent_d,
	XL_SEXP *	net_d);
void *
uncompress_r64(
	XL_SEXP *	net_d);

void
copy_buf_p_of(unsigned long * buf,
	char * ptr,
	int w,int h);
void
copy_buf_g_of(unsigned long * buf,
	char * ptr,
	int w,int h);

XL_SEXP *
xl_mxUncompressOldFormat(XLISP_ENV * env,XL_SEXP * s,XLISP_ENV * a,XL_SYM_FIELD * sf);

void
init_mxUncompressOldFormat(XLISP_ENV * env)
{
	set_env(env,l_string(std_cm,"mxUncompressOldFormat"),
		get_func_prim(xl_mxUncompressOldFormat,FO_APPLICATIVE,0,1,3));
}

/*
unsigned long *
get_cr_buf(
	I_RECT * ir,
	TREE_NODE * parent,
	XL_SEXP * ret,
	XL_SEXP * query,
	int ww,int hh)
*/


/*
net_d = (ww hh ret query)
*/

void *
uncompress_cr(
	MATRIX_NODE *	n,
	void *		parent_d,
	XL_SEXP *	net_d)
{
void * ret_data;
MATRIX_DH_SET rds;
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;

int ww,hh;
MATRIX_DH_SET parent_ds;
XL_SEXP * query,* ret;
int * parent_ptr;
MATRIX_ALLOC_VECTOR_PARAM vp;
int ix_size[2];
int default_data;
int * rd_ptr;

	memset(&parent_ds,0,sizeof(parent_ds));
	if ( parent_d ) {
		get_matrix_dh_set(&parent_ds,parent_d);
		if ( parent_ds.hd->dim != 2 )
			return 0;
		parent_ptr = (int*)parent_ds.offset;
	}
	
	_x = get_el(net_d,0);
	_y = get_el(net_d,1);
	ww = _x->integer.data;
	hh = _y->integer.data;
	query = get_el(net_d,2);
	ret = get_el(net_d,3);

	ix_size[0] = ww;
	ix_size[1] = hh;
	default_data = C_TRANSPARENT;
	vp.dim = 2;
	vp.ix_size = &ix_size[0];
	vp.default_data = &default_data;
	ret_data = (*mx_type_uint32_v.alloc_data)
		(&mx_type_uint32_v,MD_MMALLOC,&vp,0,
		__FILE__,__LINE__);
	get_matrix_dh_set(&rds,ret_data);
	rd_ptr = rds.offset;

	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 = (unsigned char*)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_d ) {
			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_ds.ix[0];

					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_ptr[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;

					rd_ptr[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;

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

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


/*
net_d = (w h type reply)
*/

void
copy_buf_p_of(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_of(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;
	}
}

void *
uncompress_r64(
	XL_SEXP *	net_d)
{
int w,h;

XL_SEXP * _w,* _h,* _type;
XL_SEXP * reply;
MATRIX_ALLOC_VECTOR_PARAM vp;
int ix_size[2];
int default_data;
int * rd_ptr;
void * ret_data;
MATRIX_DH_SET rds;


	_w = get_el(net_d,0);
	_h = get_el(net_d,1);
	_type = get_el(net_d,2);
	reply = get_el(net_d,3);

	w = _w->integer.data;
	h = _h->integer.data;

	ix_size[0] = w;
	ix_size[1] = h;
	default_data = C_TRANSPARENT;
	vp.dim = 2;
	vp.ix_size = &ix_size[0];
	vp.default_data = &default_data;
	ret_data = (*mx_type_uint32_v.alloc_data)
		(&mx_type_uint32_v,MD_MMALLOC,&vp,0,
		__FILE__,__LINE__);
	get_matrix_dh_set(&rds,ret_data);
	rd_ptr = rds.offset;


	if ( _type->string.data[0] == 'P' )
		copy_buf_p_of(rds.offset,reply->raw.data,w,h);
	else	copy_buf_g_of(rds.offset,reply->raw.data,w,h);
	return ret_data;
}



XL_SEXP *
xl_mxUncompressOldFormat(XLISP_ENV * env,XL_SEXP * s,XLISP_ENV * a,XL_SYM_FIELD * sf)
{
L_CHAR * format;
XL_SEXP * this_data;
XL_SEXP * p_data;
MATRIX_TOKEN * t;
void * p;
void * _ret;
XL_SEXP * ret;
INTEGER64 * this_dim_code, * p_dim_code;
XL_SEXP * err;
	t = get_env_work(env);
	if ( t == 0 )
		return 0;
	this_dim_code = p_dim_code = 0;
	err = 0;
	format = get_sf_attribute(sf,l_string(std_cm,"format"));
	if ( list_length(s) == 3 ) {
		this_data = get_el(s,2);
		this_dim_code = get_dim_code_from_sexp(err=get_el(this_data,1));
		if ( this_dim_code == 0 )
			goto type_missmatch;
		this_data = get_el(this_data,2);
		p_data = get_el(s,1);
		p_dim_code = get_dim_code_from_sexp(err=get_el(p_data,1));
		if ( p_dim_code == 0 )
			goto type_missmatch;
		p_data = get_el(p_data,2);
		switch ( get_type(p_data) ) {
		case XLT_PTR:
			p = p_data->ptr.ptr;
			break;
		case XLT_RAW:
			p = p_data->raw.data;
			break;
		default:
			goto type_missmatch;
		}
	}
	else {
		this_data = get_el(s,1);
ss_printf("**** ");
print_sexp(s_stdout,this_data,PF_RAW_DISABLE);
ss_printf("\n");
		this_dim_code = get_dim_code_from_sexp(err=get_el(this_data,1));
		if ( this_dim_code == 0 )
			goto type_missmatch;
		this_data = get_el(this_data,2);
		p_data = 0;
		p = 0;
	}
	if ( format == 0 )
		_ret = uncompress_cr(t->process_node,p,this_data);
	else if ( l_strcmp(format,l_string(std_cm,"CR")) == 0 )
		_ret = uncompress_cr(t->process_node,p,this_data);
	else if ( l_strcmp(format,l_string(std_cm,"R64")) == 0 )
		_ret = uncompress_r64(this_data);
	else	goto inv_param;
	ret = List(
		n_get_symbol("data"),
		get_sexp_from_dim_code(t->process_node->matrix,this_dim_code),
		get_ptr(_ret,gc_text),
		-1);
	goto end;

type_missmatch:
	ret = get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"mxUncompressOldFormat"),
		err);
	goto end;
inv_param:
	ret = get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"mxUncompressOldFormat"),
		n_get_string("invalid parameter in mxUncompressOldFormat"));
	goto end;
	/*
matrix_err:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_OBJECT,
		l_string(std_cm,"mxUncompressOldFormat"),
		n_get_string("invalid matrix loading"));
	*/

end:
	if ( this_dim_code )
		d_f_ree(this_dim_code);
	if ( p_dim_code )
		d_f_ree(p_dim_code);
	return ret;
}





