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

#include <math.h>
#include <limits>

#include "Angle.h"

#define FLOAT_INFINITY std::numeric_limits<float>::infinity()

TEST(Angle8, Construct) {
  float angle = 0.0F;
  Angle8 a = Angle8::Degrees(angle);
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);

  angle = -180.0F;
  a = Angle8::Degrees(angle);
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);

  angle = 270.0F;
  a = Angle8::Degrees(angle);
  EXPECT_FLOAT_EQ(a.InDegrees(), -90);
}

TEST(Angle8, Negate) {
  float angle = 0;
  Angle8 a = Angle8::Degrees(angle);
  a = -a;
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);

  angle = 90.0F;
  a = Angle8::Degrees(angle);
  a = -a;
  EXPECT_FLOAT_EQ(a.InDegrees(), -angle);
}

TEST(Angle8, Add) {
  Angle8 a = Angle8::Degrees(-45);
  Angle8 b = Angle8::Degrees(45.0F);
  Angle8 r = a + b;
  EXPECT_FLOAT_EQ(r.InDegrees(), 0);
}

TEST(Angle8, Subtract) {
  Angle8 a = Angle8::Degrees(0);
  Angle8 b = Angle8::Degrees(45.0F);
  Angle8 r = a - b;
  EXPECT_FLOAT_EQ(r.InDegrees(), -45);
}

TEST(Angle8, Compare) {
  Angle8 a = Angle8::Degrees(45);
  bool r = false;

  r = a > Angle8::Degrees(0);
  EXPECT_TRUE(r) << "45 > 0";

  r = a > Angle8::Degrees(90);
  EXPECT_FALSE(r) << "45 > 90";

  r = a > Angle8::Degrees(-90);
  EXPECT_TRUE(r) << "45 > -90";
}

TEST(Angle8, Normalize) {
  Angle8 r = Angle8();

  r = Angle8::Normalize(Angle8::Degrees(90.0f));
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90";

  r = Angle8::Normalize(Angle8::Degrees(-90));
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90";

  r = Angle8::Normalize(Angle8::Degrees(270));
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270";

  r = Angle8::Normalize(Angle8::Degrees(270 + 360));
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360";

  r = Angle8::Normalize(Angle8::Degrees(-270));
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270";

  r = Angle8::Normalize(Angle8::Degrees(-270 - 360));
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360";

  r = Angle8::Normalize(Angle8::Degrees(0));
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0";

  if (false) {  // std::numeric_limits<float>::is_iec559) {
    // Infinites are not supported
    r = Angle8::Normalize(Angle8::Degrees(FLOAT_INFINITY));
    EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY";

    r = Angle8::Normalize(Angle8::Degrees(-FLOAT_INFINITY));
    EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY";
  }
}

TEST(Angle8, Clamp) {
  Angle8 r = Angle8();

  // Clamp(1, 0, 2) will fail because Angle8 does not have enough resolution for
  // this. Instead we use Clamp(10, 0, 20) etc.
  r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0),
                    Angle8::Degrees(20));
  EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 10 0 20";

  r = Angle8::Clamp(Angle8::Degrees(-10), Angle8::Degrees(0),
                    Angle8::Degrees(20));
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -10 0 20";

  r = Angle8::Clamp(Angle8::Degrees(30), Angle8::Degrees(0),
                    Angle8::Degrees(20));
  EXPECT_NEAR(r.InDegrees(), 20, 1.0e-0) << "Clamp 30 0 20";

  r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0),
                    Angle8::Degrees(0));
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 10 0 0";

  r = Angle8::Clamp(Angle8::Degrees(0), Angle8::Degrees(0), Angle8::Degrees(0));
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0";

  r = Angle8::Clamp(Angle8::Degrees(0), Angle8::Degrees(10),
                    Angle8::Degrees(-10));
  EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 0 10 -10";

  if (false) {  // std::numeric_limits<float>::is_iec559) {
    // Infinites are not supported
    r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0),
                      Angle8::Degrees(FLOAT_INFINITY));
    EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 0 INFINITY";

    r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(-FLOAT_INFINITY),
                      Angle8::Degrees(10));
    EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 -INFINITY 1";
  }
}

// TEST(Angle8, Difference) {
//   Angle8 r = 0;

//   r = Angle8::Difference(0, 90);
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90";

//   r = Angle8::Difference(0, -90);
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90";

//   r = Angle8::Difference(0, 270);
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270";

//   r = Angle8::Difference(0, -270);
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270";

//   r = Angle8::Difference(90, 0);
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0";

//   r = Angle8::Difference(-90, 0);
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0";

//   r = Angle8::Difference(0, 0);
//   EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0";

//   r = Angle8::Difference(90, 90);
//   EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90";

//   if (std::numeric_limits<float>::is_iec559) {
//     r = Angle8::Difference(0, INFINITY);
//     EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY";

//     r = Angle8::Difference(0, -INFINITY);
//     EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY";

//     r = Angle8::Difference(-INFINITY, INFINITY);
//     EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY
//     INFINITY";
//   }
// }

TEST(Angle8, MoveTowards) {
  Angle8 r = Angle8();

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 30);
  EXPECT_NEAR(r.InDegrees(), 30, 1.0e-0) << "MoveTowards 0 90 30";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 90);
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), 180);
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 -90 -180";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 270);
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), -30);
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -30);
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -90);
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -180);
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -270);
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 0);
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(0), 0);
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0";

  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(0), 30);
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30";

  if (false) {  // std::numeric_limits<float>::is_iec559) {
    // infinites are not supported
    r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90),
                            FLOAT_INFINITY);
    EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY";

    r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(FLOAT_INFINITY),
                            30);
    EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30";

    r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90),
                            -FLOAT_INFINITY);
    EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY)
        << "MoveTowards 0 -90 -FLOAT_INFINITY";

    r = Angle8::MoveTowards(Angle8::Degrees(0),
                            Angle8::Degrees(-FLOAT_INFINITY), -30);
    EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 -FLOAT_INFINITY -30";
  }
}

#endif