#include <stdio.h>
#include <ctype.h>
#include "room.h"
#include "stringops.h"

room_list *room_load (char *file)
{
	room_list *rl = NULL;
	room *tempr, *tempd;
	FILE *f;
	char input[256];
	int src, dst;

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

	rl = allocate (room_list);
	rl->head = rl->tail = NULL;
	rl->size = 0;

	f = fopen (file, "r");
	if (f == NULL)
		return rl;

	fgets (input, 255, f);
	clipret (input);

	while (!feof(f) && (strcmp (input, "---")))
	{
		room_add (rl, input);
		fgets (input, 255, f);
		clipret (input);
	}

	if (!feof(f))
	{
		fscanf (f, "%d %d ", &src, &dst);
		fgets (input, 255, f);
		clipret (input);

		while (!feof(f))
		{
			tempr = room_find_num (rl, src);
			tempd = room_find_num (rl, dst);

			link_add (tempr->links, tempd, input);
			fscanf (f, "%d %d ", &src, &dst);
			fgets (input, 255, f);
			clipret (input);
		}
	}

	fclose (f);

	return rl;
}

void room_save (room_list *rl, char *file)
{
	FILE *f;
	room *scan;
	link *linkscan;
	int num = 1;

	f = fopen (file, "w");
	if (f == NULL) return;

	for (scan = rl->head; scan != NULL; scan = scan->next)
	{
		fputs (scan->name, f);
		putc ('\n', f);
	}
	fputs ("---\n", f);
	for (scan = rl->head; scan != NULL; scan = scan->next, num++)
	{
		for (linkscan = scan->links->head; linkscan != NULL;
			linkscan = linkscan->next)
		{
			fprintf (f, "%d %d %s\n", num,
				room_num (rl, linkscan->dest), linkscan->name);
		}
	}
	fclose (f);
}

void room_add (room_list *rl, char *name)
{
	room *new;

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

	new = allocate (room);
	copystring (new->name, name);

	new->links = allocate (link_list);
	new->links->head = new->links->tail = NULL;
	new->links->size = 0;

	new->next = NULL;

	if (rl->tail != NULL)
		rl->tail->next = new;
	else
		rl->head = new;

	rl->tail = new;

	(rl->size)++;
}

void room_delete (room_list *rl, room *dead)
{
	room *scan;
	link *link_scan;

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

	if ((rl == NULL) || (rl->head == NULL))
		return;

	for (scan = rl->head; scan != NULL; scan = scan->next)
	{
		if (scan != dead)
		{
			for (link_scan = scan->links->head; link_scan != NULL;
				link_scan = link_scan->next)
			{
				if (link_scan->dest == dead)
					link_delete (scan->links, link_scan);
			}
		}
	}

	if (rl->head == dead)
	{
		rl->head = dead->next;
		if (rl->head == NULL)
		{
			rl->tail = NULL;
		}

		link_burn (dead->links);
		free (dead->name);
		free (dead);

		(rl->size)--;
	}
	else
	{
		for (scan = rl->head;
			(scan->next != NULL) && (scan->next != dead);
			scan = scan->next);
		if (scan->next != NULL)
		{
			if (scan->next == rl->tail) rl->tail = scan;
			scan->next = scan->next->next;
			
			link_burn (dead->links);
			free (dead);

			(rl->size)--;
		}
	}
}

room *room_find (room_list *rl, char *name)
{
	room *scan;

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

	if (isdigit (*name)) return (room_find_num (rl, atoi(name)));

	for (scan = rl->head;
		(scan != NULL) && (strcasecmp (name, scan->name));
		scan = scan->next);
	return scan;
}

room *room_find_num (room_list *rl, int n)
{
	room *scan;

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

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

static void room_elements_burn (room *r)
{
	#ifdef FUNCTIONS
	puts ("<room_elements_burn>");
	#endif

	if (r != NULL)
	{
		room_elements_burn (r->next);
		link_burn (r->links);
		free (r->name);
		free (r);
	}
}

void room_burn (room_list *rl)
{
	#ifdef FUNCTIONS
	puts ("**room_burn");
	#endif

	if (rl != NULL)
	{
		room_elements_burn (rl->head);
		free (rl);
	}
}

void link_add (link_list *ll, room *dest, char *name)
{
	link *new;

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

	new = allocate (link);
	copystring (new->name, name);
	new->dest = dest;
	new->next = NULL;

	if (ll->tail != NULL) ll->tail->next = new;
	else ll->head = new;
	ll->tail = new;

	(ll->size)++;
}

void link_delete (link_list *ll, link *dead)
{
	#ifdef FUNCTIONS
	puts ("**link_delete");
	#endif

	if ((ll == NULL) || (ll->head == NULL))
		return;

	if (ll->head == dead)
	{
		ll->head = dead->next;

		free (dead->name);
		free (dead);

		(ll->size)--;
	}
	else
	{
		link *scan;
		for (scan = ll->head;
			(scan->next != NULL) && (scan->next != dead);
			scan = scan->next);
		if (scan->next != NULL)
		{
			if (scan->next == ll->tail) ll->tail = scan;

			scan->next = scan->next->next;

			free (dead->name);
			free (dead);

			(ll->size)--;
		}
	}
}

link *link_find (link_list *ll, char *name)
{
	link *scan;

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

	for (scan = ll->head;
		(scan != NULL) && (strcasecmp (name, scan->name));
		scan = scan->next);

	return scan;
}

link *link_find_num (link_list *ll, int n)
{
	link *scan;

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

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

static void link_elements_burn (link *l)
{
	#ifdef FUNCTIONS
	puts ("<link_elements_burn>");
	#endif

	if (l != NULL)
	{
		link_elements_burn (l->next);
		free (l->name);
		free (l);
	}
}

void link_burn (link_list *ll)
{
	#ifdef FUNCTIONS
	puts ("**link_burn");
	#endif

	if (ll != NULL)
	{
		link_elements_burn (ll->head);
		free (ll);
	}
}

int room_num (room_list *rl, room *r)
{
	room *scan;
	int num = 1;

	if ((rl == NULL) || (rl->head == NULL))
		return 0;

	for (scan = rl->head;
		(scan != NULL) && (scan != r);
		scan = scan->next, num++);

	if (scan == NULL)
		return 0;

	return num;
}

int link_count (link_list *ll)
{
	link *scan;
	int n = 0;

	for (scan = ll->head; scan != NULL; scan = scan->next, n++);

	return n;
}