/*
 * status.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.
 *
 */
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define DEBUG 		0
#include "debug.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");
	gui_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);

	gui_set_statusbar_text("Odpojen.");
	gui_set_statusbar_progress(0, 0.0, "");
	gui_append_to_chat("-- Odpojen.\n");
	
	gui_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, "-P", NULL, "-A", NULL, NULL, NULL };
	gchar *log_level[] = { "-q", NULL, "-v", "-d" };
	const char *net_profile, *net_address, *net_backend, *net_log_level;
	int log;
	
	DBG_MSG(5, "enter_connecting");

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

	if (!backend_network) {
		gui_switch_main_page(GUI_PAGE_CHAT);

		/* base options */
		net_profile = option_get_string("main", "net", "profile");
		net_backend = option_get_string("main", "net", "backend");
		net_address = option_get_string("main", "net", "address");
		
		DBG_MSG(3, "Pripojeni:");
		DBG_MSG(3, "  profile:  %s", net_profile);
		DBG_MSG(3, "  backend:  %s", net_backend);
		DBG_MSG(3, "  address:  %s", net_address);

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

		argv[0] = (char*) net_backend;
		argv[2] = (char*) net_profile;
		argv[4] = (char*) net_address;
	
		/* additional options */
		log = option_get_integer("main", "ui", "enable_comm_log");
		net_log_level = option_get_string("network", net_profile, "log_level");
		
		if (net_log_level) {
			int log_level_n;

			log_level_n = net_log_level[0] - '0';
			if (log_level_n >= 0 && log_level_n < sizeof(log_level))
				argv[5] = log_level[log_level_n];
		}
	
		/* spawn */
		dir_update();
		backend_network = backend_spawn('N', option_get_string("main", "dir", "network"), argv, log);
		if (backend_network) {
			gui_append_to_netlog("-- Backend spuštěn (pid %d)...\n", backend_network->pid);
		} else {
			gui_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");
	gui_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)
		gui_switch_main_page(GUI_PAGE_CHAT);

	playerlist_clear_ack();

	if (last_status == S_CONNECTING)
		gui_append_to_chat("-- Připojen.\n");
	else
		gui_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;
	int log;
	
	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");
	log = option_get_integer("main", "ui", "enable_comm_log");
	
	DBG_MSG(3, "Hra:");
	DBG_MSG(3, "  backend:  %s", backend);

	gui_append_to_chat("\n-- Spouštím hru \"%s\" ...\n", backend);
	gui_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, log);
	if (backend_game) {
		gui_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);
		gui_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;
	
	gui_append_to_gamelog("-- Backend připraven.\n");
	gui_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");
	gui_append_to_gamelog("-- Zahajuji hru.\n");
	gui_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");

	gui_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);

	gui_switch_main_page(GUI_PAGE_BOARD);
}


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);
	
	gui_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");
	gui_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)();
			
			gui_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: */
