#if GTEST
#include <gtest/gtest.h>
#include <limits>
#include <math.h>

#include "Matrix.h"

TEST(MatrixSingle, Init) {
  // zero
  MatrixOf<float> m0 = MatrixOf<float>(0, 0);

  // one
  float data1[] = {1.0F};
  MatrixOf<float> m1 = MatrixOf<float>(1, 1, data1);

  // two
  float data2[] = {1.0F, 2.0F, 3.0F, 4.0F};
  MatrixOf<float> m2 = MatrixOf<float>(2, 2, data2);

  // negative
  // MatrixOf<float> m_1 = MatrixOf<float>(-1, -1);
  // parameters are unsigned
}

TEST(MatrixSingle, Transpose) {
  float data1[] = {1.0F};
  MatrixOf<float> m = MatrixOf<float>(1, 1, data1);

  MatrixOf<float> r = MatrixOf<float>(1, 1);
  m.Transpose(&r);

  // 2 x 2

  float data3[] = {1.0F, 2.0F, 3.0F, 4.0F};
  MatrixOf<float> m22 = MatrixOf<float>(2, 2, data3);
  EXPECT_EQ(m22.RowCount(), 2);
  EXPECT_EQ(m22.ColCount(), 2);

  float data4[] = {0.0F, 0.0F, 0.0F, 0.0F};
  MatrixOf<float> r22 = MatrixOf<float>(2, 2, data4);
  EXPECT_EQ(r22.RowCount(), 2);
  EXPECT_EQ(r22.ColCount(), 2);

  m22.Transpose(&r22);
  EXPECT_EQ(r22.RowCount(), 2);
  EXPECT_EQ(r22.ColCount(), 2);
  EXPECT_FLOAT_EQ(r22.Get(0, 0), 1.0F);
  EXPECT_FLOAT_EQ(r22.Get(0, 1), 3.0F);
  EXPECT_FLOAT_EQ(r22.Get(1, 0), 2.0F);
  EXPECT_FLOAT_EQ(r22.Get(1, 1), 4.0F);

  // 1 x 2
  float data12[] = {1.0F, 2.0F};
  MatrixOf<float> m12 = MatrixOf<float>(1, 2, data12);
  EXPECT_EQ(m12.RowCount(), 1);
  EXPECT_EQ(m12.ColCount(), 2);

  float data21[] = {0.0F, 0.0F};
  MatrixOf<float> r21 = MatrixOf<float>(2, 1, data21);
  EXPECT_EQ(r21.RowCount(), 2);
  EXPECT_EQ(r21.ColCount(), 1);

  m12.Transpose(&r21);
  EXPECT_EQ(r21.RowCount(), 2);
  EXPECT_EQ(r21.ColCount(), 1);
  EXPECT_FLOAT_EQ(r21.Get(0, 0), 1.0F);
  EXPECT_FLOAT_EQ(r21.Get(1, 0), 2.0F);

  // changing dimensions, same size is okay
  MatrixOf<float> r12 = MatrixOf<float>(1, 2, data21);
  EXPECT_EQ(r12.RowCount(), 1);
  EXPECT_EQ(r12.ColCount(), 2);

  m12.Transpose(&r12);
  EXPECT_EQ(r12.RowCount(), 2);
  EXPECT_EQ(r12.ColCount(), 1);
  EXPECT_FLOAT_EQ(r12.Get(0, 0), 1.0F);
  EXPECT_FLOAT_EQ(r12.Get(0, 1), 2.0F);
}

TEST(MatrixSingle, Multiply) {
  float m12data[] = {1.0F, 2.0F};
  MatrixOf<float> m12 = MatrixOf<float>(1, 2, m12data);

  EXPECT_EQ(m12.RowCount(), 1);
  EXPECT_EQ(m12.ColCount(), 2);
  EXPECT_FLOAT_EQ(m12.Get(0, 0), 1.0F);
  EXPECT_FLOAT_EQ(m12.Get(0, 1), 2.0F);

  float m21data[] = {3.0F, 4.0F};
  MatrixOf<float> m21 = MatrixOf<float>(2, 1, m21data);

  EXPECT_EQ(m21.RowCount(), 2);
  EXPECT_EQ(m21.ColCount(), 1);
  EXPECT_FLOAT_EQ(m21.Get(0, 0), 3.0F);
  EXPECT_FLOAT_EQ(m21.Get(1, 0), 4.0F);

  float r11data[] = {0.0F};
  MatrixOf<float> r11 = MatrixOf<float>(1, 1, r11data);

  EXPECT_EQ(r11.RowCount(), 1);
  EXPECT_EQ(r11.ColCount(), 1);

  MatrixOf<float>::Multiply(&m12, &m21, &r11);
  EXPECT_EQ(r11.RowCount(), 1);
  EXPECT_EQ(r11.ColCount(), 1);
  EXPECT_FLOAT_EQ(r11.Get(0, 0), 11.0F);

  float r22data[] = {0.0F, 0.0F, 0.0F, 0.0F};
  MatrixOf<float> r22 = MatrixOf<float>(2, 2, r22data);

  MatrixOf<float>::Multiply(&m21, &m12, &r22);
  EXPECT_EQ(r22.RowCount(), 2);
  EXPECT_EQ(r22.ColCount(), 2);
  EXPECT_FLOAT_EQ(r22.Get(0, 0), 3.0F);
  EXPECT_FLOAT_EQ(r22.Get(0, 1), 4.0F);
  EXPECT_FLOAT_EQ(r22.Get(1, 0), 6.0F);
  EXPECT_FLOAT_EQ(r22.Get(1, 1), 8.0F);
}

TEST(MatrixSingle, Multiply_Vector3) {
  Vector3 v = Vector3(1.0, 2.0, 3.0);
  Vector3 r = Vector3::zero;

  // float m13data[] = {3.0, 4.0, 5.0};
  // MatrixOf<float> m13 = MatrixOf<float>(1, 3, m13data);
  // Vector3 r = MatrixOf<float>::Multiply(&m13, v);

  float m33data[] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
  MatrixOf<float> m33 = MatrixOf<float>(3, 3, m33data);
  r = MatrixOf<float>::Multiply(&m33, v);
  EXPECT_FLOAT_EQ(Vector3::Distance(r, Vector3(1.0f, 2.0f, 3.0f)), 0);
}

#endif