/**
 * @file cmdproc.c NATEON command processor functions
 *
 * purple
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "nateon.h"
#include "cmdproc.h"

NateonCmdProc *
nateon_cmdproc_new(NateonSession *session)
{
	NateonCmdProc *cmdproc;

	cmdproc = g_new0(NateonCmdProc, 1);

	cmdproc->session = session;
	cmdproc->txqueue = g_queue_new();
	cmdproc->history = nateon_history_new();

	return cmdproc;
}

void
nateon_cmdproc_destroy(NateonCmdProc *cmdproc)
{
	NateonTransaction *trans;

	while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL)
		nateon_transaction_destroy(trans);

	g_queue_free(cmdproc->txqueue);

	nateon_history_destroy(cmdproc->history);

	if (cmdproc->last_cmd != NULL)
		nateon_command_destroy(cmdproc->last_cmd);

	g_free(cmdproc);
}

void
nateon_cmdproc_process_queue(NateonCmdProc *cmdproc)
{
	NateonTransaction *trans;

	while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL)
		nateon_cmdproc_send_trans(cmdproc, trans);
}

void
nateon_cmdproc_queue_trans(NateonCmdProc *cmdproc, NateonTransaction *trans)
{
	g_return_if_fail(cmdproc != NULL);
	g_return_if_fail(trans   != NULL);

	g_queue_push_tail(cmdproc->txqueue, trans);
}

static void
show_debug_cmd(NateonCmdProc *cmdproc, gboolean incoming, const char *command)
{
	NateonServConn *servconn;
	const char *names[] = { "NS", "SB" };
	char *show;
	char tmp;
	size_t len;

	servconn = cmdproc->servconn;
	len = strlen(command);
	show = g_strdup(command);

	tmp = (incoming) ? 'S' : 'C';

	if ((show[len - 1] == '\n') && (show[len - 2] == '\r'))
	{
		show[len - 2] = '\0';
	}

	purple_debug_misc("nateon", "%c: %s %03d: %s\n", tmp,
					names[servconn->type], servconn->num, show);

	g_free(show);
}

void
nateon_cmdproc_send_trans(NateonCmdProc *cmdproc, NateonTransaction *trans)
{
	NateonServConn *servconn;
	char *data;
	size_t len;

	g_return_if_fail(cmdproc != NULL);
	g_return_if_fail(trans != NULL);

	servconn = cmdproc->servconn;

	if (!servconn->connected)
		return;

	nateon_history_add(cmdproc->history, trans);

	data = nateon_transaction_to_string(trans);

	len = strlen(data);

	show_debug_cmd(cmdproc, FALSE, data);

	if (trans->callbacks == NULL)
		trans->callbacks = g_hash_table_lookup(cmdproc->cbs_table->cmds, trans->command);

	if (trans->payload != NULL)
	{
		data = g_realloc(data, len + trans->payload_len);
		memcpy(data + len, trans->payload, trans->payload_len);
		len += trans->payload_len;
	}

	nateon_servconn_write(servconn, data, len);

	g_free(data);
}

//void
//nateon_cmdproc_send_quick(NateonCmdProc *cmdproc, const char *command,
//					   const char *format, ...)
//{
//	NateonServConn *servconn;
//	char *data;
//	char *params = NULL;
//	va_list arg;
//	size_t len;
//
//	g_return_if_fail(cmdproc != NULL);
//	g_return_if_fail(command != NULL);
//
//	servconn = cmdproc->servconn;
//
//	if (!servconn->connected)
//		return;
//
//	if (format != NULL)
//	{
//		va_start(arg, format);
//		params = g_strdup_vprintf(format, arg);
//		va_end(arg);
//	}
//
//	if (params != NULL)
//		data = g_strdup_printf("%s %s\r\n", command, params);
//	else
//		data = g_strdup_printf("%s\r\n", command);
//
//	g_free(params);
//
//	len = strlen(data);
//
//	show_debug_cmd(cmdproc, FALSE, data);
//
//	nateon_servconn_write(servconn, data, len);
//
//	g_free(data);
//}

void
nateon_cmdproc_send(NateonCmdProc *cmdproc, const char *command,
				 const char *format, ...)
{
	NateonTransaction *trans;
	va_list arg;

	g_return_if_fail(cmdproc != NULL);
	g_return_if_fail(command != NULL);

	if (!cmdproc->servconn->connected)
		return;

	trans = g_new0(NateonTransaction, 1);

	trans->command = g_strdup(command);

	if (format != NULL)
	{
		va_start(arg, format);
		trans->params = g_strdup_vprintf(format, arg);
		va_end(arg);
	}

	nateon_cmdproc_send_trans(cmdproc, trans);
}

void
nateon_cmdproc_process_payload(NateonCmdProc *cmdproc, char *payload,
							int payload_len)
{
	NateonCommand *last;

	g_return_if_fail(cmdproc != NULL);

	last = cmdproc->last_cmd;
	last->payload = g_memdup(payload, payload_len);
	last->payload_len = payload_len;

	if (last->payload_cb != NULL)
		last->payload_cb(cmdproc, last, payload, payload_len);
}

//void
//nateon_cmdproc_process_msg(NateonCmdProc *cmdproc, NateonMessage *msg)
//{
//	NateonMsgTypeCb cb;
//
//	if (nateon_message_get_content_type(msg) == NULL)
//	{
//		purple_debug_misc("nateon", "failed to find message content\n");
//		return;
//	}
//
//	cb = g_hash_table_lookup(cmdproc->cbs_table->msgs,
//							 nateon_message_get_content_type(msg));
//
//	if (cb == NULL)
//	{
//		purple_debug_warning("nateon", "Unhandled content-type '%s'\n",
//						   nateon_message_get_content_type(msg));
//
//		return;
//	}
//
//	cb(cmdproc, msg);
//}

void
nateon_cmdproc_process_cmd(NateonCmdProc *cmdproc, NateonCommand *cmd)
{
	NateonTransCb cb = NULL;
	NateonTransaction *trans = NULL;

	if (cmd->trId)
		trans = nateon_history_find(cmdproc->history, cmd->trId);

	if (trans != NULL)
		if (trans->timer)
			purple_timeout_remove(trans->timer);

	if (g_ascii_isdigit(cmd->command[0]))
	{
		if (trans != NULL)
		{
			NateonErrorCb error_cb = NULL;
			int error;

			error = atoi(cmd->command);

			if (trans->error_cb != NULL)
				error_cb = trans->error_cb;

			if (error_cb == NULL && cmdproc->cbs_table->errors != NULL)
				error_cb = g_hash_table_lookup(cmdproc->cbs_table->errors, trans->command);

			if (error_cb != NULL)
			{
				error_cb(cmdproc, trans, error);
			}
			else
			{
#if 1
				nateon_error_handle(cmdproc->session, error);
#else
				purple_debug_warning("nateon", "Unhandled error '%s'\n",
								   cmd->command);
#endif
			}

			return;
		}
	}

	if (cmdproc->cbs_table->async != NULL)
		cb = g_hash_table_lookup(cmdproc->cbs_table->async, cmd->command);

	if (cb == NULL && trans != NULL)
	{
		cmd->trans = trans;

		if (trans->callbacks != NULL)
			cb = g_hash_table_lookup(trans->callbacks, cmd->command);
	}
//
//	if (cb == NULL && cmdproc->cbs_table->fallback != NULL)
//		cb = g_hash_table_lookup(cmdproc->cbs_table->fallback, cmd->command);

	if (cb != NULL)
	{
		cb(cmdproc, cmd);
	}
	else
	{
		purple_debug_warning("nateon", "Unhandled command '%s'\n",
						   cmd->command);
	}

//	if (trans != NULL && trans->pendent_cmd != NULL)
//		nateon_transaction_unqueue_cmd(trans, cmdproc);
}

void
nateon_cmdproc_process_cmd_text(NateonCmdProc *cmdproc, const char *command)
{
	show_debug_cmd(cmdproc, TRUE, command);

	if (cmdproc->last_cmd != NULL)
		nateon_command_destroy(cmdproc->last_cmd);

	cmdproc->last_cmd = nateon_command_from_string(command);

	nateon_cmdproc_process_cmd(cmdproc, cmdproc->last_cmd);
}
