#include <string.h>
#include <kalmia.h>
#include "test/test.h"
#include "transform.h"

void create_identity();
void multiply();

void parse_matrix_fail_nonmatrix();
void parse_identity();

void parse_rotate_fail();
void parse_rotate();

void parse_scale_fail();
void parse_scale();

void parse_translate_fail();
void parse_translate();


void suite_transform()
{
	lily_run_test(create_identity);
	lily_run_test(multiply);
	lily_run_test(parse_matrix_fail_nonmatrix);
	lily_run_test(parse_identity);
	lily_run_test(parse_rotate_fail);
	lily_run_test(parse_rotate);
	lily_run_test(parse_scale_fail);
	lily_run_test(parse_scale);
	lily_run_test(parse_translate_fail);
	lily_run_test(parse_translate);
}


/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

/* ======== basic ======== */

void create_identity()
{
	ka_matrix_t mat;
	mat[0] = 100;
	int rc = kai_identity(&mat);
	lily_assert_true(rc == 0);

	lily_assert_float_equal(mat[0], 1.0f, 1e-3);
	lily_assert_float_equal(mat[1], 0.0f, 1e-3);
	lily_assert_float_equal(mat[2], 0.0f, 1e-3);
	lily_assert_float_equal(mat[3], 0.0f, 1e-3);
	lily_assert_float_equal(mat[4], 0.0f, 1e-3);
	lily_assert_float_equal(mat[5], 1.0f, 1e-3);
	lily_assert_float_equal(mat[6], 0.0f, 1e-3);
	lily_assert_float_equal(mat[7], 0.0f, 1e-3);
	lily_assert_float_equal(mat[8], 0.0f, 1e-3);
	lily_assert_float_equal(mat[9], 0.0f, 1e-3);
	lily_assert_float_equal(mat[10], 1.0f, 1e-3);
	lily_assert_float_equal(mat[11], 0.0f, 1e-3);
	lily_assert_float_equal(mat[12], 0.0f, 1e-3);
	lily_assert_float_equal(mat[13], 0.0f, 1e-3);
	lily_assert_float_equal(mat[14], 0.0f, 1e-3);
	lily_assert_float_equal(mat[15], 1.0f, 1e-3);
}


void multiply()
{
	ka_matrix_t A = {
		2.0f,  0.0f,  1.0f,  0.0f,
		0.0f,  3.0f,  0.0f,  0.0f,
		0.0f,  0.0f,  1.0f,  0.0f,
		0.0f,  0.0f,  0.0f,  1.0f,
	};

	ka_matrix_t B = {
		0.0f,  3.0f,  0.0f,  0.0f,
		1.0f,  0.0f,  1.0f,  0.0f,
		0.0f,  2.0f,  2.0f,  0.0f,
		0.0f,  0.0f,  0.0f,  1.0f,
	};

	int rc = kai_multiply(&A, A, B);
	lily_assert_true(rc == 0);

	lily_assert_float_equal(A[0],  0.0f, 1e-3);
	lily_assert_float_equal(A[1],  8.0f, 1e-3);
	lily_assert_float_equal(A[2],  2.0f, 1e-3);
	lily_assert_float_equal(A[3],  0.0f, 1e-3);

	lily_assert_float_equal(A[4],  3.0f, 1e-3);
	lily_assert_float_equal(A[5],  0.0f, 1e-3);
	lily_assert_float_equal(A[6],  3.0f, 1e-3);
	lily_assert_float_equal(A[7],  0.0f, 1e-3);

	lily_assert_float_equal(A[8],  0.0f, 1e-3);
	lily_assert_float_equal(A[9],  2.0f, 1e-3);
	lily_assert_float_equal(A[10], 2.0f, 1e-3);
	lily_assert_float_equal(A[11], 0.0f, 1e-3);

	lily_assert_float_equal(A[12], 0.0f, 1e-3);
	lily_assert_float_equal(A[13], 0.0f, 1e-3);
	lily_assert_float_equal(A[14], 0.0f, 1e-3);
	lily_assert_float_equal(A[15], 1.0f, 1e-3);
}


/* ======== matrix ======== */
void parse_matrix_fail_nonmatrix()
{
	char str[128];
	strncpy(str, "<nonmatrix></nonmatrix>", 128);
	ezxml_t tag = ezxml_parse_str(str, strlen(str));

	ka_matrix_t mat;
	int rc = kai_parse_matrix(&mat, tag);
	lily_assert_true(rc != 0);

	ezxml_free(tag);
}


void parse_identity()
{
	char str[512];
	strncpy(
		str, 
		"<matrix>\n"
		"	1 0 0 0\n"
		"	0 1 0 0\n"
		"	0 0 1 0\n"
		"	0 0 0 1\n"
		"</matrix>",
		512
	);
	ezxml_t tag = ezxml_parse_str(str, strlen(str));

	ka_matrix_t mat;
	mat[0] = 100;
	int rc = kai_parse_matrix(&mat, tag);
	lily_assert_true(rc == 0);
	ezxml_free(tag);

	lily_assert_float_equal(mat[0], 1.0f, 1e-3);
	lily_assert_float_equal(mat[1], 0.0f, 1e-3);
	lily_assert_float_equal(mat[2], 0.0f, 1e-3);
	lily_assert_float_equal(mat[3], 0.0f, 1e-3);
	lily_assert_float_equal(mat[4], 0.0f, 1e-3);
	lily_assert_float_equal(mat[5], 1.0f, 1e-3);
	lily_assert_float_equal(mat[6], 0.0f, 1e-3);
	lily_assert_float_equal(mat[7], 0.0f, 1e-3);
	lily_assert_float_equal(mat[8], 0.0f, 1e-3);
	lily_assert_float_equal(mat[9], 0.0f, 1e-3);
	lily_assert_float_equal(mat[10], 1.0f, 1e-3);
	lily_assert_float_equal(mat[11], 0.0f, 1e-3);
	lily_assert_float_equal(mat[12], 0.0f, 1e-3);
	lily_assert_float_equal(mat[13], 0.0f, 1e-3);
	lily_assert_float_equal(mat[14], 0.0f, 1e-3);
	lily_assert_float_equal(mat[15], 1.0f, 1e-3);
}


/* ======== rotate ======== */
void parse_rotate_fail()
{
	char str[128];
	strncpy(str, "<non></non>", 128);
	ezxml_t tag = ezxml_parse_str(str, strlen(str));

	ka_matrix_t mat;
	int rc = kai_parse_rotate(&mat, tag);
	lily_assert_true(rc != 0);

	ezxml_free(tag);
}


void parse_rotate()
{
	char str[512];
	strncpy(
		str, 
		"<rotate>\n"
		"	0 1 0 90.0\n"
		"</rotate>",
		512
	);
	ezxml_t tag = ezxml_parse_str(str, strlen(str));

	ka_matrix_t mat;
	mat[0] = 100;
	int rc = kai_parse_rotate(&mat, tag);
	lily_assert_true(rc == 0);
	ezxml_free(tag);

	lily_assert_float_equal(mat[0],  0.0f, 1e-3);
	lily_assert_float_equal(mat[1],  0.0f, 1e-3);
	lily_assert_float_equal(mat[2],  1.0f, 1e-3);
	lily_assert_float_equal(mat[3],  0.0f, 1e-3);
	lily_assert_float_equal(mat[4],  0.0f, 1e-3);
	lily_assert_float_equal(mat[5],  1.0f, 1e-3);
	lily_assert_float_equal(mat[6],  0.0f, 1e-3);
	lily_assert_float_equal(mat[7],  0.0f, 1e-3);
	lily_assert_float_equal(mat[8], -1.0f, 1e-3);
	lily_assert_float_equal(mat[9],  0.0f, 1e-3);
	lily_assert_float_equal(mat[10], 0.0f, 1e-3);
	lily_assert_float_equal(mat[11], 0.0f, 1e-3);
	lily_assert_float_equal(mat[12], 0.0f, 1e-3);
	lily_assert_float_equal(mat[13], 0.0f, 1e-3);
	lily_assert_float_equal(mat[14], 0.0f, 1e-3);
	lily_assert_float_equal(mat[15], 1.0f, 1e-3);
}


/* ======== scale ======== */
void parse_scale_fail()
{
	char str[128];
	strncpy(str, "<non></non>", 128);
	ezxml_t tag = ezxml_parse_str(str, strlen(str));

	ka_matrix_t mat;
	int rc = kai_parse_scale(&mat, tag);
	lily_assert_true(rc != 0);

	ezxml_free(tag);
}


void parse_scale()
{
	char str[512];
	strncpy(
		str, 
		"<scale>\n"
		"	10 5 -1\n"
		"</scale>",
		512
	);
	ezxml_t tag = ezxml_parse_str(str, strlen(str));

	ka_matrix_t mat;
	mat[0] = 100;
	int rc = kai_parse_scale(&mat, tag);
	lily_assert_true(rc == 0);
	ezxml_free(tag);

	lily_assert_float_equal(mat[0], 10.0f, 1e-3);
	lily_assert_float_equal(mat[1],  0.0f, 1e-3);
	lily_assert_float_equal(mat[2],  0.0f, 1e-3);
	lily_assert_float_equal(mat[3],  0.0f, 1e-3);
	lily_assert_float_equal(mat[4],  0.0f, 1e-3);
	lily_assert_float_equal(mat[5],  5.0f, 1e-3);
	lily_assert_float_equal(mat[6],  0.0f, 1e-3);
	lily_assert_float_equal(mat[7],  0.0f, 1e-3);
	lily_assert_float_equal(mat[8],  0.0f, 1e-3);
	lily_assert_float_equal(mat[9],  0.0f, 1e-3);
	lily_assert_float_equal(mat[10],-1.0f, 1e-3);
	lily_assert_float_equal(mat[11], 0.0f, 1e-3);
	lily_assert_float_equal(mat[12], 0.0f, 1e-3);
	lily_assert_float_equal(mat[13], 0.0f, 1e-3);
	lily_assert_float_equal(mat[14], 0.0f, 1e-3);
	lily_assert_float_equal(mat[15], 1.0f, 1e-3);
}


/* ======== translate ======== */
void parse_translate_fail()
{
	char str[128];
	strncpy(str, "<non></non>", 128);
	ezxml_t tag = ezxml_parse_str(str, strlen(str));

	ka_matrix_t mat;
	int rc = kai_parse_translate(&mat, tag);
	lily_assert_true(rc != 0);

	ezxml_free(tag);
}


void parse_translate()
{
	char str[512];
	strncpy(
		str, 
		"<translate>\n"
		"	10 5 -1\n"
		"</translate>",
		512
	);
	ezxml_t tag = ezxml_parse_str(str, strlen(str));

	ka_matrix_t mat;
	mat[0] = 100;
	int rc = kai_parse_translate(&mat, tag);
	lily_assert_true(rc == 0);
	ezxml_free(tag);

	lily_assert_float_equal(mat[0],  1.0f, 1e-3);
	lily_assert_float_equal(mat[1],  0.0f, 1e-3);
	lily_assert_float_equal(mat[2],  0.0f, 1e-3);
	lily_assert_float_equal(mat[3], 10.0f, 1e-3);
	lily_assert_float_equal(mat[4],  0.0f, 1e-3);
	lily_assert_float_equal(mat[5],  1.0f, 1e-3);
	lily_assert_float_equal(mat[6],  0.0f, 1e-3);
	lily_assert_float_equal(mat[7],  5.0f, 1e-3);
	lily_assert_float_equal(mat[8],  0.0f, 1e-3);
	lily_assert_float_equal(mat[9],  0.0f, 1e-3);
	lily_assert_float_equal(mat[10], 1.0f, 1e-3);
	lily_assert_float_equal(mat[11],-1.0f, 1e-3);
	lily_assert_float_equal(mat[12], 0.0f, 1e-3);
	lily_assert_float_equal(mat[13], 0.0f, 1e-3);
	lily_assert_float_equal(mat[14], 0.0f, 1e-3);
	lily_assert_float_equal(mat[15], 1.0f, 1e-3);
}