/*
 * draw.c
 *
 * Copyright (C) 2005-2007  Josef Kufner <jk@myserver.cz>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.  See the
 * GNU General Public License for more details.
 *
 *
 *
 * Object with id 0 is background. Objects are drawn in order by their ids.
 *
 */


#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "dirs.h"
#include "gui.h"

#define _GNU_SOURCE
#include <unistd.h>

#include "draw.h"
#include "gui.h"

#define DEBUG 		0
#include "debug.h"


#define MAX_IMAGE	1024
#define MAX_OBJECT	1024

enum {
	state_current,
	state_new,
	state_max
};

static struct s_image {
	char *file;
	GdkPixbuf *pixbuf;
} image[MAX_IMAGE];

static struct s_object {
	int exists;
	int x, y, height, width;
	int image;
} object[state_max][MAX_OBJECT];

static GtkWidget *draw_widget = NULL;


void draw_init (GtkWidget *drawing_area)
{
	DBG_MSG(6, "");
	assert(drawing_area != NULL);
	draw_widget = drawing_area;
	bzero(image, sizeof(image));
	bzero(object, sizeof(object));
	gtk_widget_set_size_request (draw_widget, 1, 1);
}


int draw_image_load (const char *dir, const char *file, int id)
{
	GError *error = NULL;
	char *filename = NULL;
	char cwd[512];

	assert(dir != NULL);
	assert(file != NULL);
	assert(id >= 0 && id < MAX_IMAGE);
	
	filename = dir_build_filename(dir, file);	

	DBG_MSG(6, "\"%s\" -> %d", filename, id);
	
	draw_image_remove(id);
	
	if (!(image[id].pixbuf = gdk_pixbuf_new_from_file(filename, &error))) {
		gui_show_error_message(_("Nepovedlo se načíst obrázek"), 
				_("%s\npracovní adresář: %s"),
				error->message, getcwd(cwd, sizeof(cwd)));
		free(filename);
		g_error_free(error);
		return 0;
	}

	image[id].file = filename;

	return 1;
}


void draw_image_remove (int id)
{
	DBG_MSG(6, "%d", id);
	assert(id >= 0 && id < MAX_IMAGE);
	if (image[id].pixbuf) {
		DBG_MSG(10, "pixbuf = %p", image[id].pixbuf);
		gdk_pixbuf_unref(image[id].pixbuf);
		image[id].pixbuf = NULL;
	}
	
	if (image[id].file) {
		DBG_MSG(10, "file = %p", image[id].file);
		free(image[id].file);
		image[id].file = NULL;
	}
	DBG_MSG(8, "%d done.", id);
}



int draw_object_add (int object_id, int image_id, int x, int y, int height, int width)
{
	DBG_MSG(6, "%d %d at [ %d, %d ], size %d x %d",
			object_id, image_id, x, y, height, width);
	assert(object_id >= 0 && object_id < MAX_OBJECT);
	assert(image_id >= 0 && image_id < MAX_IMAGE);
	
	if (image[image_id].pixbuf || (image_id == -1 && height > 0 && width > 0)) {
		object[state_new][object_id].exists = 1;
		object[state_new][object_id].x = x;
		object[state_new][object_id].y = y;
		object[state_new][object_id].image = image_id;
		object[state_new][object_id].width = width > 0 ? width : gdk_pixbuf_get_width(image[image_id].pixbuf);
		object[state_new][object_id].height = height > 0 ? height : gdk_pixbuf_get_height(image[image_id].pixbuf);
		
		DBG_MSG(6, "x = %d, y = %d, image = %d, width = %d, height = %d",
				object[state_new][object_id].x,
				object[state_new][object_id].y,
				object[state_new][object_id].image,
				object[state_new][object_id].width,
				object[state_new][object_id].height);

		/* objekt s id == 0 je pozadi, podle nej se urci velikost plochy */
		if (object_id == 0) {
			gtk_widget_set_size_request(draw_widget, object[state_new][0].width, object[state_new][0].height);
		}
		return 1;
	} else {
		return 0;
	}
}


void draw_object_delete (int object_id)
{
	DBG_MSG(6, "%d", object_id);
	assert(object_id >= 0 && object_id < MAX_OBJECT);
	object[state_new][object_id].exists = 0;
}


void draw_object_move (int object_id, int x, int y)
{
	DBG_MSG(6, "%d to [ %d, %d ]", object_id, x, y);
	assert(object_id >= 0 && object_id < MAX_OBJECT);
	object[state_new][object_id].x = x;
	object[state_new][object_id].y = y;
}


int draw_get_object_by_xy (int x, int y)
{
	int i;

	for (i = MAX_OBJECT - 1; i >= 0; i--) {
		if (object[state_new][i].exists) {
			DBG_MSG(8, "Checking object %d at %d, %d (%d x %d)",
					i, object[state_new][i].x, object[state_new][i].y, object[state_new][i].width, object[state_new][i].height);
			if (object[state_new][i].x < x && object[state_new][i].y < y
					&& object[state_new][i].x + object[state_new][i].width > x
					&& object[state_new][i].y + object[state_new][i].height > y)
			{
				DBG_MSG(5, "Found object %d", i);
				return i;
			}
		}
	}
	DBG_MSG(5, "No object found");
	return -1;
	
}


void draw_remove_all (void)
{
	int i;

	DBG_MSG(6, "");
	for (i = 0; i < MAX_IMAGE; i++) {
		if (image[i].pixbuf || image[i].file)
			draw_image_remove(i);
	}
	draw_init(draw_widget);
}


void draw_all(void)
{
	memcpy(object[state_current], object[state_new], sizeof(object[state_current]));
	if (GTK_WIDGET_DRAWABLE(draw_widget))
		gtk_widget_queue_draw (draw_widget);
	else
		gui_page_notify(GUI_PAGE_BOARD);
}


void draw_all_real(void)
{
	int i;
	DBG_MSG(6, "");

	if (image[object[state_current][0].image].pixbuf != NULL && GTK_WIDGET_DRAWABLE(draw_widget)) {
		DBG_MSG(8, "drawing background...");
		gdk_draw_pixbuf(draw_widget->window, NULL, image[object[state_current][0].image].pixbuf,
				0, 0, 0, 0, -1, -1,
				GDK_RGB_DITHER_NORMAL, 0, 0);
		
		for (i = 1; i < MAX_OBJECT; i++) {
			if (object[state_current][i].exists && object[state_current][i].image >= 0) {
				DBG_MSG(8, "drawing object %d at [ %d, %d ]...", i, object[state_current][i].x, object[state_current][i].y);
				gdk_draw_pixbuf(draw_widget->window,
						NULL, image[object[state_current][i].image].pixbuf,
						0, 0,
						object[state_current][i].x, object[state_current][i].y,
						object[state_current][i].width, object[state_current][i].height,
						GDK_RGB_DITHER_NORMAL, 0, 0);
			}
		}
	}
}


/* Ok, this is second implementation of draw_all_real, but this draws into
 * pixbuf instead of drawable. This is slower than draw_all_real.
 */
int draw_save_screenshot_png(const char *dir, const char *file)
{
	gboolean ret = 1;
	GError *error = NULL;
	char cwd[512];
	GdkPixbuf *pb;
	int i;
	char *filename;
	
	assert(file != NULL);
	assert(dir != NULL);
	DBG_MSG(1, "filename = \"%s\", \"%s\"", dir, file);
	
	/* build filename */
	filename = dir_build_filename(dir, file);

	if (image[object[state_current][0].image].pixbuf != NULL) {
		/* create pixbuf */
		pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, object[state_current][0].width, object[state_current][0].height);

		/* render everything to pixbuf */
		for (i = 0; i < MAX_OBJECT; i++) {
			if (object[state_current][i].exists && object[state_current][i].image >= 0) {
				DBG_MSG(8, "drawing object %d at [ %d, %d ]...", i, object[state_current][i].x, object[state_current][i].y);
				gdk_pixbuf_composite(image[object[state_current][i].image].pixbuf, pb,
						object[state_current][i].x, object[state_current][i].y,
						object[state_current][i].width, object[state_current][i].height,
						object[state_current][i].x, object[state_current][i].y,
						1.0, 1.0, GDK_INTERP_NEAREST, 255);
			}
		}

		/* save pixbuf to file */
		ret = gdk_pixbuf_save(pb, filename, "png", &error, NULL);

		/* return */
		if (ret) {
			DBG_MSG(2, "ok");
		} else {
			DBG_MSG(2, "err");
			gui_show_error_message(_("Nepovedlo se uložit obrázek herní desky"), 
					_("%s\npracovní adresář: %s"),
					error->message, getcwd(cwd, sizeof(cwd)));
			g_error_free(error);
		}
		return ret;
	}
	g_free(filename);
	return -1;
}

/* vim:set encoding=utf8: */

