#include "com_move.h"
#include "room.h"
#include "move.h"
#include "random_functs.h"
#include "stringops.h"

typedef struct link_valid_list_elt
{
	link *l;
	struct link_valid_list_elt *next;
} link_valid_list_elt;

typedef struct link_valid_list
{
	link_valid_list_elt *head;
	int size;
} link_valid_list;

static char word[128];

static link *command_move_random (globals *g)
{
	room_queue_elt *room_visited;
	link *scan;

	#ifdef FUNCTIONS
	puts ("<command_move_random>");
	#endif

	for (room_visited = g->rooms_visited->head; room_visited != NULL;
		room_visited = room_visited->next)
	{
		for (scan = g->room_current->links->head; scan != NULL;
			scan = scan->next)
		{
			if ((scan->dest == room_visited->room) &&
				(random_int () % 2 == 0))
				return scan;
		}
	}

	if (g->room_current->links->head != NULL)
	{
		return (link_find_num (g->room_current->links,
			random_int () % g->room_current->links->size + 1));
	}
	else
	{
		if (random_int () % g->moveodds == 0)
		{
			socket_write (g->socket, g->home_str);
			room_queue_add (g->rooms_visited, g->room_current,
				g->movequeuesize);
			g->room_current = g->room_home;
		}
	}
	return NULL;
}

static link_valid_list *command_move_valid_list (room_queue *rq, room *r)
{
	link *lscan;
	room_queue_elt *rscan;
	link_valid_list *lvl = NULL;
	link_valid_list_elt *lvle;
	int flag;

	#ifdef FUNCTIONS
	puts ("<command_move_valid_list>");
	#endif

	lvl = allocate (link_valid_list);
	lvl->head = NULL;
	lvl->size = 0;

	for (lscan = r->links->head; lscan != NULL; lscan = lscan->next)
	{
		flag = 0;
		for (rscan = rq->head; rscan != NULL; rscan = rscan->next)
		{
			if (lscan->dest == rscan->room) flag = 1;
		}

		if (flag == 0)
		{
			lvle = allocate (link_valid_list_elt);
			lvle->l = lscan;
			lvle->next = lvl->head;
			lvl->head = lvle;
			(lvl->size)++;
		}
	}

	return lvl;
}

static void command_move_valid_list_elements_burn (link_valid_list_elt *lvle)
{
	#ifdef FUNCTIONS
	puts ("<command_move_valid_list_elements_burn>");
	#endif

	if (lvle != NULL)
	{
		command_move_valid_list_elements_burn (lvle->next);
		free (lvle);
	}
}

static void command_move_valid_list_burn (link_valid_list *lvl)
{
	#ifdef FUNCTIONS
	puts ("<command_move_valid_list_burn>");
	#endif

	command_move_valid_list_elements_burn (lvl->head);
	free (lvl);
}

static link *command_move_valid_list_num (link_valid_list *lvl, int n)
{
	link_valid_list_elt *scan;
	#ifdef FUNCTIONS
	puts ("<command_move_valid_list_num>");
	#endif

	for (scan = lvl->head; (scan != NULL) && (n > 1);
		scan = scan->next, n--);

	return scan->l;
}

void command_move (globals *g, char *l)
{
	link *link = NULL;
	link_valid_list *lvl;

	#ifdef FUNCTIONS
	puts ("**command_move");
	#endif

	if (g->room_current == NULL)
		return;
	if (g->room_current->links->head == NULL)
		return;

	l = tokenize (word, l);

	if (strlen (word) > 0)
		link = link_find (g->room_current->links, word);

	if (link == NULL)
	{
		if (g->rooms_visited->size > 0)
		{
			lvl = command_move_valid_list (g->rooms_visited,
				g->room_current);
			
			if (lvl->size > 0)
			{
				link = command_move_valid_list_num (lvl,
					random_int () % lvl->size + 1);
				command_move_valid_list_burn (lvl);
			}
			else
			{
				link = link_find_num (g->room_current->links,
					random_int () %
					g->room_current->links->size + 1);
			}
		}
		else
			link = command_move_random (g);
	}

	if (g->movequeuesize > 0)
		room_queue_add (g->rooms_visited, g->room_current,
			g->movequeuesize);

	if (link != NULL)
	{
		g->room_current = link->dest;
		socket_write (g->socket, link->name);
	}
}