/*
 * msg_handle.c
 * 
 * Copyright (C) 2006  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.
 *
 */

#include <assert.h>
#include <stdlib.h>

#include "msg_handle.h"
#include "message.h"
#include "dirs.h"
#include "options.h"
#include "gui.h"
#include "draw.h"
#include "backend.h"
#include "playerlist.h"
#include "status.h"
#include "support.h"

#define DEBUG 0
#include "debug.h"


void msg_handle_chat(MESSAGE *msg)
{
	char *str = NULL, *cmd = NULL, *sender = NULL;
	int is_remote;

	DBG_MSG(3, "chat_handle_message");
	if (message_get(msg, MESSAGE_STRING, &cmd, MESSAGE_STRING, &str, MESSAGE_STRING, &sender, MESSAGE_INTEGER, &is_remote, MESSAGE_END)) {
		append_to_chat("%s %s: %s\n", is_remote ? "->":"<-", sender, str);
	}
}


void msg_handle_backend(MESSAGE *msg)
{
	char *data = NULL;
	
	assert(msg != NULL);

	if (backend_network && msg->dest == 'N') {
		data = message_to_string(msg, 1);
		backend_send(backend_network, data);
		free(data);
	}
	
	if (backend_game && msg->dest == 'G') {
		data = message_to_string(msg, 1);
		backend_send(backend_game, data);
		free(data);
	}
}


void msg_handle_draw(MESSAGE *msg)
{
	char *cmd = NULL;
	char *file, *s;
	int img_id, obj_id, x, y, h, w;
	
	assert(msg != NULL);

	message_get(msg, MESSAGE_STRING, &cmd, MESSAGE_END);
	
	if (cmd && cmd[0] == 'B') {
		switch (cmd[1]) {
			case 'i':
				switch (cmd[2]) {
					case 'l':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_STRING, &file,
								MESSAGE_INTEGER, &img_id,
								MESSAGE_END))
						{
							draw_image_load(option_get_string("main", "dir.data"), file, img_id);
						}
						break;
					case 'r':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_INTEGER, &img_id,
								MESSAGE_END))
						{
							draw_image_remove(img_id);
						}
						break;
				}
				break;

			case 'o':
				switch (cmd[2]) {
					case 'a':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_INTEGER, &obj_id,
								MESSAGE_INTEGER, &img_id,
								MESSAGE_INTEGER, &x,
								MESSAGE_INTEGER, &y,
								MESSAGE_INTEGER, &h,
								MESSAGE_INTEGER, &w,
								MESSAGE_END))
						{
							draw_object_add(obj_id, img_id, x, y, h, w);
						}
						break;

					case 'd':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_INTEGER, &obj_id,
								MESSAGE_END))
						{
							draw_object_delete(obj_id);
						}
						break;

					case 'm':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_INTEGER, &obj_id,
								MESSAGE_INTEGER, &x,
								MESSAGE_INTEGER, &y,
								MESSAGE_END))
						{
							draw_object_move(obj_id, x, y);
						}
						break;
				}
				break;

			case 's':
				switch (cmd[2]) {
					case 't':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_STRING, &s,
								MESSAGE_END))
						{
							set_statusbar_text(s);
						}
						break;
						
						
					case 'c':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_INTEGER, &x,
								MESSAGE_INTEGER, &y,
								MESSAGE_STRING, &s,
								MESSAGE_END))
						{
							set_statusbar_clock(x, y, "%s", s);
						}
						break;
						
					case 'p':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_INTEGER, &x,
								MESSAGE_INTEGER, &y,
								MESSAGE_STRING, &s,
								MESSAGE_END))
						{
							set_statusbar_progress(x != 0, y / 100., "%s", s);
						}
						break;
						
					case 's':
						if (message_get(msg, MESSAGE_SKIP,
								MESSAGE_INTEGER, &x,
								MESSAGE_END))
						{
							if (x >= 0)
								set_semaphore(x & 3);
						}
						break;
				}
				break;
			case 'u':
				draw_all();
				break;
				
			case 'r':
				draw_remove_all();
				break;
		}
	}

}


void msg_handle_options(MESSAGE *msg)
{
	char *cmd = NULL, *cat = NULL, *opt = NULL, *val_str = NULL;
	int val_int = 0;
	MESSAGE *reply = NULL;
	
	assert(msg != NULL);

	message_get(msg, MESSAGE_STRING, &cmd, MESSAGE_END);
	
	if (cmd && cmd[0] == 'O') {
		switch(cmd[1]) {
			case 'u':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &opt,
						MESSAGE_END))
				{
					option_unset(cat, opt);
				}
				break;

			case 's':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &opt,
						MESSAGE_STRING, &val_str,
						MESSAGE_END))
				{
					option_set_string(cat, opt, val_str);
				} else if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &opt,
						MESSAGE_INTEGER, &val_int,
						MESSAGE_END))
				{
					option_set_integer(cat, opt, val_int);
				}
				break;
				
			case 'g':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &opt,
						MESSAGE_END))
				{
					reply = message_create('O', msg->src);
					switch (option_get_type(cat, opt)) {
						case OPTION_STRING:
							message_append(reply, MESSAGE_STRING, "Or",
									MESSAGE_STRING, cat,
									MESSAGE_STRING, opt,
									MESSAGE_STRING, option_get_string(cat, opt),
									MESSAGE_END);
							break;

						case OPTION_INTEGER:
							message_append(reply, MESSAGE_STRING, "Or",
									MESSAGE_STRING, cat,
									MESSAGE_STRING, opt,
									MESSAGE_INTEGER, option_get_integer(cat, opt),
									MESSAGE_END);
							break;

						case OPTION_NONE:
							message_append(reply, MESSAGE_STRING, "Or",
									MESSAGE_STRING, cat,
									MESSAGE_STRING, opt,
									MESSAGE_END);
							break;
					}
					message_send(reply);
					message_destroy(reply);
				}
				break;
		}
	}
}


void msg_handle_playerlist(MESSAGE *msg)
{
	char *cmd = NULL, *nick, *address, *role, *score, *conn_state;
	MESSAGE *reply = NULL;
	int i;

	assert(msg != NULL);

	message_get(msg, MESSAGE_STRING, &cmd, MESSAGE_END);
	
	if (cmd && cmd[0] == 'P') {
		switch(cmd[1]) {
			case 'j':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_END))
				{
					playerlist_add(address);
					append_to_chat(_("-- %s se připojil(a)\n"), address);
				}
				break;

			case 'p':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_END))
				{
					playerlist_remove(address);
					append_to_chat(_("-- %s se odpojil(a)\n"), address);
				}
				break;
				
			case 'i':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &nick,
						MESSAGE_STRING, &role,
						MESSAGE_STRING, &score,
						MESSAGE_STRING, &conn_state,
						MESSAGE_END))
				{
					playerlist_update(address, nick, role, score, conn_state);
				}
				break;
				
			case 'n':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &nick,
						MESSAGE_END))
				{
					playerlist_update(address, nick, NULL, NULL, NULL);
				}
				break;
				
			case 'r':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &role,
						MESSAGE_END))
				{
					playerlist_update(address, NULL, role, NULL, NULL);
				}
				break;
				
			case 's':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &score,
						MESSAGE_END))
				{
					playerlist_update(address, NULL, NULL, score, NULL);
				}
				break;
				
			case 'c':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &conn_state,
						MESSAGE_END))
				{
					playerlist_update(address, NULL, NULL, NULL, conn_state);
				}
				break;

			case 'g':
				if (message_get(msg, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_END))
				{
					playerlist_get(address, &nick, &role, &score, &conn_state, NULL);
					reply = message_create('P', msg->src);
					message_append(reply, MESSAGE_STRING, "Pi",
							MESSAGE_STRING, address,
							MESSAGE_STRING, nick ? nick : "",
							MESSAGE_STRING, role ? role : "",
							MESSAGE_STRING, score ? score : "",
							MESSAGE_STRING, conn_state ? conn_state : "",
							MESSAGE_END);
					message_send(reply);
					message_destroy(reply);
				}
				break;
				
			case 'l':
				/* begin */
				reply = message_create('P', msg->src);
				message_append(reply, MESSAGE_STRING, "Plb", MESSAGE_END);
				message_send(reply);
				message_destroy(reply);

				/* data */
				for (i = 0; playerlist_list(&i, &address, &nick, &role, &score, &conn_state, NULL); i++) {
					if (address) {
						reply = message_create('P', msg->src);
						message_append(reply, MESSAGE_STRING, "Pi",
								MESSAGE_STRING, address,
								MESSAGE_STRING, nick ? nick : "",
								MESSAGE_STRING, role ? role : "",
								MESSAGE_STRING, score ? score : "",
								MESSAGE_STRING, conn_state ? conn_state : "",
								MESSAGE_END);
						message_send(reply);
						message_destroy(reply);
					}
				}

				/* end */
				reply = message_create('P', msg->src);
				message_append(reply, MESSAGE_STRING, "Ple", MESSAGE_END);
				message_send(reply);
				message_destroy(reply);

				break;
		}
	}
}


void msg_handle_session(MESSAGE *msg)
{
	char *cmd = NULL, *str = NULL, *addr = NULL, *role = NULL;
	
	assert(msg != NULL);

	message_get(msg, MESSAGE_STRING, &cmd, MESSAGE_END);
	
	if (cmd && cmd[0] == 'S') {
		DBG_MSG(3, "msg_handle_session: cmd = \"%s\"", cmd);
		switch (cmd[1]) {
			case 'o': /* online/offline */
				switch (cmd[2]) {
					case 'n':	/* online */
						if (get_status() == S_CONNECTING) {
							switch_to_status(S_CONNECTED);
						}
						break;

					case 'f':	/* offline */
						if (get_status() != S_DISCONNECTING && get_status() != S_EXITING) {
							switch_to_status(S_CONNECTING);
						}
						break;
				}
				break;

			case 'r': /* role list */
				message_get_next(msg, 1, MESSAGE_SKIP, MESSAGE_END);
				gui_role_clear();
				while (message_get_next(msg, 0, MESSAGE_STRING, &str, MESSAGE_END)) {
					gui_role_add(str);
				}
				break;

			case 'p': /* player */
				switch (cmd[2]) {
					case 'a': /* ack */
						if (message_get(msg, MESSAGE_SKIP, MESSAGE_SKIP, MESSAGE_STRING, &addr, MESSAGE_END)) {
							playerlist_update_ack(addr, 1);
						}
						break;
						
					case 'e': /* error */
						if (message_get(msg, MESSAGE_SKIP, MESSAGE_SKIP, MESSAGE_STRING, &addr, MESSAGE_END)) {
							playerlist_update_ack(addr, -2);
						}
						break;

					case 'r': /* role */
						if (message_get(msg, MESSAGE_SKIP, MESSAGE_SKIP, MESSAGE_STRING, &role, MESSAGE_STRING, &addr, MESSAGE_END)) {
							playerlist_update(addr, NULL, role, NULL, NULL);
							if (get_status() == S_LOADED) {
								gtk_widget_set_sensitive(lookup_widget(main_window, "game_start_button"), TRUE);
								gtk_widget_set_sensitive(lookup_widget(main_window, "game_role_combobox"), TRUE);
							}
						}
						break;

					case 'g': /* select game */
						if (get_status() == S_CONNECTED && message_get(msg, MESSAGE_SKIP, MESSAGE_SKIP, MESSAGE_STRING, &str, MESSAGE_END)) {
							option_set_string("main", "game.backend", str);
							switch_to_status(S_LOADING);
						}
						break;

					case 'b': /* start game */
						if (message_get(msg, MESSAGE_SKIP, MESSAGE_SKIP, MESSAGE_STRING, &addr, MESSAGE_END)) {
							playerlist_update_ack(addr, 2);
							playerlist_get(addr, &str, NULL, NULL, NULL, NULL);
							append_to_chat(_("-- %s zahajuje hru\n"), str && str[0] ? str : addr);

							if (playerlist_have_all_acks(2)) {
								switch_to_status(S_GAME_PLAYING);
							}
						}
						break;
						
					case 'o': /* over -- hrac uz nehraje */
						if (message_get(msg, MESSAGE_SKIP, MESSAGE_SKIP, MESSAGE_STRING, &addr, MESSAGE_END)) {
							playerlist_update_ack(addr, -1);
							playerlist_get(addr, &str, NULL, NULL, NULL, NULL);
							append_to_chat(_("-- %s končí\n"), str && str[0] ? str : addr);

							if (playerlist_have_all_acks(-1)) {
								switch_to_status(S_CONNECTED);
							}
						}
						break;

					case 't': /* turn -- forward only */
						if (msg->src == 'N') {
							message_edit(msg, 'S', 'G');
						} else if (msg->src == 'G') {
							message_edit(msg, 'S', 'N');
						}
						message_send(msg);
						break;

				}
				break;
				
			case 'g': /* game */
				switch (cmd[2]) {
					case 'l': /* loaded */
						DBG_MSG(1, "Sgl: stat = %d", get_status());
						if (get_status() == S_LOADING) {
							switch_to_status(S_LOADED);
						}
						break;
						
					case 'a': /* accept */
						DBG_MSG(1, "Sga: stat = %d", get_status());
						if (get_status() == S_GAME_CHECK) {
							switch_to_status(S_GAME_STARTING);
						}
						break;

					case 'r': /* reject */
						DBG_MSG(1, "Sgr: stat = %d", get_status());
						if (get_status() == S_GAME_CHECK) {
							switch_to_status(S_LOADED);
						}
						{
							GtkWidget *d;
							d = gtk_message_dialog_new(GTK_WINDOW(main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
									GTK_BUTTONS_OK, _("Ještě nelze zahájit hru"));
							gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(d),
									_("Herní modul odmítl zahájení hry. Nejspíš nejsou rozděleny všechny"
									  " role nebo jsou rozděleny špatně."));
							gtk_dialog_run(GTK_DIALOG(d));
							gtk_widget_destroy(d);
						}
						break;

				}
				break;

		}
	}
}


void msg_handle_test(MESSAGE *msg)
{
	char *str, *p_msg_str = NULL;
	MESSAGE *m;
	
	DBG_MSG(1, "test");
	str = message_to_string(msg, 0);
	DBG_MSG(1, "string: %s", str);

	m = message_from_string('T', 'T', str, &p_msg_str);
	free(str);

	str = message_to_string(msg, 0);
	DBG_MSG(1, "string: %s", str);

	free(str);
	message_destroy(m);
	
	return;
}

/* vim:set encoding=utf8: */
