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

#include <assert.h>
#include <string.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 "connection.h"
#include "session.h"
#include "record.h"
#include "roles.h"
#include "glade_support.h"

#define DEBUG 5
#include "debug.h"


extern BACKEND *backend_network;
extern BACKEND *backend_game;


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

	DBG_MSG(3, "");
	/*MSG* C message_body
	 * 
	 * Chat
	 *
	 * Send or display normal chat message.
	 */
	if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &cmd, MESSAGE_STRING, &str, MESSAGE_END)
			&& message_get(msg, MESSAGE_PART_SENDER_INFO, MESSAGE_STRING, &sender, MESSAGE_INTEGER, &is_remote, MESSAGE_END))
	{
		gui_append_to_chat(playerlist_get_nick(sender), is_remote ? GUI_CHAT_IN : GUI_CHAT_OUT, "%s", 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;
	long img_id, obj_id, x, y, h, w;
	
	assert(msg != NULL);

	message_get(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &cmd, MESSAGE_END);

	if (cmd && cmd[0] == 'B') {
		switch (cmd[1]) {
			case 'i':
				switch (cmd[2]) {
					case 'l':
						/*MSG* Bil filename img_id
						 * 
						 * Board Image Load
						 * 
						 * Load image from file. To
						 * show image on board, object
						 * must be created (see 'Boa').
						 */
						if (message_get(msg, MESSAGE_PART_DATA, 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':
						/*MSG* Bir img_id
						 *
						 * Board image remove.
						 *
						 * Remove image. No objects should use this image.
						 */
						if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
								MESSAGE_INTEGER, &img_id,
								MESSAGE_END))
						{
							draw_image_remove(img_id);
						}
						break;
				}
				break;

			case 'o':
				switch (cmd[2]) {
					case 'a':
						/*MSG* Boa obj_id img_id x y height width
						 * 
						 * Board Object Add
						 * 
						 * Add object at board. img_id is id of image
						 * loaded with Bil. If height and width is -1,
						 * then size is determined automaticaly.
						 */
						if (message_get(msg, MESSAGE_PART_DATA, 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':
						/*MSG* Bod obj_id
						 *
						 * Board Object Delete
						 *
						 * Remove object from board.
						 */
						if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
								MESSAGE_INTEGER, &obj_id,
								MESSAGE_END))
						{
							draw_object_delete(obj_id);
						}
						break;

					case 'm':
						/*MSG* Bom obj_id x y
						 * 
						 * Board Object Move
						 *
						 * Move object to new [x, y]. Don't forget to update
						 * board with 'Bu'.
						 */
						if (message_get(msg, MESSAGE_PART_DATA, 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':
						/*MSG* Bst text
						 * 
						 * Board Statusbar Text
						 * 
						 * Set statusbar text to 'text'.
						 */
						if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
								MESSAGE_STRING, &s,
								MESSAGE_END))
						{
							gui_append_to_chat(NULL, GUI_CHAT_SYS, s);
						}
						break;
						
						
					case 'c':
						/*MSG* Bsc is_visible icon text
						 *
						 * Board Statusbar Clock
						 *
						 * Set statusbar clock (secondary text at right). If 
						 * 'is_visible' is zero, clock part of statusbar is hidden.
						 * 'icon' is integer from 0 to 5; zero means none.
						 */
						if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
								MESSAGE_INTEGER, &x,
								MESSAGE_INTEGER, &y,
								MESSAGE_STRING, &s,
								MESSAGE_END))
						{
							gui_set_statusbar_clock(x, y, "%s", s);
						}
						break;
						
					case 'p':
						/*MSG* Bp is_visible percentage text
						 *
						 * Board Statusbar Progresbar
						 *
						 * Set progresbar in statusbar. If 'is_visible' is zero,
						 * progressbar is hidden. Filled part is given in percents
						 * as 'percentage'.
						 */
						if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
								MESSAGE_INTEGER, &x,
								MESSAGE_INTEGER, &y,
								MESSAGE_STRING, &s,
								MESSAGE_END))
						{
							gui_set_statusbar_progress(x != 0, y / 100., "%s", s);
						}
						break;
						
					case 's':
						/*MSG* Bss value
						 *
						 * Board Statusbar Semaphore
						 *
						 * Set semaphore lights. Lights are binary representation
						 * of value, e.g. 2 means green on and red off.
						 */
						if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
								MESSAGE_INTEGER, &x,
								MESSAGE_END))
						{
							if (x >= 0)
								gui_set_semaphore(x & 3);
						}
						break;
				}
				break;
			case 'u':
				/*MSG* Bu
				 *
				 * Board Update
				 *
				 * Just redraw board.
				 */
				draw_all();
				break;
				
			case 'r':
				/*MSG* Br
				 *
				 * Board Remove
				 *
				 * Remove everything from board. All objects, all images.
				 */
				draw_remove_all();
				break;
		}
	}
}


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

	message_get(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &cmd, MESSAGE_END);
	
	if (cmd && cmd[0] == 'O') {
		switch(cmd[1]) {
			case 'u':
				/*MSG* Ou cat mod opt
				 *
				 * Option Unset
				 *
				 * Remove given option from database.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &mod,
						MESSAGE_STRING, &opt,
						MESSAGE_END))
				{
					option_unset(cat, mod, opt);
				}
				break;

			case 'a':
				/*MSG* Oa cat mod opt value
				 *
				 * Option Add
				 *
				 * If given option does not exist, set it to 'value'. 
				 * This is good for loading default values.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &mod,
						MESSAGE_STRING, &opt,
						MESSAGE_END)
					&& option_get_type(cat, mod, opt) != OPTION_NONE)
				{
					break;
				}
				
			case 's':
				/*MSG* Os cat mod opt value
				 *
				 * Option Set
				 *
				 * Set given option to 'value'. 'value' can be 
				 * integer or string.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &mod,
						MESSAGE_STRING, &opt,
						MESSAGE_STRING, &val_str,
						MESSAGE_END))
				{
					option_set_string(cat, mod, opt, val_str);
				} else if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &mod,
						MESSAGE_STRING, &opt,
						MESSAGE_INTEGER, &val_int,
						MESSAGE_END))
				{
					option_set_integer(cat, mod, opt, val_int);
				}
				break;
				
			case 'g':
				/*MSG* Og cat mod opt value
				 *
				 * Option Get
				 *
				 * Request for value of given option. Option
				 * database will reply with 'Or'.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &cat,
						MESSAGE_STRING, &mod,
						MESSAGE_STRING, &opt,
						MESSAGE_END))
				{
					reply = message_create('O', msg->src);
					/*MSG* Or cat mod opt value
					 *
					 * Option Reply
					 *
					 * Option database will send this message
					 * as answer to 'Og'. 'value' can be string or
					 * integer if option exists. If option is not found,
					 * 'value' parameter will be missing.
					 */
					switch (option_get_type(cat, mod, opt)) {
						case OPTION_STRING:
							message_append(reply, MESSAGE_PART_DATA, MESSAGE_STRING, "Or",
									MESSAGE_STRING, cat,
									MESSAGE_STRING, mod,
									MESSAGE_STRING, opt,
									MESSAGE_STRING, option_get_string(cat, mod, opt),
									MESSAGE_END);
							break;

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

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

			case 'd':
				/*MSG* Odo category module window_title fields...
				 *
				 * Option Dialog Open
				 *
				 * Shows dialog with given fields. Number of 'fields'
				 * is unlimited, but there is no scrollbar in dialog.
				 *
				 * Type of fields is determined by first character of its label.
				 *
				 * See documentation for details.
				 */
				/*MSG* Odc update
				 *
				 * Option Dialog Close
				 *
				 * Option dialog has been closed. If 'update' is 1, ok button 
				 * has been pressed and configuration has been changed.
				 */
				if (cmd[2] == 'o')
					gui_config_dialog_from_message(msg, msg->src != 'O');
				break;
		}
	}
}


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

	assert(msg != NULL);

	message_get(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &cmd, MESSAGE_END);
	
	if (cmd && cmd[0] == 'P') {
		switch(cmd[1]) {
			case 'j':
				/*MSG* Pj address
				 *
				 * Player Join
				 *
				 * Player has joined to the game.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_END))
				{
					playerlist_add(address);
					playerlist_update_connected(address, 1);
					playerlist_update_state(address, S_S_NONE, NULL);
					gui_append_to_chat(NULL, GUI_CHAT_SYS, _("%s se připojil(a)"), playerlist_get_nick(address));
				}
				break;

			case 'p':
				/*MSG* Pp address
				 * 
				 * Player Part
				 *
				 * Player has left the game.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_END))
				{
					//playerlist_update_connected(address, 0);
					playerlist_remove(address);
					gui_append_to_chat(NULL, GUI_CHAT_SYS, _("%s se odpojil(a)"), playerlist_get_nick(address));
				}
				break;
				
			case 'i':
				/*MSG* Pi address nick role score conn_state
				 *
				 * Player Info
				 *
				 * Update player info. All values are strings.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, 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':
				/*MSG* Pn address nick
				 *
				 * Player Nick
				 *
				 * Update player's nickname.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &nick,
						MESSAGE_END))
				{
					playerlist_update(address, nick, NULL, NULL, NULL);
				}
				break;
				
			case 'r':
				/*MSG* Pr address role
				 *
				 * Player Role
				 *
				 * Update player role.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &role,
						MESSAGE_END))
				{
					playerlist_update(address, NULL, role, NULL, NULL);
				}
				break;
				
			case 's':
				/*MSG* Ps address score
				 *
				 * Player Score
				 *
				 * Update player's score.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &score,
						MESSAGE_END))
				{
					playerlist_update(address, NULL, NULL, score, NULL);
				}
				break;
				
			case 'c':
				/*MSG* Pc address conn_state
				 *
				 * Player Connection state
				 *
				 * Update player's connection state. It is just string shown
				 * in playerlist. Intended to show ping or something like that.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_STRING, &conn_state,
						MESSAGE_END))
				{
					playerlist_update(address, NULL, NULL, NULL, conn_state);
				}
				break;

			case 'g':
				/*MSG* Pg address
				 *
				 * Player Get
				 *
				 * Request for player info. Player list will reply
				 * with 'Pi' message.
				 */
				if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
						MESSAGE_STRING, &address,
						MESSAGE_END))
				{
					playerlist_get(address, &nick, &role, &score, &conn_state, NULL, NULL, NULL);
					reply = message_create('P', msg->src);
					message_append(reply, MESSAGE_PART_DATA, 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':
				/*MSG* Pl
				 *
				 * Player List
				 *
				 * Request for info about all players in game. Player list will reply with
				 * seqence of messages 'Plb', 'Pi', 'Pi', ..., 'Ple'.
				 */
				
				/* begin */
				reply = message_create('P', msg->src);
				message_append(reply, MESSAGE_PART_DATA, 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, NULL, &connected); i++) {
					if (address && connected) {
						reply = message_create('P', msg->src);
						message_append(reply, MESSAGE_PART_DATA, 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_PART_DATA, MESSAGE_STRING, "Ple", MESSAGE_END);
				message_send(reply);
				message_destroy(reply);

				break;
		}
	}
}


void msg_handle_session(MESSAGE *msg)
{
	char *cmd = NULL, *str = NULL;
	long remote = 0;
	int have_sender_info = 0;
	char *address = NULL;
	
	assert(msg != NULL);

	/* get command */
	message_get(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &cmd, MESSAGE_END);

	/* command must be 'S*' */
	if (!cmd || cmd[0] != 'S')
		return;

	/* get sender info */
	if (msg->src == 'N')
		have_sender_info = message_get(msg, MESSAGE_PART_SENDER_INFO, MESSAGE_STRING, &address, MESSAGE_INTEGER, &remote, MESSAGE_END);
	
	/* process message */
	DBG_MSG(3, "cmd = \"%s\"", cmd);
	switch (cmd[1]) {
		case 'c': 
			/*MSG* Sc description time state_id state_parameter
			 *
			 * State Changed
			 * 
			 * Notification, that peer has changed it's state.
			 */
			{
				long time;
				char *state, *state_param, *state_desc;
					
				if (have_sender_info && message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP, 
							MESSAGE_STRING, &state_desc,
							MESSAGE_INTEGER, &time,
							MESSAGE_STRING, &state,
							MESSAGE_STRING, &state_param,
							MESSAGE_END))
				{
					//char *game = NULL;
					//char *my_role = NULL;
					int state_id;

					if ((state_id = status_get_id_by_abbr(session_status, state)) == -1
							|| state_id > session_status->max_st)
					{
						gui_append_to_chat(NULL, GUI_CHAT_SYS, _("%s posílá blbosti"), playerlist_get_nick(address));
						break;
					}

					/* update info (player list, etc.) */
					session_update_info(time, cmd[1], state_id, state_param, state_desc, NULL, address, remote);

					/* process message */
					session_message_action_switch_param(time, cmd[1], state_id, state_param, address, remote);
				}
			}
			break;

			
		case 'q': /* session query */
			/*MSG* Sq description time
			 *
			 * Session Query
			 *
			 * What is state of all players ?  This sends client when connects into
			 * session.
			 */
			{
				long time;
				char *desc;
					
				if (have_sender_info && message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP, 
							MESSAGE_STRING, &desc,
							MESSAGE_INTEGER, &time,
							MESSAGE_END))
				{
					record_append(time, "q", address, remote, 0, NULL, 1, desc);
					session_send_state_info(address);
				}
			}
			break;

			
		case 'i': /* session info */
			/*MSG* Si description glob_time glob_state glob_game player_state player_state_param player_role my_addr my_role
			 *
			 * Session Info
			 *
			 * Player's state. Reply to "Sq".
			 */
			{
				long glob_time;
				char *glob_state, *player_state, *player_state_param, *desc, *glob_game, *player_role, *my_addr, *my_role;
				const char *my_real_addr;
					
				if (have_sender_info && message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
							MESSAGE_STRING, &desc,
							MESSAGE_INTEGER, &glob_time,
							MESSAGE_STRING, &glob_state,
							MESSAGE_STRING, &glob_game,
							MESSAGE_STRING, &player_state,
							MESSAGE_STRING, &player_state_param,
							MESSAGE_STRING, &player_role,
							MESSAGE_STRING, &my_addr,
							MESSAGE_STRING, &my_role,
							MESSAGE_END))
				{
					char *my_my_role = NULL;
					int glob_state_id, player_state_id;
					
					if ((glob_state_id = status_get_id_by_abbr(session_status, glob_state)) == -1
							|| glob_state_id > session_status->max_st
							|| (player_state_id = status_get_id_by_abbr(session_status, player_state)) == -1
							|| player_state_id > session_status->max_st)
					{
						gui_append_to_chat(NULL, GUI_CHAT_SYS, _("%s posílá blbosti"), playerlist_get_nick(address));
						break;
					}
					
					/* update info */
					session_update_info(glob_time, cmd[1], player_state_id, player_state_param, desc, player_role, address, remote);

					/* check if my_role is mine */
					if (remote) {
						my_real_addr = option_get_string("main", "net", "my_address");
						if (my_real_addr && my_addr && strcmp(my_real_addr, my_addr) == 0)
							my_my_role = my_role;
					}

					/* process message */
					session_message_action_switch(glob_time, cmd[1], glob_state_id, glob_game, my_my_role, address, remote);
				}
			}
			break;

			
		case 'o': /* online/offline */
			switch (cmd[2]) {
				case 'n':	/* online */
					/*MSG* Son my_address
					 *
					 * Status ONline
					 *
					 * Status notification.
					 */
					if (status_get(connection_status) == S_C_CONNECTING) {
						char *my_addr;
						if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP,
									MESSAGE_STRING, &my_addr,
									MESSAGE_END))
						{
							option_set_string("main", "net", "my_address", my_addr);
							status_switch(connection_status, S_C_CONNECTED, NULL);
						}
					}
					break;

				case 'f':	/* offline */
					/*MSG* Sof
					 *
					 * Status OFfline
					 * 
					 * Status notification.
					 */
					if (status_get(connection_status) != S_C_DISCONNECTING && status_get(connection_status) != S_C_EXITING) {
						status_switch(connection_status, S_C_CONNECTING, NULL);
					}
					break;
			}
			break;
			
		case 'g': /* game */
			switch (cmd[2]) {
				case 'l': /* loaded */
					/*MSG* Sgl
					 *
					 * Session Game Loaded
					 *
					 * Notify, that game has been successfuly loaded.
					 * 
					 */
					DBG_MSG(1, "Sgl: stat = %d", status_get(connection_status));
					if (status_get(session_status) == S_S_LOADING) {
						status_switch(session_status, S_S_LOADED, NULL);
					}
					break;
					
				case 'a': /* allow */
					/*MSG* Sga
					 *
					 * Session Game Allow
					 *
					 * Game start allowed.
					 */
					DBG_MSG(1, "Sga: stat = %d", status_get(connection_status));
					if (status_get(session_status) == S_S_READY) {
						status_switch(session_status, S_S_START_CHECK, NULL);
					}
					break;

				case 'd': /* deny */
					/*MSG* Sgd
					 *
					 * Session Game Deny
					 *
					 * Game start denied
					 */
					DBG_MSG(1, "Sgr: stat = %d", status_get(connection_status));
					if (status_get(session_status) == S_S_READY) {
						gui_append_to_chat(NULL, GUI_CHAT_SYS, _("Ještě nelze zahájit hru."));
						gui_show_error_message_async(_("Ještě nelze zahájit hru"),
								_("Herní modul odmítl zahájení hry. Nejspíš nejsou rozděleny všechny "
								  "potřebné role nebo jsou rozděleny špatně."));
						status_switch(session_status, S_S_LOADED, NULL);
					}
					break;
					
				case 'r': /* role list */
					/*MSG* Sgr roles
					 *
					 * Session Game Roles
					 *
					 * List of valid player roles. Observer is added automaticaly.
					 */
					message_get_rewind(msg, MESSAGE_PART_DATA);
					message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_SKIP, MESSAGE_END);
					roles_clear();
					roles_add(_("pozorovatel"));
					while (message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &str, MESSAGE_END)) {
						roles_add(str);
					}
					gui_role_select(0);
					break;

				case 'o': /* over */
					/*MSG* Sgo
					 *
					 * Session Game Over
					 *
					 * Game over.
					 */
					DBG_MSG(1, "Sgo");
					if (status_get(session_status) == S_S_GAME_PLAYING) {
						status_switch(session_status, S_S_GAME_OVER, NULL);
					}
					break;


			}
			break;

		case 't': /* turn -- forward only */
			/*MSG* St human_readable_description data
			 *
			 * Session Player Turn
			 */
			if (have_sender_info && msg->src == 'N') {
				message_edit(msg, 'S', 'G');
				message_send(msg);
			} else if (msg->src == 'G') {
				message_edit(msg, 'S', 'N');
				message_send(msg);
			}
			break;

		case 'u': /* surrender */
			/*MSG* Su
			 *
			 * Session sUrrender
			 *
			 * Player gives up.
			 */
			if (have_sender_info && msg->src == 'N') {
				char *role;
				playerlist_get(address, NULL, &role, NULL, NULL, NULL, NULL, NULL);
				if (role && role[0]) {
					message_edit(msg, 'S', 'G');
					message_send(msg);
				}
			}
			break;
			
	}
}


void msg_handle_network_profiles(MESSAGE *msg)
{
	char *cmd = NULL;
	long update = 0;
	
	assert(msg != NULL);

	/* only update window */
	if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &cmd, MESSAGE_INTEGER, &update, MESSAGE_END)) {
		if (strcmp(cmd, "Odc") == 0 && update && dialog_network_profiles) {
			DBG_MSG(3, "updating network profiles dialog...");
			gui_update_network_profiles();
			DBG_MSG(3, "updating network profiles dialog... done");
		}
	}
}


extern GTimer *debug_ping_timer[MESSAGE_MAX_TARGETS];

void msg_handle_test(MESSAGE *msg)
{
	char *cmd;
	
	assert(msg != NULL);

	/* get command */
	message_get(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &cmd, MESSAGE_END);

	/* command must be 'T*' */
	if (!cmd || cmd[0] != 'T')
		return;

	DBG_MSG(3, "");

	switch (cmd[1]) {
		case 'p': /* ping request */
			{
				MESSAGE *m;

				m = message_create(msg->dest, msg->src);
				message_append(m, MESSAGE_PART_DATA, MESSAGE_STRING, "Tr", MESSAGE_END);
				message_send(m);
				message_destroy(m);
			}
			break;

		case 'r': /* ping reply */
			if (debug_ping_timer[(int)msg->src]) {
				gulong usec, sec;

				sec = (long) g_timer_elapsed(debug_ping_timer[(int)msg->src], &usec);
				gui_append_to_chat(NULL, GUI_CHAT_SYS, "Ping reply from \"%s\" in %lu sec %lu usec",
						message_get_target_description(msg->src),
						sec, usec);

				g_timer_destroy(debug_ping_timer[(int)msg->src]);
				debug_ping_timer[(int)msg->src] = NULL;
			}
			break;
	}

}

/* vim:set encoding=utf8: */
