#include "test_common.h"
#include <string.h>

/******************************************************************************
 * atf_x_equals
 *****************************************************************************/

bool atf_val_equals(atf_test_result * __result__, as_val * actual, as_val * expected)
{
	if ( actual == expected ) {
		return true;
	}

	bassert_int_eq(as_val_type(actual), as_val_type(expected));
	switch(as_val_type(actual)) {
		case AS_INTEGER:
			bassert(atf_integer_equals(__result__, as_integer_fromval(actual), as_integer_fromval(expected)));
			break;
		case AS_DOUBLE:
			bassert(atf_double_equals(__result__, as_double_fromval(actual), as_double_fromval(expected)));
			break;
		case AS_STRING:
			bassert(atf_string_equals(__result__, as_string_fromval(actual), as_string_fromval(expected)));
			break;
		case AS_LIST:
			bassert(atf_list_equals(__result__, as_list_fromval(actual), as_list_fromval(expected)));
			break;
		case AS_MAP:
			bassert(atf_map_equals(__result__, as_map_fromval(actual), as_map_fromval(expected)));
			break;
		default:
			error("Unhandled val type");
	}
	return true;
}

bool atf_integer_equals(atf_test_result * __result__, as_integer * actual, as_integer * expected)
{
	bassert_int_eq( as_integer_get(actual), as_integer_get(expected) );
	return true;
}

bool atf_double_equals(atf_test_result * __result__, as_double * actual, as_double * expected)
{
	bassert_double_eq( as_double_get(actual), as_double_get(expected) );
	return true;
}

bool atf_string_equals(atf_test_result * __result__, as_string * actual, as_string * expected)
{
	bassert_string_eq( as_string_get(actual), as_string_get(expected) );
	return true;
}

bool atf_list_equals(atf_test_result * __result__, as_list * actual, as_list * expected)
{
	bassert_int_eq( as_list_size(actual), as_list_size(expected) );
	uint32_t n = as_list_size(actual);
	for (uint32_t i = 0; i < n; i++) {
		as_val * v1 = as_list_get(actual, i);
		as_val * v2 = as_list_get(expected, i);
		bassert(atf_val_equals(__result__, v1, v2));
	}
	return true;
}

typedef struct {
	as_map * actual;
	atf_test_result * result;
} atf_map_equals_foreach_data;

static bool atf_map_equals_foreach(const as_val * key, const as_val * expected, void * udata)
{
	atf_map_equals_foreach_data * data = (atf_map_equals_foreach_data *) udata;
	as_val * actual = as_map_get(data->actual, (as_val *) key);
	return atf_val_equals(data->result, (as_val *) actual, (as_val *) expected);
}

bool atf_map_equals(atf_test_result * __result__, as_map * actual, as_map * expected)
{
	atf_map_equals_foreach_data data = {
		.actual = actual,
		.result = __result__
	};
	bassert_int_eq( as_map_size(actual), as_map_size(expected) );
	bassert(as_map_foreach(expected, atf_map_equals_foreach, &data));
	return true;
}
