/*
 * test automatically generated "idtree" data types
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "datatypes.h"


void inteqtest( int value, int expected, char *mesg )
{
	if( value == expected )
	{
		printf( "%s==%d: ok\n", mesg, expected );
	} else
	{
		printf( "%s==%d, actual: %d: fail\n", mesg, expected, value );
	}
}


void streqtest( char *value, char *expected, char *mesg )
{
	if( strcmp(value,expected) == 0 )
	{
		printf( "%s==%s: ok\n", mesg, expected );
	} else
	{
		printf( "%s==%s, actual: %s: fail\n", mesg, expected, value );
	}
}


void testleaf( idtree t, char *expected, char *treename )
{
	char label[1024];
	sprintf( label, "isnode(%s)", treename );
	inteqtest( idtree_kind(t), idtree_is_leaf, label );
	string id;
	get_idtree_leaf( t, &id );
	sprintf( label, "getleaf(%s)", treename );
	streqtest( id, expected, label );
}


/* recursive idtree leaf counter
 * In Haskell, this'd be:
 *   nleaves(leaf(x))   = 1
 *   nleaves(node(l,r)) = nleaves(l) + nleaves(r)
 */
int nleaves( idtree t )
{
	/* have we found a leaf?  answer 1 if so */
	if( idtree_kind(t) == idtree_is_leaf )
	{
		return 1;
	}

	/* found node: break it apart into left and right trees */
	idtree l, r;
	get_idtree_node( t, &l, &r );

	/* sum their numbers of leaves */
	return nleaves(l) + nleaves(r);
}


/*
 * append value onto the end of malloced chunk *result, maxlen max,
 * current length *len, updating the length.  the value must fit in!
 */
void append_mustfit( char *result, int max, int *len, char *value )
{
	int vlen = strlen(value)+1;
	assert( vlen + *len < max );
	strcat( result, value );
	*len += vlen;
}


/* recursive leaf concatenator,
 * storage allocation makes this damn tricky
 */
void ccleaves_recrsv( idtree t, char *sep, char *result, int max, int *len )
{
	if( idtree_kind(t) == idtree_is_leaf )
	{
		string id;
		get_idtree_leaf( t, &id );
		append_mustfit( result, max, len, id );
		append_mustfit( result, max, len, sep );
	} else
	{
		idtree l, r;
		get_idtree_node( t, &l, &r );
		ccleaves_recrsv( l, sep, result, max, len );
		ccleaves_recrsv( r, sep, result, max, len );
	}
}


/*
 * idtree leaf concatenator, with a separator (sep) between the leaves
 * returns a malloc()ed string, caller is responsible for freeing it.
 */
string concatleaves( idtree t, char *sep )
{
	int max = 1024;
	char *result = (char *) malloc( max * sizeof(char) );
	int currlen = 0;
	*result = '\0';
	ccleaves_recrsv( t, sep, result, max, &currlen );
	return result;
}


int main( void )
{
	idtree t1 = idtree_leaf( "absolutely" );
	testleaf( t1, "absolutely", "ab" );

	idtree t2 = idtree_leaf( "fabulous" );
	testleaf( t2, "fabulous", "fab" );

	idtree t = idtree_node( t1, t2 );

	inteqtest( idtree_kind(t), idtree_is_node, "isnode((ab,fab))" );

	idtree l, r;
	get_idtree_node( t, &l, &r );

	testleaf( l, "absolutely", "left((ab,fab))" );
	testleaf( r, "fabulous", "right((ab,fab))" );

	inteqtest( nleaves(t), 2, "nleaves((ab,fab))" );

	t = idtree_node( t, t2 );
	inteqtest( idtree_kind(t), idtree_is_node,
		"isnode(((ab,fab),fab))" );
	inteqtest( nleaves(t), 3, "nleaves(((ab,fab),fab))" );

	string s = concatleaves( t, "," );
	streqtest( s, "absolutely,fabulous,fabulous,",
		"concatleaves(((ab,fab),fab),',')" );
	free(s);

	exit(0);
	return(0);
}
