/*
 * connection.c
 * 
 * Copyright (C) 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 <stdio.h>
#include <assert.h>

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

#define DEBUG 0
#include "debug.h"

STATUS *connection_status = NULL;
BACKEND *backend_network = NULL;


static void on_backend_exit(void) {
	status_switch(connection_status, S_C_OFFLINE, NULL);
}


static void on_backend_cleanup(void) {
	gui_append_to_netlog("-- Spojení uzavřeno.\n\n");
	backend_network = NULL;
}


static void enter_offline (STATUS *st) {
	DBG_MSG(5, "");

	playerlist_update_connected_all(0);
	gui_set_statusbar_progress(0, 0.0, "");
	gui_append_to_chat(NULL, GUI_CHAT_SYS, "Odpojen.");
	
	gui_store_options_with_info();

	switch (st->last_st) {
		case S_C_EXITING:
			gtk_main_quit();
			break;

		case S_C_RECONNECT:
			status_switch(connection_status, S_C_CONNECTING, NULL);
			break;
	}
}


static void leave_offline (STATUS *st) {
	DBG_MSG(5, "");
}


static void enter_connecting (STATUS *st) {
	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, "");
	assert(backend_network == NULL);

	/* 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(NULL, GUI_CHAT_SYS, "Připojuji k \"%s\" (%s)...", net_address, net_backend);
	gui_append_to_netlog("-- Start: backend \"%s\", adresa \"%s\"...\n", net_backend, net_address);
	
	playerlist_clear_state();
	gui_switch_main_page(GUI_PAGE_CHAT);

	argv[0] = (char*) net_backend;
	argv[2] = (char*) net_profile;
	argv[4] = (char*) net_address;

	/* additional options */
	log = option_get_integer("main", "debug", "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, GUI_LOG_NET);
	if (backend_network) {
		/* set callbacks */
		backend_network->on_exit_cb = on_backend_exit;
		backend_network->on_cleanup_cb = on_backend_cleanup;

		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");
		status_switch(connection_status, S_C_OFFLINE, NULL);
	}
}


static void leave_connecting (STATUS *st) {
	DBG_MSG(5, "");
}


static void enter_connected (STATUS *st) {

	DBG_MSG(5, "");

	//if (st->last_st != S_C_GAME_ENDING)
	//	gui_switch_main_page(GUI_PAGE_CHAT);
	//	
	
	session_update_global_state(status_get_time(session_status), status_get(session_status),
			option_get_string("main", "game", "backend"),
			option_get_string("main", "game", "my_role"));

	session_send_sync_rq();

	gui_append_to_chat(NULL, GUI_CHAT_SYS, "Připojen.");
}


static void leave_connected (STATUS *st) {
	DBG_MSG(5, "");
}


static void enter_disconnecting (STATUS *st) {
	DBG_MSG(5, "");
	gui_append_to_chat(NULL, GUI_CHAT_SYS, "Odpojuji se...");
	if (backend_network) {
		backend_kill(backend_network);
	} else {
		status_switch(connection_status, S_C_OFFLINE, NULL);
	}
}


static void leave_disconnecting (STATUS *st) {
	DBG_MSG(5, "");
}


static void enter_exiting (STATUS *st) {
	DBG_MSG(5, "(including S_C_DISCONNECTING)");
	enter_disconnecting(st);
}


static void leave_exiting (STATUS *st) {
	DBG_MSG(5, "(including S_C_DISCONNECTING)");
	leave_disconnecting(st);
}


static void enter_reconnect (STATUS *st) {
	DBG_MSG(5, "(including S_C_DISCONNECTING)");
	enter_disconnecting(st);
}


static void leave_reconnect (STATUS *st) {
	DBG_MSG(5, "(including S_C_DISCONNECTING)");
	leave_disconnecting(st);
}


static void after_switch (STATUS *st)
{
	gui_update_expanders();
	gui_update_main_window();
}

void connection_init(void)
{
	struct s_status_table status_table[] = {
		/* stav			zkr.	pri vstupu		pri opousteni		*/
		{ "none",		NULL,	NULL,			NULL			},
		{ "offline",		NULL,	enter_offline,		leave_offline		},
		{ "connecting",		NULL,	enter_connecting,	leave_connecting	},
		{ "connected",		NULL,	enter_connected,	leave_connected		},
		{ "disconnecting",	NULL,	enter_disconnecting,	leave_disconnecting	},
		{ "exiting",		NULL,	enter_exiting,		leave_exiting		},
		{ "reconnect",		NULL,	enter_reconnect,	leave_reconnect		}
	};
	
	connection_status = status_create("connection", status_table, sizeof(status_table)/sizeof(status_table[0]));
	connection_status->cb_after_switch = after_switch;
}

void connection_cleanup(void)
{
	status_destroy(connection_status);
}


