#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ArrayHandleVirtualCoordinates.h>

#include <vtkm/cont/testing/Testing.h>

#include <vector>


namespace
{

////
//// BEGIN-EXAMPLE UsingArrayHandleVirtualCoordinates.cxx
////
static constexpr vtkm::Id ARRAY_SIZE = 10;

VTKM_CONT std::vector<vtkm::FloatDefault> CountSeveralCoordinates(
  const std::vector<vtkm::cont::ArrayHandleVirtualCoordinates>& vectorOfCoordinates)
{
  std::vector<vtkm::FloatDefault> counts;
  for (auto&& arrayHandleCoordinate : vectorOfCoordinates)
  {
    counts.push_back(arrayHandleCoordinate.GetNumberOfValues());
  }
  return counts;
}

VTKM_CONT void CountArrays()
{
  using CPType = vtkm::cont::ArrayHandleCounting<vtkm::FloatDefault>;
  vtkm::cont::ArrayHandleCounting<vtkm::Vec3f> one(
    vtkm::Vec3f{ 0, 0, 0 }, vtkm::Vec3f{ 1, 1, 1 }, ARRAY_SIZE);
  vtkm::cont::ArrayHandleUniformPointCoordinates two(vtkm::Id3(10, 10, 10));
  vtkm::cont::ArrayHandleCounting<vtkm::FloatDefault> c1(0, 1, ARRAY_SIZE);
  vtkm::cont::ArrayHandleCounting<vtkm::FloatDefault> c2(0, 1, ARRAY_SIZE);
  vtkm::cont::ArrayHandleCounting<vtkm::FloatDefault> c3(0, 1, ARRAY_SIZE);
  vtkm::cont::ArrayHandleCartesianProduct<CPType, CPType, CPType> three(c1, c2, c3);

  std::vector<vtkm::cont::ArrayHandleVirtualCoordinates> vectorOfCoordinates;
  vectorOfCoordinates.emplace_back(one);
  vectorOfCoordinates.emplace_back(two);
  vectorOfCoordinates.emplace_back(three);

  std::vector<vtkm::FloatDefault> elements =
    CountSeveralCoordinates(vectorOfCoordinates);
  //// PAUSE-EXAMPLE
  VTKM_TEST_ASSERT(test_equal(ARRAY_SIZE, elements[0]));
  VTKM_TEST_ASSERT(test_equal(ARRAY_SIZE * ARRAY_SIZE * ARRAY_SIZE, elements[1]));
  VTKM_TEST_ASSERT(test_equal(ARRAY_SIZE * ARRAY_SIZE * ARRAY_SIZE, elements[2]));
  //// RESUME-EXAMPLE
}
////
//// END-EXAMPLE UsingArrayHandleVirtualCoordinates.cxx
////

////
//// BEGIN-EXAMPLE BadCastArrayHandleVirtualCoordinates.cxx
////
VTKM_CONT void BadCast()
{
  vtkm::cont::ArrayHandleCounting<vtkm::Vec3f_64> one(
    vtkm::Vec3f_64{ 0, 0, 0 }, vtkm::Vec3f_64{ 1, 1, 1 }, ARRAY_SIZE);
  std::vector<vtkm::cont::ArrayHandleVirtualCoordinates> vectorOfCoordinates;
  vectorOfCoordinates.emplace_back(one); // OH NO! WE LOST PRECISION!
}
////
//// END-EXAMPLE BadCastArrayHandleVirtualCoordinates.cxx
////


void TestArrayHandleVirtualCoordinateCounts()
{
  VTKM_LOG_S(vtkm::cont::LogLevel::Info,
             "Testing Array Handle Virtual Coordinate Counts");
  CountArrays();
}

void TestBadCastArrayHandleVirtualCoordinates()
{
  VTKM_LOG_S(vtkm::cont::LogLevel::Info,
             "Testing Array Handle Virtual Coordinate Bad Cast");
  BadCast();
}

static void Test()
{
  TestArrayHandleVirtualCoordinateCounts();
  TestBadCastArrayHandleVirtualCoordinates();
}

} // anonymous namespace

int ArrayHandleVirtualCoordinates(int argc, char* argv[])
{
  return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}
