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

#include "v/v_types.h"
#include "v/v_errors.h"

extern "C" {
#include "memory_debug.h"
#include "task.h"
#include "lock_level.h"

// machine dependent functions prototypes
void v_image_new_m(VImage* img, short w, short h, char depth);
void v_image_free_m(VImage* img);
void v_image_draw_start_m(VImage* img);
void v_image_draw_end_m(VImage* img);
bool v_image_call_lock_m(VImage* img);
void v_image_call_unlock_m(VImage* img);
VImage* _v_image_ref(VImage* img);
VImage* _v_image_unref(VImage* img);
bool v_image_lock(VImage *img);
void v_image_unlock(VImage *img);


VImage*
v_image_new(short w, short h, char depth)
{
	VImage* ret = (VImage*)d_alloc(sizeof(VImage));
	if ( depth != 32 )
		er_panic("non 32 bit image is not yet supported");
	v_image_new_m(ret, w, h, depth);
	ret->size.w = w;
	ret->size.h = h;
	ret->ref_cnt = 1;
	ret->drawing = false;
	return ret;
}

VImage*
_v_image_ref(VImage* img)
{
	if ( img )
		img->ref_cnt++;
	return img;
}

VImage*
_v_image_unref(VImage* img)
{
	if ( img && --img->ref_cnt == 0 )
		v_image_free(img);
	return img;
}

void
v_image_free(VImage* img)
{
	v_image_free_m(img);
	d_f_ree(img);
}

VImage*
v_image_copy(VImage* img)
{
	VImage* ret = v_image_new(img->size.w, img->size.h, 32);
	if ( img->size.w * img->size.h ) {
		v_image_draw_start(img, 0);
		v_image_draw_start(ret, 0);
		memcpy(ret->buf_32, img->buf_32, img->w_border * img->size.h * 4);
		v_image_draw_end(ret);
		v_image_draw_end(img);
	}
	return ret;
}

VImage*
v_image_partial(VImage* img, VRect *r)
{
	if ( r->l < 0 || r->t < 0 || r->r > img->size.w || r->b > img->size.h )
		return 0;
	VImage* ret = v_image_new(r->r-r->l, r->b-r->t, 32);
	if ( img->size.w * img->size.h ) {
		v_image_draw_start(img, 0);
		v_image_draw_start(ret, 0);
		for ( int h = r->t ; h < r->b ; h++ )
			memcpy(ret->buf_32 + (h-r->t)*ret->w_border, img->buf_32 + h*img->w_border + r->l,
					(r->r - r->l)*4);
		v_image_draw_end(ret);
		v_image_draw_end(img);
	}
	return ret;
}

int
_v_image_draw_start(VImage* img, int no_block, char* file, int line)
{

	while ( ! v_image_call_lock_m(img) )
		if ( no_block )
			return -1;
		else
			sleep_task((int)img, SEM_NULL);
	
	img->tid = get_tid();
	img->in_file = file;
	img->in_line = line;

	return 0;
}

void
_v_image_draw_end(VImage* img, char* file, int line)
{
	img->tid = 0;
	img->out_file = file;
	img->out_line = line;
	
	v_image_call_unlock_m(img);
}

// image lock - must be called via msequence from _m routine

bool
v_image_lock(VImage *img)
{
	if ( img->drawing )
		return false;
	img->drawing = true;
	v_image_draw_start_m(img);
	return true;
}

void
v_image_unlock(VImage *img)
{
	if ( ! img->drawing )
		er_panic("v_image_unlock");
	v_image_draw_end_m(img);
	img->drawing = false;
	wakeup_task((int)img);
}


} // extern "C"
