#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#include "calc.hpp"
#include <vector>


TEST_CASE("norm", "[calc]")
{
  std::vector<double> const v_0{0, 0, 0};
  REQUIRE(calc::norm(v_0.cbegin(), v_0.cend()) == 0);

  std::vector<double> const v_empty{};
  REQUIRE(calc::norm(v_empty.cbegin(), v_empty.cend()) == 0);

  std::vector<double> const v{1, 1, 1, 1, 1, 1, 1, 1, 1};
  REQUIRE(calc::norm(v.cbegin(), v.cend()) == Approx(3) );
}


TEST_CASE("position_segment", "[calc]")
{
  Positions const pos{
      Position(0, 0, 0),
      Position(0.5, 2, 1),
      Position(2.0, 8, 4)
    };
  SECTION("center") {
    auto const [first, second] = calc::position_segment(pos, 0.23);
    REQUIRE(first.time == pos[0].time);
    REQUIRE(second.time == pos[1].time);
  }
  SECTION("begin") {
    auto const [first, second] = calc::position_segment(pos, 0);
    REQUIRE(first.time == pos[0].time);
    REQUIRE(second.time == pos[1].time);
  }
  SECTION("corner") {
    auto const [first, second] = calc::position_segment(pos, 0.5);
    REQUIRE(first.time == pos[0].time);
    REQUIRE(second.time == pos[1].time);
  }
  SECTION("end") {
    auto const [first, second] = calc::position_segment(pos, 2.0);
    REQUIRE(first.time == pos[1].time);
    REQUIRE(second.time == pos[2].time);
  }
}


TEST_CASE("interpolation", "[calc]")
{
  Positions const groundtruth{
      Position(0.0, 0, 0),
      Position(1.0, 1, 1),
      Position(2.0, 3, 1)
    };
  Magnetics magnetics{
      Magnetic(0.0, 0, 0, 0),
      Magnetic(0.5, 0, 0, 0),
      Magnetic(1.0, 0, 0, 0),
      Magnetic(1.5, 0, 0, 0),
      Magnetic(2.0, 0, 0, 0)
    };
  calc::interpolate_positions(magnetics, groundtruth);
  REQUIRE(magnetics[0].position[0] == Approx(0));
  REQUIRE(magnetics[0].position[1] == Approx(0));
  REQUIRE(magnetics[1].position[0] == Approx(0.5));
  REQUIRE(magnetics[1].position[1] == Approx(0.5));
  REQUIRE(magnetics[3].position[0] == Approx(2));
  REQUIRE(magnetics[3].position[1] == Approx(1));
  REQUIRE(magnetics[4].position[0] == Approx(3));
  REQUIRE(magnetics[4].position[1] == Approx(1));
}


TEST_CASE("crop_temporal_inersection", "[calc]")
{
  Positions const positions{
      Position(1.0, 8, 4),
      Position(1.5, 8, 4),
      Position(2.0, 8, 4)
    };
  SECTION("right-corner") {
    Magnetics magnetics{
      Magnetic(0.0, 1, 1),
      Magnetic(0.5, 2, 2),
      Magnetic(1.0, 3, 3),
      Magnetic(1.5, 4, 4),
      Magnetic(2.0, 5, 5)
    };
    calc::crop_temporal_inersection(magnetics, positions);
    REQUIRE(magnetics.size() == 3);
    REQUIRE(magnetics[0].position[0] == 3);
    REQUIRE(magnetics[2].position[0] == 5);
  }
  SECTION("left-corner") {
    Magnetics magnetics{
      Magnetic(1.0, 2, 2),
      Magnetic(2.0, 3, 3),
      Magnetic(3.0, 4, 4),
      Magnetic(4.0, 5, 5)
    };
    calc::crop_temporal_inersection(magnetics, positions);
    REQUIRE(magnetics.size() == 2);
    REQUIRE(magnetics[0].position[0] == 2);
    REQUIRE(magnetics[1].position[0] == 3);
  }
}


TEST_CASE("spatial_extent", "[calc]")
{
  Magnetics const mag{
      Magnetic(0, 1, 2),
      Magnetic(0.5, 2, 1),
      Magnetic(1.0, 8, 23),
      Magnetic(1.5, 9, 4)
    };
  auto const [x_min, y_min, x_max, y_max] = calc::spatial_extent(mag);
  REQUIRE(x_min == mag[0].position[0]);
  REQUIRE(y_min == mag[1].position[1]);
  REQUIRE(x_max == mag[3].position[0]);
  REQUIRE(y_max == mag[2].position[1]);
}
