/**********************************************************************
 
	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/VClipboard.h"
#include "v/v_serialized_exec.h"
extern "C" {
#include "memory_debug.h"
#include "jpeg.h"
}

void * VClipboard::data = 0;
int VClipboard::data_type = 0;

static bool _is_data_type_available(int type)
{
	bool ret = false;
	GtkClipboard *clipboard = gtk_clipboard_get(GDK_NONE);
	switch ( type ) {
	  case VDT_STRING:
		ret = gtk_clipboard_wait_is_text_available(clipboard);
		break;
	  default:
		char n[] = {type, 0};
		GdkAtom target = gdk_atom_intern(n, false);
		GtkSelectionData *data = gtk_clipboard_wait_for_contents(clipboard, target);
		ret = (data != NULL);
		gtk_selection_data_free(data);
		break;
	}
	return ret;
}

bool
VClipboard::is_data_type_available(int type)
{
	return v_serialized_exec_func(_is_data_type_available, type);
}

static void
get_clip(GtkClipboard *clipboard,
			GtkSelectionData *selection_data,
			guint info,
			void *user_data)
{
	char n[] = {info, 0};
	GdkAtom atom = gdk_atom_intern(n, false);
	gtk_selection_data_set(selection_data, atom, 8, (guchar*)user_data+4, *(int*)user_data);
}

static void
clear_clip(GtkClipboard *clipboard, gpointer user_data)
{
	d_f_ree(user_data);
}


static void _set_data_type(int type, int len, void *data, bool clear)
{
	GtkClipboard *clipboard = gtk_clipboard_get(GDK_NONE);
	if ( clear ) {
		gtk_clipboard_clear(clipboard);
	}
	switch ( type ) {
	  case VDT_STRING:
		gtk_clipboard_set_text(clipboard, (gchar*)data, len);
		break;
	  default: {
			char target[] = {type, 0};
			GtkTargetEntry entry = {target, 0, type};
			char* clip = (char*)d_alloc(4+len);
			*(int*)clip = len;
			memcpy(clip+4, data, len);
			gtk_clipboard_set_with_data(clipboard, &entry, 1, get_clip, clear_clip, clip);
			break;
		}
	}
}

void
VClipboard::set_data_type(int type, int len, void *data, bool clear)
{
	v_serialized_exec_sub(_set_data_type, type, len, data, clear);
}


static void * _get_data_type(int type, int *outLen, void **data, int *data_type)
{
	GtkClipboard *clipboard = gtk_clipboard_get(GDK_NONE);
	GtkSelectionData *sel;
	gchar *ch;
	switch ( type ) {
	  case VDT_STRING:
		ch = gtk_clipboard_wait_for_text(clipboard);
		*data = ch;
		*data_type = type;
		*outLen = strlen(ch);
		return ch;
	  default:
		char n[] = {type, 0};
		GdkAtom atom = gdk_atom_intern(n, false);
		sel = gtk_clipboard_wait_for_contents(clipboard, atom);
		*data = sel->data;
		*data_type = type;
		*outLen = sel->length;
		break;
	}
	return *data;
}

void *
VClipboard::get_data_type(int type, int &outLen)
{
	return v_serialized_exec_func(_get_data_type, type, &outLen, &data, &data_type);
}


static void _release_data(void **data, int *data_type)
{
	if ( *data == 0 )
		return;
	switch ( *data_type ) {
	  case VDT_STRING:
		g_free(*data);
		break;
	  default:
		break;
	}
	*data = 0;
	*data_type = 0;
}

void
VClipboard::release_data()
{
	v_serialized_exec_sub(_release_data, &data, &data_type);
}


static VImage *
_get_image()
{
	int size;
	void *img = VClipboard::get_data_type(VDT_IMAGE, size);
	if ( !img )
		return 0;
	int w, h;
	int _w, _h, p;
	unsigned char *rgb_buf = jpeg_uncompress(&w,&h,(unsigned char*)img,size);
	VImage *ret = v_image_new(w,h,32);
	v_image_draw_start(ret,0);
	for ( _h = 0 ; _h < h ; _h ++ )
		for ( _w = 0 ; _w < w ; _w ++ ) {
			p = 4*(_h*w+_w);
			SET_RGB8_32(ret->buf_32[_h*ret->w_border + _w],
				rgb_buf[p], rgb_buf[p+1], rgb_buf[p+2], 0xff);
		}
	v_image_draw_end(ret);
	free(rgb_buf);
	VClipboard::release_data();
	return ret;
}

VImage*
VClipboard::get_image()
{
	return v_serialized_exec_func(_get_image);
}


static void
_set_image(VImage* img, int *outSize, bool clear)
{
	unsigned char * rgb_buf = (unsigned char*)d_alloc(img->size.h*img->size.w*4), a;
	v_image_draw_start(img,0);
	for ( int h = 0 ; h < img->size.h ; h ++ )
		for ( int w = 0 ; w < img->size.w ; w ++ ) {
			int p = 4*(h*img->size.w + w);
			GET_RGB8_32(img->buf_32[img->w_border*h + w],
				rgb_buf[p],rgb_buf[p+1],rgb_buf[p+2],a);
		}
	v_image_draw_end(img);
	void *jpeg = jpeg_compress(outSize,rgb_buf,img->size.w,img->size.h,80);
	d_f_ree(rgb_buf);
	
	VClipboard::set_data_type(VDT_IMAGE, *outSize, jpeg, clear);
	free(jpeg);
}

void
VClipboard::set_image(VImage* img, int *outSize, bool clear)
{
	v_serialized_exec_sub(_set_image, img, outSize, clear);
}
