#include "tests/MatrixStackTests.h"
#include "tests/Test.h"
#include "math/MatrixStack.h"
#include "utils/StringBuffer.h"

typedef MatrixStack<5> Matrices;
typedef StringBuffer<500> String;

static void testInit(Test& test) {
    Matrix m;
    Matrices stack;
    for(int i = 0; i < 16; i++) {
        test.checkEqual(m.getValues()[i], stack.peek().getValues()[i], "contains identity matrix");
    }
}

static void testPop(Test& test) {
    Matrices stack;
    stack.peek().scale(2.0f);
    stack.push();
    test.checkEqual(false, stack.pop(), "pop returns false when there is something to pop");
    test.checkEqual(true, stack.pop(), "pop returns true when the lowest matrix was popped");
    Matrix m;
    for(int i = 0; i < 16; i++) {
        test.checkEqual(m.getValues()[i], stack.peek().getValues()[i], "contains identity matrix");
    }
}

static void testPush(Test& test) {
    Matrices stack;
    for(int i = 0; i < 4; i++) {
        test.checkEqual(false, stack.push(), "push returns false without overflow");
    }
    for(int i = 0; i < 1000000; i++) {
        test.checkEqual(true, stack.push(), "push returns true with overflow");
    }
    test.checkEqual(true, true, "survives overflow");
}

static void testToString1(Test& test) {
    Matrices stack;
    stack.peek().scale(2.0f);
    stack.push();
    stack.peek().scale(3.0f);
    stack.push();
    stack.peek().scale(4.0f);
    test.checkEqual(String("["
            "[[2.00, 0.00, 0.00, 0.00], "
            "[0.00, 2.00, 0.00, 0.00], "
            "[0.00, 0.00, 2.00, 0.00], "
            "[0.00, 0.00, 0.00, 1.00]], "
            "[[6.00, 0.00, 0.00, 0.00], "
            "[0.00, 6.00, 0.00, 0.00], "
            "[0.00, 0.00, 6.00, 0.00], "
            "[0.00, 0.00, 0.00, 1.00]], "
            "[[24.00, 0.00, 0.00, 0.00], "
            "[0.00, 24.00, 0.00, 0.00], "
            "[0.00, 0.00, 24.00, 0.00], "
            "[0.00, 0.00, 0.00, 1.00]]"
            "]"), String(stack), "to string 1");
}

static void testToString2(Test& test) {
    Matrices stack;
    stack.peek().scale(2.0f);
    stack.push();
    stack.peek().scale(3.0f);
    test.checkEqual(String("["
            "[[2.00, 0.00, 0.00, 0.00], "
            "[0.00, 2.00, 0.00, 0.00], "
            "[0.00, 0.00, 2.00, 0.00], "
            "[0.00, 0.00, 0.00, 1.00]], "
            "[[6.00, 0.00, 0.00, 0.00], "
            "[0.00, 6.00, 0.00, 0.00], "
            "[0.00, 0.00, 6.00, 0.00], "
            "[0.00, 0.00, 0.00, 1.00]]"
            "]"), String(stack), "to string 2");
}

static void testToString3(Test& test) {
    Matrices stack;
    test.checkEqual(String("["
            "[[1.00, 0.00, 0.00, 0.00], "
            "[0.00, 1.00, 0.00, 0.00], "
            "[0.00, 0.00, 1.00, 0.00], "
            "[0.00, 0.00, 0.00, 1.00]]"
            "]"), String(stack), "to string 3");
}

void MatrixStackTests::test() {
    Test test("MatrixStack");
    testInit(test);
    testPop(test);
    testPush(test);
    testToString1(test);
    testToString2(test);
    testToString3(test);
    test.finalize();
}