/**********************************************************************
 
	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	<string.h>

extern "C" {
#include	"memory_debug.h"
#include	"gif_rgb.h"
}

#include	"v/v.h"
#include 	"v/VgbIndicate.h"

int copy_meter(VgbIndicateMeter * m1,VgbIndicateMeter * m2,int flags,
		VgbIndicateMeter * lim);
VImage * get_image_element(VgbIndicateImage * im,int nos);

int
copy_meter(VgbIndicateMeter * m1,VgbIndicateMeter * m2,int flags,
		VgbIndicateMeter * lim)
{
int ret;
int i;
int old;
	ret = 0;
	for ( i = 0 ; i < IND_ARY_LEN ; i ++ ) {
		if ( !(flags & (1<<i)) )
			continue;
		old = m1->ary[i];
		m1->ary[i] = m2->ary[i];
		if ( m1->ary[i] < 0 )
			m1->ary[i] = 0;
		else if ( lim && m1->ary[i] >= lim->ary[i] ) {
			if ( lim->ary[i] == 0 )
				m1->ary[i] = 0;
			else	m1->ary[i] = lim->ary[i]-1;
		}
		if ( m1->ary[i] != old )
			ret |= 1<<i;
	}
	for ( i = 0 ; i < IND_ARY_LEN ; i ++ ) {
		if ( !(flags & (1<<(i+IND_ARY_LEN))) )
			continue;
		old = m1->ary[i];
		m1->ary[i] += m2->ary[i];
		if ( m1->ary[i] < 0 )
			m1->ary[i] = 0;
		else if ( lim && m1->ary[i] >= lim->ary[i] ) {
			if ( lim->ary[i] == 0 )
				m1->ary[i] = 0;
			else	m1->ary[i] = lim->ary[i]-1;
		}
		if ( m1->ary[i] != old )
			ret |= 1<<i;
	}
	return ret;
}

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


VExError
VgbIndicate::create_do(const VObjectStatus* s, int flags,VObject * nmp, void * arg)
{
VImage ** imgs;
VExError err;
VObjectAppStatusAry * app;
VgbIndicateStatus * in_sts;
VgbIndicateMeter * m_sts;
int in_flags,m_flags;
VObjectStatus _sts;
VgbIndicateImage * im;
int i,j;

	err = initial_VExError(V_ER_NO_ERR,VSF_SPACING,0);

	info = 0;

	memset(&meter,0,sizeof(meter));
	memset(&limit,0,sizeof(limit));
	memset(d_obj,0,sizeof(d_obj));
	memset(t_obj,0,sizeof(t_obj));
	if ( arg ) {
		app = (VObjectAppStatusAry*)arg;
		in_sts = (VgbIndicateStatus*)app[0].sts;
		in_flags = app[0].flags;
		if ( in_sts == 0 ) {
			in_sts = 0;
			in_flags = 0;
			m_sts = 0;
			m_flags = 0;
		}
		else {
			m_sts = (VgbIndicateMeter*)app[1].sts;
			m_flags = app[1].flags;
			if ( m_sts == 0 ) {
				m_sts = 0;
				m_flags = 0;
			}
		}
	}
	if ( m_sts == 0 ) {
		return initial_VExError(V_ER_INVALID_MODE,0,0);
	}
	copy_vobject_status(&_sts,(VObjectStatus*)s,flags);
	_sts.parent = this;
	_sts.spacing.w = _sts.spacing.h = 0;
	align = VHAlignView::create(&_sts,
			flags|VSF_PARENT|VSF_SPACING);
	_sts.parent = align;
	_sts.alignv = VALIGN_TOP;
	_sts.alignh = VALIGN_LEFT;
	_sts.padding.w = _sts.padding.h = 0;
	_sts.spacing.w = _sts.spacing.h = 0;
	for ( i = 0 ; i < IND_ARY_LEN ; i ++ ) {
		if ( !(in_flags & (1<<i)) )
			continue;
		im = &in_sts->ary[i];
		if ( im->img == 0 )
			continue;
		imgs = (VImage**)d_alloc(sizeof(VImage*)*im->levels);
		for (  j = 0 ; j < im->levels ; j ++ )
			imgs[j] = get_image_element(im,j);
		_sts.size = _sts.min_size = imgs[0]->size;
		d_obj[i] = VexDraw::create(&_sts,
				flags|VSF_PARENT|VSF_ALIGN|VSF_SPACING|
				VSF_PADDING|VSF_MIN_SIZE|VSF_SIZE);
		d_obj[i]->set_images(im->levels,imgs,imgs[0]->size);
		for ( j = 0 ; j < im->levels ;j ++ ) {
			v_image_unref(imgs[j]);
		}
		d_f_ree(imgs);
		limit.ary[i] = im->levels;

		if ( im->name == 0 )
			continue;
		_sts.descriptor = im->name;
		t_obj[i] = VStaticText::create(&_sts,
				flags|VSF_DESC|VSF_PARENT|
				VSF_SPACING|VSF_ALIGN|VSF_PADDING);
	}
	copy_meter(&meter,m_sts,m_flags,&limit);
	for ( i = 0 ; i < IND_ARY_LEN ; i ++ ) {
		if ( d_obj[i] == 0 )
			continue;
		_sts.value = meter.ary[i];
		d_obj[i]->set_status(&_sts,VSF_VALUE);
	}
	return err;
}


void
VgbIndicate::destroy_do(VObject * nmp)
{
	memset(&t_obj,0,sizeof(t_obj));
	memset(&d_obj,0,sizeof(d_obj));
	align = 0;
}

void
VgbIndicate::destroy_do_out_of_lock(VObject * nmp)
{
}

void
VgbIndicate::redraw(VRect * rect) const
{
}

VgbIndicate::~VgbIndicate()
{
}


VExError
VgbIndicate::set_status(const VObjectStatus * s,int flags)
{
	return VMacro::set_status(s, flags);
}

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

VExError
VgbIndicate::get_indicate_status(
			VgbIndicateStatus * s,
			int flags) const
{
int i;
VObjectStatus _sts;
	VM_OP_START_EX
	memset(s,0,sizeof(*s));
	for ( i = 0 ; i < IND_ARY_LEN ; i ++ ) {
		if ( !(flags & (1<<i)) )
			continue;
		s->ary[i].levels = limit.ary[i];
		if ( t_obj[i] == 0 )
			continue;
		t_obj[i]->get_status(&_sts,VSF_DESC);
		s->ary[i].name = (L_CHAR*)_sts.descriptor;
	}
	VM_OP_END
	return initial_VExError(V_ER_NO_ERR,0,0);
}

VExError
VgbIndicate::set_indicate_status(
			const VgbIndicateStatus *,
			int flags)
{
	return initial_VExError(V_ER_INVALID_MODE,0,0);
}


VExError
VgbIndicate::get_indicate_meter(
			VgbIndicateMeter * m,
			int flags) const
{
	VM_OP_START_EX
	copy_meter(m,(VgbIndicateMeter*)&meter,flags&IND_ARY_MASK1,0);
	VM_OP_END
	return initial_VExError(V_ER_NO_ERR,0,0);
}


VExError
VgbIndicate::set_indicate_meter(
		const VgbIndicateMeter * m,
		int flags)
{
int change;
int i;
VObjectStatus _sts;
	VM_OP_START_EX

	change = copy_meter(&meter,(VgbIndicateMeter*)m,flags,&limit);
	for ( i = 0 ; i < IND_ARY_LEN ; i ++ ) {
		if ( !(change & (1<<i)) )
			continue;
		if ( d_obj[i] == 0 )
			continue;
		_sts.value = meter.ary[i];
		d_obj[i]->set_status(&_sts,VSF_VALUE);
	}
	VM_OP_END
	return initial_VExError(V_ER_NO_ERR,0,0);
}








