/**********************************************************************
 
	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomoki SEKIYAMA <sekiyama@yahoo.co.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 <fcntl.h>
#include <stdlib.h>

#include "v/VDraw.h"
#include "v/vobj_utils.h"

extern "C" {
#include "xl.h"
#include "memory_debug.h"
#include "gif.h"
#include "jpeg.h"

#define IMG_FMT_JPEG	1
#define IMG_FMT_GIF	2


int get_image_type(L_CHAR * type);
int get_format_type(L_CHAR * fmt);
unsigned char * load_image_data(L_CHAR * filepath,int * len,L_CHAR * name);
VImage * get_image_from_lchar(XL_SEXP ** retp,XLISP_ENV * env,L_CHAR * filepath,
		L_CHAR * _img_field);
VImage * get_image_from_sf(XL_SEXP ** retp,XLISP_ENV * env,L_CHAR * filepath,
			XL_SYM_FIELD * sf);
XL_SEXP * vobj_VDraw(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);

int
get_image_type(L_CHAR * type)
{
	if ( l_strcmp(type,l_string(std_cm,"raw")) == 0 )
		return 0;
	if ( l_strcmp(type,l_string(std_cm,"file")) == 0 )
		return 1;
	return -1;
}

int
get_format_type(L_CHAR * fmt)
{
int ret;
	if ( l_strcmp(fmt,l_string(std_cm,"jpg")) == 0 )
		ret = IMG_FMT_JPEG;
	else if ( l_strcmp(fmt,l_string(std_cm,"jpeg")) == 0 )
		ret = IMG_FMT_JPEG;
	else if ( l_strcmp(fmt,l_string(std_cm,"gif")) == 0 )
		ret = IMG_FMT_GIF;
	else	ret = -1;
	return ret;
}

unsigned char *
load_image_data(L_CHAR * filepath,int * len,L_CHAR * name)
{
STREAM * s;
int _len;
unsigned char * ret;
L_CHAR * script;
	script = get_script(filepath,name);
	if ( script == 0 )
		return 0;
	s = s_open_file(n_string(std_cm,script),O_RDONLY);
	if ( s == 0 ) {
		d_f_ree(script);
		return 0;
	}
	_len = s_seek_file(s,0,SEEK_END);
	s_seek_file(s,0,SEEK_SET);
	ret = (unsigned char*)d_alloc(_len);
	s_read(s,ret,_len);
	*len = _len;
	d_f_ree(script);
	return ret;
}


VImage *
get_image_from_lchar(XL_SEXP ** retp,XLISP_ENV * env,L_CHAR * filepath,
		L_CHAR * _img_field)
{
VImage * ret;
L_CHAR * img_field;
L_CHAR * p;
L_CHAR * if_arg[4];
int type,format;
// type 0=RAW 1=file
L_CHAR * name;
unsigned char * data;
int i;
XL_SEXP * _img;
int w,h,data_len;
RGB4 * ptr;
unsigned int * raw;
int x,y;
GIF_ENV ge;
int data_free;
	ret = 0;
	*retp = 0;
	data_free = 0;
	img_field = ll_copy_str(_img_field);
	if_arg[0] = img_field;
	i = 1;
	for ( p = img_field ; *p ; p ++ ) {
		if ( *p == ':' ) {
			*p = 0;
			p ++;
			if ( i < 4 )
				if_arg[i++] = p;
		}
	}
	if_arg[i] = 0;
	switch ( i ) {
	case 0:
	case 1:
		ret = 0;
		goto end;
	case 2:
		type = get_image_type(if_arg[0]);
		name = if_arg[1];
		for ( i = l_strlen(name)-1 ; i >= 0 ; i -- )
			if ( name[i] == '.' ) {
				format = get_format_type(&name[i+1]);
				goto ok;
			}
		goto end;
	ok:
		break;
	case 3:
		type = get_image_type(if_arg[0]);
		format = get_format_type(if_arg[1]);
		name = if_arg[2];
		break;
	default:
		er_panic("get_image_from_sf");
	}
	if ( type < 0 || format < 0 ) {
		ret = 0;
		goto end;
	}
	switch ( type ) {
	case 0:
		_img = eval(env,get_symbol(name));
		switch ( get_type(_img) ) {
		case XLT_ERROR:
			*retp = _img;
			goto end;
		case XLT_RAW:
			break;
		default:
			goto end;
		}
		data = (unsigned char*)_img->raw.data;
		data_len = _img->raw.size;
		break;
	case 1:
		data = load_image_data(filepath,&data_len,name);
		if ( data == 0 )
			goto end;
		data_free = 1;
		break;
	default:
		er_panic("get_image_form_sf");
	}
	switch ( format ) {
	case IMG_FMT_GIF:
		raw = gif_uncompress(&w,&h,&ge,data,data_len);
		break;
	case IMG_FMT_JPEG:
		raw = (unsigned int*)jpeg_uncompress(&w,&h,data,data_len);
		break;
	default:
		er_panic("get_image_from_sf");
	}
	ret = v_image_new(w,h,32);
	v_image_draw_start(ret, 0);
	switch ( format ) {
	case IMG_FMT_JPEG:
		for ( x = 0 ; x < w ; x ++ ) {
			for ( y = 0 ; y < h ; y ++ ) {
				ptr = (RGB4*)&raw[x + y*w];
				SET_RGB8_32(ret->buf_32[x + ret->w_border*y],
					ptr->r,ptr->g,ptr->b,RGB8_MAX);
			}
		}
		break;
	default:
		for ( x = 0 ; x < w ; x ++ ) {
			for ( y = 0 ; y < h ; y ++ ) {
				ptr = (RGB4*)&raw[x + y*w];
				SET_RGB8_32(ret->buf_32[x + ret->w_border*y],
					ptr->r,ptr->g,ptr->b,ptr->x);
			}
		}
		break;
	}
	v_image_draw_end(ret);
end:
	if ( data_free )
		d_f_ree(data);
	d_f_ree(img_field);
	return ret;
}

VImage *
get_image_from_sf(XL_SEXP ** retp,XLISP_ENV * env,L_CHAR * filepath,
			XL_SYM_FIELD * sf)
{
L_CHAR * _img_field;
	_img_field = get_sf_attribute(sf,l_string(std_cm,"image"));
	if ( _img_field == 0 )
		return 0;
	return get_image_from_lchar(retp,env,filepath,_img_field);
}

XL_SEXP *
vobj_VDraw(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
XL_SEXP * _ref;
XL_SEXP * img_ret;
VDraw *obj;
VObjectStatus sts;
VImage * img;
L_CHAR *use_alpha;
int flags;

	use_alpha = get_sf_attribute(sf, l_string(std_cm, "use_alpha"));
	if ( use_alpha && atoi(n_string(std_cm, use_alpha)) ) {
		flags = VSF_ATTR;
		sts.attr = VDraw::use_alpha;
	}
	else
		flags = 0;

	img = get_image_from_sf(&img_ret,env,arg->h.file->name,sf);
	if ( img == 0 ) {
		return vobj_get_error(initial_VExError(V_ER_PARAM,0,0),arg);
	}
	sts.min_size = sts.size = img->size;

	_ref = get_refered_object<VDraw>
			(&obj,env,arg,sf,VO_DRAW,"VDraw",&sts,VSF_SIZE|VSF_MIN_SIZE|flags,0);
	if  ( get_type(_ref) == XLT_ERROR ) {
		v_image_unref(img);
		return _ref;
	}

	if ( obj->set_image(img) != V_ER_NO_ERR )
		er_panic("1");
	v_image_unref(img);

	if ( get_type(_ref) == XLT_INTEGER )
		return vobj_get_id_list(_ref->integer.data,0,sf,0);
	return 0;
}

void
init_VDraw(XLISP_ENV *env)
{
	set_env(env,l_string(std_cm,"VDraw"),
		get_func_prim((XL_SEXP*(*)())vobj_VDraw,FO_NORMAL,0,1,1));
}


} // extern "C"
