/* GameID.c
 *  Musus Umbra, 1996/7
 */

#include "gameid.h"
#include "core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>


static int lowcmp( char *a, char *b )
{
	while ( tolower(*a) == tolower(*b) )
	{
		if ( !*a++ ) { return 0; }
		b++;
	}
	return ( tolower(*a) - tolower(*b) );
}


/* New in 1.01 */
gamelist insert_sorted( gamelist gl, game_node *n )
{
	game_node *srch = gl;
	game_node *prev = NULL;
	if ( !gl ) { n->next = NULL; return n; }	/* no list => new head */
	while ( srch )
	{
		if ( lowcmp( srch->s, n->s ) >= 0 ) { break; }
		prev = srch;
		srch = srch->next;
	}
	if ( prev )			/* insert after the head? */
	{
		n->next = prev->next;	/* link in after 'prev' */
		prev->next = n;
	}
	else	/* new head */
	{
		n->next = gl;	/* = old head */
		gl = n;			/* new node is now the head */
	}
	return gl;
}


game_id_node *text_to_ids( char *ids )
{
	game_id_node *id_head = NULL;
	char *id = strtok( ids, "/" );
	while ( id )
	{
		char *size, *release, *serial, *c;
		game_id_node *new_node;
		size = c = id;
		while ( *c!='.' && *c ) { c++; }
		if ( *c ) { *c++ = 0; }
		release = c;
		while ( *c!='.' && *c ) { c++; }
		if ( *c ) { *c++ = 0; }
		if ( *c )
		{
			serial = c;
		}
		else
		{
			serial = release;
			release = size;
			size = "0";
		}
		new_node = malloc(sizeof(game_id_node));
		if ( !new_node ) { fatal("err.memory1","build_id_list/1"); }
		new_node->size = atoi( size );
		new_node->release = atoi( release );
		memcpy(new_node->serial,serial,6);
		new_node->next = id_head;
		id_head = new_node;
		id = strtok( NULL, "/" );
	}
	return id_head;
}







char *ids_to_text( game_id_node *head, char *text )
{
	char *iptr = text;
	for ( iptr=text ; head ; head=head->next )
	{
		if ( head->size )
			iptr += sprintf( iptr,"%d.",head->size );
		iptr += sprintf(iptr,"%d.", head->release );
		memcpy(iptr,head->serial,6);
		iptr+=6;
		*iptr++ = '/';
	}
	*(iptr-1) = 0;
	return text;
}


gamelist add_game( gamelist gl, char *s, char *l, char *i )
{
	game_node *new_node = malloc( sizeof(game_node) );
	if ( !new_node ) { fatal("err.memory1","add_game/1"); }
	strncpy(new_node->s,s,9);
	new_node->l = malloc(strlen(l)+1);
	if ( !new_node->l ) { fatal("err.memory1","add_game/2"); }
	strcpy(new_node->l,l);
	new_node->ids = text_to_ids(i);
	return insert_sorted(gl,new_node);
}


void delete_list( gamelist gl )
{
	while ( gl )
	{
		game_node *next = gl->next;
		game_id_node *id = gl->ids;
		while ( id )
		{
			game_id_node *next = id->next;
			free( id );
			id = next;
		}
		free( gl->l );
		free( gl );
		gl = next;
	}
}

game_node *identify_game( gamelist gl, game_id_node *id )
{
	game_node *g_srch;
	game_id_node *i_srch;
	game_node *best = NULL;
	for ( g_srch=gl ; g_srch ; g_srch=g_srch->next )
	{
		for ( i_srch=g_srch->ids ; i_srch ; i_srch=i_srch->next )
		{
			if ( i_srch->release == id->release )
			{
				if ( !memcmp( i_srch->serial, id->serial, 6 ) )
				{
					if ( i_srch->size == id->size )
					{
						return g_srch;
					}
					else
					{
						if ( !best && !i_srch->size ) { best = g_srch; }
					}
				}
			}
		}
	}
	return best;
}


gamelist remove_id( gamelist gl, game_id_node *i )
{
	game_node *match = identify_game( gl, i );
	while ( match )
	{
		game_id_node *srch = match->ids;
		game_id_node *prev = NULL;
		game_node *new_start = match->next;
		while (srch)
		{
			if ( srch->size == i->size )
				if ( srch->release == i->release )
					if ( !memcmp( srch->serial, i->serial, 6 ) )
						break;
			prev=srch;
			srch=srch->next;
		}
		if ( srch )		/* ie. a match to be deleted */
		{
			if ( prev )
			{
				prev->next = srch->next;
			}
			else
			{
				match->ids = srch->next;
			}
			free(srch);
			if ( !match->ids )		/* ie. deleted the last ID for this game */
			{
				game_node *prev = gl;
				while ( prev->next != match )
					if ( (prev = prev->next) == NULL ) { break; }
				if ( prev )		/* ie. found the predecessor in the list */
				{
					prev->next = match->next;
				}
				else			/* ie. 'match' was the head of the list */
				{
					gl = match->next;
				}
				free(match->l);
				free(match);
			}
		}
		match = identify_game( new_start, i );
	}
	return gl;
}



gamelist insert_id( gamelist gl, char *s, char *l, game_id_node *i )
{
	game_id_node *new_node = malloc( sizeof( game_id_node ) );
	game_node *srch = gl;
	if ( !new_node ) { fatal("err.memory1","insert_id/1"); }
	while ( srch )
	{
		if ( !lowcmp(srch->s,s) )
			if ( !lowcmp(srch->l,l) )
				break;
		srch = srch->next;
	}
	if ( srch )		/* ie. match found */
	{
		strcpy(srch->l,l);
		strcpy(srch->s,s);
	}
	else		/* ie. no match => make a new node */
	{
		srch = malloc( sizeof(game_node) );
		if ( !srch ) { fatal("err.memory1","insert_id/2"); }
		srch->ids = NULL;
		srch->l = malloc( strlen(l) + 1 );
		if ( !srch->l ) { fatal("err.memory1","insert_id/3"); }
		strcpy(srch->s,s);		/* needed for insert_sorted() */
		strcpy(srch->l,l);
		gl = insert_sorted( gl, srch );
	}
	new_node->next = srch->ids;
	srch->ids = new_node;
	memcpy(new_node->serial,i->serial,6);
	new_node->size = i->size;
	new_node->release = i->release;
	return gl;
}






gamelist add_game_id( gamelist gl, char *s, char *l, game_id_node *i )
{
	gl = remove_id( gl, i );
	gl = insert_id( gl, s, l, i );
	return gl;
}

