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

#include "../../src/util/memory.h"
#include "../../src/util/varray.h"

static int err;

/**
 * Create array with up to 3 strings: "a", "b" and "c".
 * @param n Actual number of strings to put in the array, [0,3].
 * @param a Here returns handle first string.
 * @param b Here returns handle second string.
 * @param c Here returns handle third string.
 * @return Created array.
 */
static varray_Type *createABC(int n, int *a, int*b, int *c)
{
	varray_Type *va = varray_new();
	*a = (n < 1)? 0 : varray_addValue(va, "a");
	*b = (n < 2)? 0 : varray_addValue(va, "b");
	*c = (n < 3)? 0 : varray_addValue(va, "c");
	return va;
}


/**
 * Returns a (statically allocated) string with the content of the array,
 * assuming each entry contains a pointer to a single char. Also checks the
 * number of entries equals the length of the array.
 * @param va
 * @return 
 */
static char * vaToString(varray_Type *va)
{
	static char res[99];
	char *s;
	int gotlen = 0;
	int i;
	s = res;
	for(i = varray_firstHandle(va); i != 0; i = varray_nextHandle(va)){
		*s = *((char *) varray_getValue(va, i));
		s++;
		gotlen++;
	}
	*s = 0;
	assert( gotlen == varray_length(va) );
	return res;
}


/**
 * Test if the array content equals the given string.
 * @param line
 * @param va
 * @param exp
 */
static void vaEqualsString(int line, varray_Type *va, char *exp)
{
	char *got = vaToString(va);
	if( strcmp(got, exp) != 0 ){
		err++;
		printf("in line %d\n\tgot %s\n\texp %s\n", line, got, exp);
	}
}


static void vaDispose(varray_Type *va)
{
	int i;
	for(i = varray_firstHandle(va); i != 0; i = varray_nextHandle(va))
		varray_detach(va, i);
	memory_dispose(va);
}


int main(int argc, char** argv)
{
	varray_Type *va;
	int a, b, c, a2;
	
	/* Empty array tests. */
	
	va = createABC(0, &a, &b, &c);
	vaEqualsString(__LINE__, va, "");
	assert( varray_length(va) == 0 );
	assert( ! varray_isValidHandle(va, 0) );
	assert( ! varray_isValidHandle(va, -1) );
	assert( ! varray_isValidHandle(va, 1) );
	vaDispose(va);
	
	
	/* 1 entry tests. */
	
	va = createABC(1, &a, &b, &c);
	vaEqualsString(__LINE__, va, "a");
	assert( ! varray_isValidHandle(va, 0) );
	
	/* remove that only entry: */
	varray_detach(va, a);
	assert( varray_length(va) == 0 );
	
	/* recycle last detached, resulting in a new handle: */
	a2 = varray_getDetachedHandle(va);
	assert( a2 != a );
	varray_setValue(va, a2, "z");
	vaEqualsString(__LINE__, va, "z");
	
	vaDispose(va);
	
	
	/* Array with 3 entries "abc". */
	va = createABC(3, &a, &b, &c);
	vaEqualsString(__LINE__, va, "abc");
	
	// Detach first entry:
	varray_detach(va, a);
	vaEqualsString(__LINE__, va, "bc");
	
	// Add entry replacing detached one; new entry added last:
	varray_setValue(va, varray_getDetachedHandle(va), "d");
	vaEqualsString(__LINE__, va, "bcd");
	
	// Add new entry; new entry added last:
	varray_addValue(va, "e");
	vaEqualsString(__LINE__, va, "bcde");
	
	vaDispose(va);
	
	/* Array with 3 entries "abc". */
	va = createABC(3, &a, &b, &c);
	vaEqualsString(__LINE__, va, "abc");
	
	// Detach middle entry:
	varray_detach(va, b);
	vaEqualsString(__LINE__, va, "ac");
	
	// Add entry replacing detached one; new entry added last:
	varray_setValue(va, varray_getDetachedHandle(va), "d");
	vaEqualsString(__LINE__, va, "acd");
	
	// Add new entry; new entry added last:
	varray_addValue(va, "e");
	vaEqualsString(__LINE__, va, "acde");
	
	vaDispose(va);
	
	/* Array with 3 entries "abc". */
	va = createABC(3, &a, &b, &c);
	vaEqualsString(__LINE__, va, "abc");
	
	// Detach last entry:
	varray_detach(va, c);
	vaEqualsString(__LINE__, va, "ab");
	
	// Add entry replacing detached one; new entry added last:
	varray_setValue(va, varray_getDetachedHandle(va), "d");
	vaEqualsString(__LINE__, va, "abd");
	
	// Add new entry; new entry added last:
	varray_addValue(va, "e");
	vaEqualsString(__LINE__, va, "abde");
	
	vaDispose(va);

	err += memory_report();
	return err == 0? 0 : 1;
}

