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

#include "Spherical16.h"

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

TEST(Spherical16, FromVector3) {
  Vector3 v = Vector3(0, 0, 1);
  Spherical16 s = Spherical16(v);

  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 0 1";
  EXPECT_FLOAT_EQ((float)s.horizontalAngle.ToFloat(), 0.0F) << "s.hor 0 0 1";
  EXPECT_FLOAT_EQ((float)s.verticalAngle.ToFloat(), 0.0F) << "s.vert 0 0 1";

  v = Vector3(0, 1, 0);
  s = Spherical16(v);

  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 1 0";
  EXPECT_FLOAT_EQ(s.horizontalAngle.ToFloat(), 0.0F) << "s.hor 0 1 0";
  EXPECT_FLOAT_EQ(s.verticalAngle.ToFloat(), 90.0F) << "s.vert 0 1 0";

  v = Vector3(1, 0, 0);
  s = Spherical16(v);

  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 1 0 0";
  EXPECT_FLOAT_EQ(s.horizontalAngle.ToFloat(), 90.0F) << "s.hor 1 0 0";
  EXPECT_FLOAT_EQ(s.verticalAngle.ToFloat(), 0.0F) << "s.vert 1 0 0";
}

TEST(Spherical16, FromPolar) {
  Polar p = Polar(1, 0);
  Spherical16 s = Spherical16(p);

  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 0)";
  EXPECT_FLOAT_EQ(s.horizontalAngle.ToFloat(), 0.0F) << "s.hor Polar(1 0)";
  EXPECT_FLOAT_EQ(s.verticalAngle.ToFloat(), 0.0F) << "s.vert Polar(1 0)";

  p = Polar(1, 45);
  s = Spherical16(p);

  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 45)";
  EXPECT_FLOAT_EQ(s.horizontalAngle.ToFloat(), 45.0F) << "s.hor Polar(1 45)";
  EXPECT_FLOAT_EQ(s.verticalAngle.ToFloat(), 0.0F) << "s.vert Polar(1 45)";

  p = Polar(1, -45);
  s = Spherical16(p);

  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 -45)";
  EXPECT_FLOAT_EQ(s.horizontalAngle.ToFloat(), -45.0F) << "s.hor Polar(1 -45)";
  EXPECT_FLOAT_EQ(s.verticalAngle.ToFloat(), 0.0F) << "s.vert Polar(1 -45)";

  p = Polar(0, 0);
  s = Spherical16(p);

  EXPECT_FLOAT_EQ(s.distance, 0.0F) << "s.distance Polar(0 0)";
  EXPECT_FLOAT_EQ(s.horizontalAngle.ToFloat(), 0.0F) << "s.hor Polar(0 0)";
  EXPECT_FLOAT_EQ(s.verticalAngle.ToFloat(), 0.0F) << "s.vert Polar(0 0)";

  p = Polar(-1, 0);
  s = Spherical16(p);

  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(-1 0)";
  EXPECT_FLOAT_EQ(s.horizontalAngle.ToFloat(), -180.0F) << "s.hor Polar(-1 0)";
  EXPECT_FLOAT_EQ(s.verticalAngle.ToFloat(), 0.0F) << "s.vert Polar(-1 0)";
}

TEST(Spherical16, Incident1) {
  Vector3 v = Vector3(2.242557f, 1.027884f, -0.322347f);
  Spherical16 s = Spherical16(v);

  Spherical16 sr = Spherical16(2.49F, 98.18f, 24.4F);
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-01);
  EXPECT_NEAR(s.horizontalAngle.ToFloat(), sr.horizontalAngle.ToFloat(),
              1.0e-02);
  EXPECT_NEAR(s.verticalAngle.ToFloat(), sr.verticalAngle.ToFloat(), 1.0e-02);

  Vector3 r = Vector3(Spherical(sr.distance, sr.horizontalAngle.ToFloat(),
                                sr.verticalAngle.ToFloat()));
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-02) << "toVector3.x 1 0 0";
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-02) << "toVector3.y 1 0 0";
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-02) << "toVector3.z 1 0 0";
}

TEST(Spherical16, Incident2) {
  Vector3 v = Vector3(1.0f, 0.0f, 1.0f);
  Spherical16 s = Spherical16(v);

  Spherical16 sr = Spherical16(1.4142135623F, 45.0f, 0.0F);
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
  EXPECT_NEAR(s.horizontalAngle.ToFloat(), sr.horizontalAngle.ToFloat(),
              1.0e-05);
  EXPECT_NEAR(s.verticalAngle.ToFloat(), sr.verticalAngle.ToFloat(), 1.0e-05);

  Vector3 r = Vector3(Spherical(sr.distance, sr.horizontalAngle.ToFloat(),
                                sr.verticalAngle.ToFloat()));
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);

  v = Vector3(0.0f, 1.0f, 1.0f);
  s = Spherical16(v);

  sr = Spherical16(1.4142135623F, 0.0f, 45.0F);
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
  EXPECT_NEAR(s.horizontalAngle.ToFloat(), sr.horizontalAngle.ToFloat(),
              1.0e-05);
  EXPECT_NEAR(s.verticalAngle.ToFloat(), sr.verticalAngle.ToFloat(), 1.0e-05);

  r = Vector3(Spherical(sr.distance, sr.horizontalAngle.ToFloat(),
                        sr.verticalAngle.ToFloat()));
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);

  v = Vector3(1.0f, 1.0f, 1.0f);
  s = Spherical16(v);
  r = Vector3(Spherical(s.distance, s.horizontalAngle.ToFloat(),
                        s.verticalAngle.ToFloat()));

  EXPECT_NEAR(s.distance, 1.73205080F, 1.0e-02);
  EXPECT_NEAR(s.horizontalAngle.ToFloat(), 45.0F, 1.0e-02);
  EXPECT_NEAR(s.verticalAngle.ToFloat(), 35.26F, 1.0e-02);

  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-04);
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-04);
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-04);

  // s = Spherical16(10, 45, 45);
  // r = s.ToVector3();
  // EXPECT_NEAR(r.x, 5, 1.0e-06);
  // EXPECT_NEAR(r.y, 7.07, 1.0e-06);
  // EXPECT_NEAR(r.z, 5, 1.0e-06);
}

TEST(Spherical16, Addition) {
  Spherical16 v1 = Spherical16(1, 45, 0);
  Spherical16 v2 = Spherical16::zero;
  Spherical16 r = Spherical16::zero;

  r = v1 + v2;
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";

  r = v1;
  r += v2;
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";

  v2 = Spherical16(1, -45, 0);
  r = v1 + v2;
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 -45 0)";
  EXPECT_FLOAT_EQ(r.horizontalAngle.ToFloat(), 0) << "Addition(1 -45 0)";
  EXPECT_FLOAT_EQ(r.verticalAngle.ToFloat(), 0) << "Addition(1 -45 0)";

  v2 = Spherical16(1, 0, 90);
  r = v1 + v2;
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 0 90)";
  EXPECT_FLOAT_EQ(r.horizontalAngle.ToFloat(), 45) << "Addition(1 0 90)";
  EXPECT_FLOAT_EQ(r.verticalAngle.ToFloat(), 45) << "Addition(1 0 90)";
}

#endif