#include <vtkm/cont/RuntimeDeviceTracker.h>

#include <vtkm/cont/ArrayCopy.h>

#include <vtkm/cont/cuda/DeviceAdapterCuda.h>

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

namespace
{

static const vtkm::Id ARRAY_SIZE = 10;

void CopyWithRuntime()
{
  std::cout << "Checking runtime in copy." << std::endl;

  using T = vtkm::Float32;
  vtkm::cont::ArrayHandle<T> srcArray;
  srcArray.Allocate(ARRAY_SIZE);
  SetPortal(srcArray.WritePortal());

  vtkm::cont::ArrayHandle<T> destArray;

  ////
  //// BEGIN-EXAMPLE RestrictCopyDevice.cxx
  ////
  vtkm::cont::ScopedRuntimeDeviceTracker tracker(
    vtkm::cont::DeviceAdapterTagCuda(),
    vtkm::cont::RuntimeDeviceTrackerMode::Disable);

  ////
  //// BEGIN-EXAMPLE ArrayCopy.cxx
  ////
  vtkm::cont::ArrayCopy(srcArray, destArray);
  ////
  //// END-EXAMPLE ArrayCopy.cxx
  ////
  ////
  //// END-EXAMPLE RestrictCopyDevice.cxx
  ////

  VTKM_TEST_ASSERT(destArray.GetNumberOfValues() == ARRAY_SIZE, "Bad array size.");
  CheckPortal(destArray.ReadPortal());
}

////
//// BEGIN-EXAMPLE ForceThreadLocalDevice.cxx
////
void ChangeDefaultRuntime()
{
  std::cout << "Checking changing default runtime." << std::endl;

  ////
  //// BEGIN-EXAMPLE SpecifyDeviceAdapter.cxx
  ////
  vtkm::cont::ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterTagTBB{});
  ////
  //// END-EXAMPLE SpecifyDeviceAdapter.cxx
  ////

  // VTK-m operations limited to serial devices here...

  // Devices restored as we leave scope.
}
////
//// END-EXAMPLE ForceThreadLocalDevice.cxx
////

void Run()
{
  CopyWithRuntime();
  ChangeDefaultRuntime();
}

} // anonymous namespace

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