/*
 * Author:          Patrick-Christopher Mattulat
 * Company:         Lynar Studios
 * E-Mail:          webmaster@lynarstudios.com
 * Created:         2022-08-05
 * Changed:         2023-06-02
 *
 * */

#include <cmath>
#include <gtest/gtest.h>
#include <ls-math/ls-math-vector.hpp>

using ls::math::core::type::vector2_components;
using ls::math::core::type::vector_scalar;
using ls::math::vector::Vector2;
using testing::Test;

namespace
{
  class Vector2Test : public Test
  {
    public:

      Vector2Test() = default;
      ~Vector2Test() override = default;
  };

  TEST_F(Vector2Test, operator_addition)
  {
    Vector2 c = Vector2(3.0f, 4.0f) + Vector2(5.0f, 3.0f);

    ASSERT_FLOAT_EQ(8.0f, c.getX());
    ASSERT_FLOAT_EQ(7.0f, c.getY());
  }

  TEST_F(Vector2Test, operator_substraction)
  {
    Vector2 c = Vector2(3.0f, 4.0f) - Vector2(5.0f, 3.0f);

    ASSERT_FLOAT_EQ(-2.0f, c.getX());
    ASSERT_FLOAT_EQ(1.0f, c.getY());
  }

  TEST_F(Vector2Test, operator_scalar)
  {
    vector_scalar scalar = Vector2(3.0f, 4.0f) * Vector2(5.0f, 3.0f);
    ASSERT_FLOAT_EQ(27.0f, scalar);
  }

  TEST_F(Vector2Test, operator_multiplicator)
  {
    Vector2 c = Vector2(3.0f, 4.0f) * 1.5f;

    ASSERT_FLOAT_EQ(4.5f, c.getX());
    ASSERT_FLOAT_EQ(6.0f, c.getY());
  }

  TEST_F(Vector2Test, operator_divisor)
  {
    auto c = Vector2(150.0f, -25.0f);
    Vector2 n = c / 152.4f;

    // round by two decimals

    double powValue = pow(10.0f, (double) 2);
    double roundedX = round(n.getX() * powValue) / powValue;
    double roundedY = round(n.getY() * powValue) / powValue;

    // evaluate result

    ASSERT_FLOAT_EQ(0.98f, roundedX);
    ASSERT_FLOAT_EQ(-0.16f, roundedY);
  }

  TEST_F(Vector2Test, operator_equals)
  {
    ASSERT_TRUE(Vector2(3.0f, 4.0f) == Vector2(3.0f, 4.0f));
  }

  TEST_F(Vector2Test, operator_equals_not_equals)
  {
    ASSERT_FALSE(Vector2(3.0f, 8.0f) == Vector2(3.0f, 4.0f));
  }

  TEST_F(Vector2Test, operator_not_equals)
  {
    ASSERT_TRUE(Vector2(3.0f, 5.0f) != Vector2(3.0f, 4.0f));
  }

  TEST_F(Vector2Test, operator_not_equals_equals)
  {
    ASSERT_FALSE(Vector2(3.0f, 4.0f) != Vector2(3.0f, 4.0f));
  }

  TEST_F(Vector2Test, add)
  {
    Vector2 c = Vector2::add(Vector2(3.0f, 4.0f), Vector2(5.0f, 3.0f));

    ASSERT_FLOAT_EQ(8.0f, c.getX());
    ASSERT_FLOAT_EQ(7.0f, c.getY());
  }

  TEST_F(Vector2Test, dot)
  {
    vector_scalar scalar = Vector2::dot(Vector2(3.0f, 4.0f), Vector2(5.0f, 3.0f));
    ASSERT_FLOAT_EQ(27.0f, scalar);
  }

  TEST_F(Vector2Test, getComponents)
  {
    Vector2 a{6.0f, 8.0f};
    vector2_components components = a.getComponents();

    ASSERT_FLOAT_EQ(6.0f, components[0]);
    ASSERT_FLOAT_EQ(8.0f, components[1]);
  }

  TEST_F(Vector2Test, getLength)
  {
    Vector2 a{6.0f, 8.0f};
    ASSERT_FLOAT_EQ(10.0f, a.getLength());
  }

  TEST_F(Vector2Test, getX)
  {
    Vector2 a{3.0f, 4.0f};
    ASSERT_FLOAT_EQ(3.0f, a.getX());
  }

  TEST_F(Vector2Test, getY)
  {
    Vector2 a{3.0f, 4.0f};
    ASSERT_FLOAT_EQ(4.0f, a.getY());
  }

  TEST_F(Vector2Test, normalize)
  {
    Vector2 a{150.0f, -25.0f};
    Vector2 n = a.normalize();

    // round by two decimals

    double roundedX = round(n.getX() * 1000.0f) / 1000.0f;
    double roundedY = round(n.getY() * 1000.0f) / 1000.0f;

    // evaluate results

    ASSERT_FLOAT_EQ(0.986f, roundedX);
    ASSERT_FLOAT_EQ(-0.164f, roundedY);
    ASSERT_FLOAT_EQ(1.0f, n.getLength());
  }

  TEST_F(Vector2Test, setX)
  {
    Vector2 a{3.0f, 4.0f};
    a.setX(14.0f);

    ASSERT_FLOAT_EQ(14.0f, a.getX());
  }

  TEST_F(Vector2Test, setY)
  {
    Vector2 a{3.0f, 4.0f};
    a.setY(8.0f);

    ASSERT_FLOAT_EQ(8.0f, a.getY());
  }

  TEST_F(Vector2Test, subtract)
  {
    Vector2 c = Vector2::subtract(Vector2(3.0f, 4.0f), Vector2(5.0f, 3.0f));

    ASSERT_FLOAT_EQ(-2.0f, c.getX());
    ASSERT_FLOAT_EQ(1.0f, c.getY());
  }
}
