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

#define DEBUG 		0
#include "debug.h"

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

static STATUS actual_status = S_OFFLINE, last_status = S_OFFLINE;


void enter_offline (void) {
	DBG_MSG(5, "enter_offline");
	disable_board();
	gui.is_online = 0;

	playerlist_remove_all();

	/* be sure, that backends are down */
	if (backend_game)
		backend_kill(backend_game);
	if (backend_network)
		backend_kill(backend_network);

	set_statusbar_text("Odpojen.");
	set_statusbar_progress(0, 0.0, "");
	append_to_chat("-- Odpojen.\n");
	
	store_options_with_info();

	if (last_status == S_EXITING)
		gtk_main_quit();
}


void leave_offline (void) {
	DBG_MSG(5, "leave_offline");
}


void enter_connecting (void) {
	gchar *argv[] = { NULL, NULL, NULL };
	const char *net_address, *net_backend;
	
	DBG_MSG(5, "enter_connecting");

	gui.is_online = 0;
	set_statusbar_text("Připojuji se...");

	if (!backend_network) {
		switch_main_page(GUI_PAGE_CHAT);

		net_backend = option_get_string("main", "net.backend");
		net_address = option_get_string("main", "net.address");
		
		DBG_MSG(3, "Pripojeni:");
		DBG_MSG(3, "  backend:  %s", net_backend);
		DBG_MSG(3, "  address:  %s", net_address);

		append_to_chat("\n-- Připojuji k \"%s\" (%s)...\n", net_address, net_backend);
		append_to_netlog("-- Start: backend \"%s\", adresa \"%s\"...\n", net_backend, net_address);

		argv[0] = (char*) net_backend;
		argv[1] = (char*) net_address;
		
		dir_update();
		backend_network = backend_spawn('N', option_get_string("main", "dir.network"), argv);
		if (backend_network) {
			append_to_netlog("-- Backend spuštěn (pid %d)...\n", backend_network->pid);
		} else {
			append_to_netlog("-- Chyba při spouštění backendu\n");
			switch_to_status(S_OFFLINE);
		}
	}
}


void leave_connecting (void) {
	DBG_MSG(5, "leave_connecting");
	set_statusbar_text(GUI_ICON_NONE, "");
}


void enter_connected (void) {
	DBG_MSG(5, "enter_connected");
	gui.is_online = 1;
	gui.is_paused = 0;
	gui.can_select_game = 1;
	gui.can_select_role = 0;
	gui.can_start_game = 0;
	gui.can_end_game = 0;

	if (last_status != S_GAME_ENDING)
		switch_main_page(GUI_PAGE_CHAT);

	playerlist_clear_ack();

	if (last_status == S_CONNECTING)
		append_to_chat("-- Připojen.\n");
	else
		append_to_chat("-- Hra skončila. Připojen.\n");
}


void leave_connected (void) {
	DBG_MSG(5, "leave_connected");
}

void enter_load_starting (void) {
	MESSAGE *msg;
	char *desc;
	const char *game;
	
	DBG_MSG(5, "enter_starting");
	
	game = option_get_string("main", "game.backend");
	desc = g_strdup_printf(_("Budeme hrát %s"), game);
	
	msg = message_create('S', 'N');
	message_append(msg, MESSAGE_STRING, "Spg", MESSAGE_STRING, desc, MESSAGE_STRING, game, MESSAGE_END);
	message_send(msg);
	message_destroy(msg);

	g_free(desc);

	switch_to_status(S_LOADING);
}

void leave_load_starting (void) {
	DBG_MSG(5, "leave_starting");
}

void enter_loading (void) {
	MESSAGE *msg;
	gchar *argv[] = { NULL, NULL };
	const char *backend;
	
	DBG_MSG(5, "enter_loading");
	assert(backend_game == NULL);
	
	gui.can_select_game = 0;
	gui.can_select_role = 0;
	gui.can_start_game = 0;
	gui.can_end_game = 0;
	gui_role_clear();

	backend = option_get_string("main", "game.backend");
	
	DBG_MSG(3, "Hra:");
	DBG_MSG(3, "  backend:  %s", backend);

	append_to_chat("\n-- Spouštím hru \"%s\" ...\n", backend);
	append_to_gamelog("\n-- Spouštím backend \"%s\" ...\n", backend);

	argv[0] = (char*) backend;
	
	dir_update();
	backend_game = backend_spawn('G', option_get_string("main", "dir.game"), argv);
	if (backend_game) {
		append_to_gamelog("-- Backend spuštěn (pid %d)...\n", backend_network->pid);
	} else {
		msg = message_create('S', 'N');
		message_append(msg, MESSAGE_STRING, "Spr", MESSAGE_STRING, _("Nebudu hrát."), MESSAGE_END);
		message_send(msg);
		message_destroy(msg);
		append_to_gamelog("-- Chyba při spouštění backendu\n");
		switch_to_status(S_CONNECTED);
	}
}


void leave_loading (void) {
	DBG_MSG(5, "leave_loading");
}


void enter_loaded (void) {
	MESSAGE *msg;

	DBG_MSG(5, "enter_loaded");

	gui.can_select_role = 1;
	gui.can_start_game = 1;
	
	append_to_gamelog("-- Backend připraven.\n");
	switch_main_page(GUI_PAGE_CHAT);

	/* send ack */
	msg = message_create('S', 'N');
	message_append(msg, MESSAGE_STRING, "Spa", MESSAGE_STRING, "jsem připraven", MESSAGE_END);
	message_send(msg);
	message_destroy(msg);
}


void leave_loaded (void) {
	DBG_MSG(5, "leave_loaded");
}


void enter_game_check (void) {
	MESSAGE *msg;

	DBG_MSG(5, "enter_game_check");
	
	gui.can_select_role = 0;
	gui.can_start_game = 0;

	/* send check request */
	msg = message_create('S', 'G');
	message_append(msg, MESSAGE_STRING, "Sgc", MESSAGE_END);
	message_send(msg);
	message_destroy(msg);
}


void leave_game_check (void) {
	DBG_MSG(5, "leave_game_check");
}


void enter_game_starting (void) {
	MESSAGE *msg;

	DBG_MSG(5, "enter_game_starting");
	append_to_gamelog("-- Zahajuji hru.\n");
	append_to_chat("-- Zahajuji hru. Čekám na ostatní.\n");
	
	/* send ack */
	msg = message_create('S', 'N');
	message_append(msg, MESSAGE_STRING, "Spb", MESSAGE_STRING, "Hrajem!", MESSAGE_END);
	message_send(msg);
	message_destroy(msg);
}


void leave_game_starting (void) {
	DBG_MSG(5, "leave_game_starting");
}


void enter_game_playing (void) {
	MESSAGE *msg;
	DBG_MSG(5, "enter_game_playing");

	append_to_chat("-- Hra zahájena.\n");

	/* poslat info game backendu a uz jen pockat nez to skonci */
	msg = message_create('S', 'G');
	message_append(msg, MESSAGE_STRING, "Sgs", MESSAGE_END);
	message_send(msg);
	message_destroy(msg);

	switch_main_page(GUI_PAGE_DESK);
}


void leave_game_playing (void) {
	DBG_MSG(5, "leave_game_playing");
}


void enter_game_ending (void) {
	MESSAGE *msg;
	
	DBG_MSG(5, "enter_game_ending");
	
	/* poslat info o tom, ze sme skoncili */
	msg = message_create('S', 'N');
	message_append(msg, MESSAGE_STRING, "Spo", MESSAGE_STRING, "Končím hru.", MESSAGE_END);
	message_send(msg);
	message_destroy(msg);
	
	append_to_chat("-- Hra ukončena. Čekám na ostatní hráče.\n");
}


void leave_game_ending (void) {
	DBG_MSG(5, "leave_game_ending");
}


void enter_out_of_sync (void) {
	DBG_MSG(5, "enter_out_of_sync");
}


void leave_out_of_sync (void) {
	DBG_MSG(5, "leave_out_of_sync");
}


void enter_disconnecting (void) {
	DBG_MSG(5, "enter_disconnecting");
	set_statusbar_text("Odpojuji se...");
	if (backend_network || backend_game) {
		if (backend_network)
			backend_kill(backend_network);
		if (backend_game)
			backend_kill(backend_game);
	} else {
		switch_to_status(S_OFFLINE);
	}
}


void leave_disconnecting (void) {
	DBG_MSG(5, "leave_disconnecting");
}


void enter_exiting (void) {
	DBG_MSG(5, "enter_exiting (including S_DISCONNECTING)");
	enter_disconnecting();
}


void leave_exiting (void) {
	DBG_MSG(5, "leave_exiting (including S_DISCONNECTING)");
	leave_disconnecting();
}


/*****************************************************************************
 *	manipulace se stavy
 ****************************************************************************/

struct s_status_table status_table[] = {
	/* stav		 	    pri vstupu		 pri opousteni		*/
	/* S_OFFLINE	 	*/{ enter_offline,	 leave_offline		},
	/* S_CONNECTING	 	*/{ enter_connecting,	 leave_connecting	},
	/* S_CONNECTED	 	*/{ enter_connected,	 leave_connected	},
	/* S_LOAD_STARTING	*/{ enter_load_starting, leave_load_starting	},
	/* S_LOADING	 	*/{ enter_loading,	 leave_loading		},
	/* S_LOADED	 	*/{ enter_loaded,	 leave_loaded		},
	/* S_GAME_CHECK	 	*/{ enter_game_check,	 leave_game_check	},
	/* S_GAME_STARTING 	*/{ enter_game_starting, leave_game_starting	},
	/* S_GAME_PLAYING 	*/{ enter_game_playing,	 leave_game_playing	},
	/* S_GAME_ENDING 	*/{ enter_game_ending,	 leave_game_ending	},
	/* S_OUT_OF_SYNC 	*/{ enter_out_of_sync,	 leave_out_of_sync	},
	/* S_DISCONNECTING	*/{ enter_disconnecting, leave_disconnecting	},
	/* S_EXITING		*/{ enter_exiting,	 leave_exiting		},
	/* S_MAX	 	*/{ NULL,		 NULL,			}
};


void switch_to_status (STATUS new_status) {
	DBG_MSG(6, "Changing state from %d to %d", actual_status, new_status);
	if (new_status < S_MAX) {
		if (new_status != actual_status) {
			if (status_table[actual_status].fn_leave)
				(*status_table[actual_status].fn_leave)();
			
			last_status = actual_status;
			actual_status = new_status;
			
			if (status_table[new_status].fn_enter)
				(*status_table[new_status].fn_enter)();
			
			update_main_window();
		}
	} else {
		fprintf(stderr, "netboard: Fatal error - wrong new status %d (old %d).\n",
				new_status, actual_status);
		exit(-1);
	}
}


STATUS get_status (void) {
	return actual_status;
}

/* vim:set encoding=utf8: */
