/**********************************************************************
 
	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 "v/VexDraw.h"

extern "C" {
VImage* v_image_eff_dark(VImage* img);
VImage* v_image_eff_bright(VImage* img);
VImage* v_image_eff_dark_b(VImage* img, VSize border);
VImage* v_image_eff_bright_b(VImage* img, VSize border);
}

VExError
VexDraw::create_do(const VObjectStatus* s, int flags, VObject *nmp, void *arg)
{
	sts.value = 0;
	image_num = 0;
	images = 0;
	return VDraw::create_do(s, flags, nmp, arg);
}

void
VexDraw::destroy_do(VObject * nmp)
{
	VDraw::destroy_do(nmp);
	for ( int i = 0 ;  i < image_num ; i++ )
		v_image_unref(images[i]);
}

VexDraw::~VexDraw()
{
}


VExError
VexDraw::get_status(VObjectStatus *s, int flags) const
{
	return VDraw::get_status(s,flags);
}

VExError
VexDraw::set_status(const VObjectStatus *s, int flags)
{
	V_OP_START_EX
	VImage *eff;
	VExError err = initial_VExError(V_ER_NO_ERR,flags,0);
	
	if ( (flags & VSF_ENABLED) && image_num > 0 ) {
		if ( s->enabled ) {
			switch( sts.attr & disabled_mask ) {
			  case disabled_img_zero:
				VDraw::set_image(images[0]);
				redraw();
				break;
			  case disabled_hilight:
				VDraw::set_image(images[sts.value]);
				redraw();
				break;
			}
		}
		else {
			switch( sts.attr & disabled_mask ) {
			  case disabled_hilight:
				eff = v_image_eff_bright(images[sts.value]);
				VDraw::set_image(eff);
				v_image_unref(eff);
				redraw();
				break;
			  case disabled_img_zero:
				VDraw::set_image(images[0]);
				redraw();
				break;
			}
		}
	}

	if ( flags & VSF_VALUE ) {
		if ( image_num == 0 )
			sts.value = s->value;
		else if ( s->value < 0 || s->value >= image_num ) {
			err.code = V_ER_PARAM;
			err.subcode2 |= VSF_VALUE;
			flags &= ~VSF_VALUE;
		}
		else {
			set_image(images[s->value]);
			redraw();
			value_changed();
		}
		err.subcode1 &= ~VSF_VALUE;
	}

	V_OP_END
	// VDraw::set_status call VLayout::mark(), so we can't lock here...

	VExError err2 = VDraw::set_status(s,flags);
	if ( err2.code )
		err = merge_VExError_vstatus_type(err,err2);

	return err;
}


VError
VexDraw::set_image(VImage* img, VSize min_size)
{
	bool bright = 0;
	V_OP_START
	for ( int i = 0 ; i < image_num ; i++ ) {
		if ( images[i] == img ) {
			sts.value = i;
			value_changed();
			if ( !sts.enabled && (sts.attr & disabled_mask) == disabled_hilight )
				bright = true;
			break;
		}
	}
	V_OP_END

	// VDraw::set_image call VLayout::mark(), so we can't lock here...
	
	if ( bright )
		img = v_image_eff_bright(img);
	VDraw::set_image(img, min_size);
	if ( bright )
		v_image_unref(img);
	return V_ER_NO_ERR;
}


VError
VexDraw::set_images(int n, VImage** imgs, VSize min_size)
{
	int i;
	V_OP_START

	for ( i = 0 ; i < image_num ; i++ )
		v_image_unref(images[i]);
	delete images;
	
	image_num = n;
	if ( n )
		images = new VImage*[n];
	for ( i = 0 ; i < n ; i++ )
		images[i] = v_image_ref(imgs[i]);
	
	if ( sts.value <= 0 || sts.value >= n ) {
		if ( n > 1 && (
				(sts.attr & over_bit_mask) == over_img_zero ||
				(sts.attr & press_bit_mask) == press_img_zero ||
				(sts.attr & click_bit_mask) == click_rotate ))
			sts.value = 1;
		else
			sts.value = 0;
	}
	set_image(images[sts.value], min_size);
	redraw();

	V_OP_END

	return V_ER_NO_ERR;
}

VError
VexDraw::set_image_at(int n, VImage* img)
{
	V_OP_START
	if ( n < 0 || n >= image_num ) {
		V_OP_END;
		return V_ER_PARAM;
	}
	v_image_unref(images[n]);
	images[n] = v_image_ref(img);
	if ( sts.value == n )
		set_image(img);
	V_OP_END
	return V_ER_NO_ERR;
}

VImage*
VexDraw::get_image_at(int n)
{
	VImage *ret;
	_V_OP_START(0)
	if ( n < 0 || n >= image_num )
		ret = 0;
	else
		ret = v_image_ref(images[n]);
	V_OP_END
	return ret;
}


bool
VexDraw::mouse_event(VMouseEvent *event)
{
	if ( event->type != V_EV_MOUSE_MOVE )
		vq_insert_callback(this, call_ex_mouse_event_handler, 0, event, sizeof(*event));
	return VDraw::mouse_event(event);
}

V_CALLBACK_D(VexDraw::ex_mouse_event_handler)
{
	VMouseEvent *event = (VMouseEvent*)sys_arg;
	VImage *eff;

	_V_OP_START_VOID
	if ( event->type == V_EV_MOUSE_ENTER && event->button )
		event->type = V_EV_MOUSE_DOWN;
	
	if ( sts.enabled || (sts.attr & disabled_mask) == disabled_none ) {
		switch ( event->type ) {

		  case V_EV_MOUSE_DOWN:
			switch ( sts.attr & press_bit_mask ) {
			  case press_hilight:
				if ( image_num > 0 ) {
					eff = v_image_eff_dark(images[sts.value]);
					VDraw::set_image(eff);
					v_image_unref(eff);
					redraw();
				}
				break;
			  case press_hilight_b:
				if ( image_num > 0 ) {
					eff = v_image_eff_dark_b(images[sts.value], sts.spacing);
					VDraw::set_image(eff);
					v_image_unref(eff);
					redraw();
				}
				break;
			  case press_img_zero:
			  	if ( image_num > 0 ) {
					VDraw::set_image(images[0]);
					redraw();
				}
				break;
			}
			break;

		  case V_EV_MOUSE_UP:
		  	get_status(&sts, VSF_SIZE);
			if ( event->point.x >= 0 && event->point.x < sts.size.w &&
				 event->point.y >= 0 && event->point.y < sts.size.h ) {
				switch ( sts.attr & click_bit_mask ) {
				  case click_rotate:
					if ( image_num > 1 ) {
						sts.value++;
						if ( sts.value >= image_num )
							sts.value = 1;
						VDraw::set_image(images[sts.value]);
						value_changed();
						redraw();
					}
					break;
				  case click_rotate_zero:
					if ( image_num > 0 ) {
						sts.value++;
						if ( sts.value >= image_num )
							sts.value = 0;
						VDraw::set_image(images[sts.value]);
						value_changed();
						redraw();
					}
					break;
				  case click_stay:
					if ( image_num > 0 ) {
						value_changed();
					}
					break;
				}
			}
			if ( sts.attr & press_bit_mask ) {
				if ( image_num > 0 ) {
					VDraw::set_image(images[sts.value]);
					redraw();
				}
				break;
			}
			// continue into V_EV_MOUSE_ENTER case

		  case V_EV_MOUSE_ENTER:
			switch ( sts.attr & over_bit_mask ) {
			  case over_hilight:
				if ( image_num > 0 ) {
					eff = v_image_eff_bright(images[sts.value]);
					VDraw::set_image(eff);
					v_image_unref(eff);
					redraw();
				}
				break;
			  case over_hilight_b:
				if ( image_num > 0 ) {
					eff = v_image_eff_bright_b(images[sts.value], sts.spacing);
					VDraw::set_image(eff);
					v_image_unref(eff);
					redraw();
				}
				break;
			  case over_img_zero:
			  	if ( image_num > 0 ) {
					VDraw::set_image(images[0]);
					redraw();
				}
				break;
			}
			break;

		  case V_EV_MOUSE_LEAVE:
			if ( sts.attr & (press_bit_mask | over_bit_mask) ) {
				if ( image_num > 0 ) {
					VDraw::set_image(images[sts.value]);
					redraw();
				}
			}
			break;
		  default:
			break;
		}
	}
	V_OP_END
}



VImage *
v_get_image_element(VImage * img,VRect elr)
{
VImage * ret;
int w_border,h,w;
int x,y;
int fx,fy;
	ret = v_image_new(w=elr.r - elr.l,h=elr.b - elr.t,32);
	w_border = img->w_border;
	v_image_draw_start(ret,0);
	v_image_draw_start(img,0);
	for ( x = 0 ; x < w ; x ++ ) {
		fx = x + elr.l;
		for ( y = 0 ; y < h ; y ++ ) {
			fy = y + elr.t;
			ret->buf_32[x + ret->w_border*y]
				= img->buf_32[fx + fy*w_border];
		}
	}
	v_image_draw_end(img);
	v_image_draw_end(ret);
	return ret;
}


